Spaces:
Running
Running
Change the animated background so it matches the theme of cryptography - Initial Deployment
Browse files- README.md +7 -5
- index.html +1308 -18
- prompts.txt +1258 -0
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: securecrypt
|
| 3 |
+
emoji: 🐳
|
| 4 |
+
colorFrom: pink
|
| 5 |
+
colorTo: gray
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
|
@@ -1,19 +1,1309 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en" class="theme-dark">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>SecureCrypt | Client-Side Encryption</title>
|
| 7 |
+
<style>
|
| 8 |
+
/* Design System */
|
| 9 |
+
:root {
|
| 10 |
+
/* Colors - Dark Mode */
|
| 11 |
+
--bg: #0b0f14;
|
| 12 |
+
--bg-elev: #121720;
|
| 13 |
+
--panel: #161c27;
|
| 14 |
+
--muted: #8ba2b0;
|
| 15 |
+
--text: #e2e8f0;
|
| 16 |
+
--text-muted: #94a3b8;
|
| 17 |
+
|
| 18 |
+
/* Accent - Sky */
|
| 19 |
+
--pri: #7dd3fc;
|
| 20 |
+
--pri-600: #38bdf8;
|
| 21 |
+
--pri-700: #0ea5e9;
|
| 22 |
+
|
| 23 |
+
/* Semantic */
|
| 24 |
+
--ok: #34d399;
|
| 25 |
+
--warn: #fbbf24;
|
| 26 |
+
--err: #f87171;
|
| 27 |
+
--info: #60a5fa;
|
| 28 |
+
|
| 29 |
+
/* Typography */
|
| 30 |
+
--font-sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, "Apple Color Emoji", "Segoe UI Emoji";
|
| 31 |
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
| 32 |
+
--text-xs: 0.75rem;
|
| 33 |
+
--text-sm: 0.875rem;
|
| 34 |
+
--text-base: 1rem;
|
| 35 |
+
--text-lg: 1.125rem;
|
| 36 |
+
--text-xl: 1.25rem;
|
| 37 |
+
--text-2xl: 1.5rem;
|
| 38 |
+
|
| 39 |
+
/* Spacing */
|
| 40 |
+
--sp-1: 0.5rem;
|
| 41 |
+
--sp-2: 0.75rem;
|
| 42 |
+
--sp-3: 1rem;
|
| 43 |
+
--sp-4: 1.25rem;
|
| 44 |
+
--sp-5: 1.5rem;
|
| 45 |
+
--sp-6: 2rem;
|
| 46 |
+
|
| 47 |
+
/* Radii & Shadows */
|
| 48 |
+
--r: 0.875rem;
|
| 49 |
+
--r-sm: 0.625rem;
|
| 50 |
+
--r-pill: 9999px;
|
| 51 |
+
--shadow-1: 0 2px 10px rgba(0,0,0,0.25);
|
| 52 |
+
--shadow-2: 0 10px 30px rgba(0,0,0,0.35);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
.theme-light {
|
| 56 |
+
--bg: #f8fafc;
|
| 57 |
+
--bg-elev: #ffffff;
|
| 58 |
+
--panel: #ffffff;
|
| 59 |
+
--muted: #64748b;
|
| 60 |
+
--text: #1e293b;
|
| 61 |
+
--text-muted: #475569;
|
| 62 |
+
--shadow-1: 0 2px 10px rgba(0,0,0,0.05);
|
| 63 |
+
--shadow-2: 0 10px 30px rgba(0,0,0,0.1);
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
/* Base Styles */
|
| 67 |
+
* {
|
| 68 |
+
margin: 0;
|
| 69 |
+
padding: 0;
|
| 70 |
+
box-sizing: border-box;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
body {
|
| 74 |
+
position: relative;
|
| 75 |
+
overflow-x: hidden;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.bg-animation {
|
| 79 |
+
position: fixed;
|
| 80 |
+
top: 0;
|
| 81 |
+
left: 0;
|
| 82 |
+
width: 100%;
|
| 83 |
+
height: 100%;
|
| 84 |
+
z-index: -1;
|
| 85 |
+
pointer-events: none;
|
| 86 |
+
overflow: hidden;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
.bg-lock,
|
| 90 |
+
.bg-key,
|
| 91 |
+
.bg-shield {
|
| 92 |
+
position: absolute;
|
| 93 |
+
transition: transform 0.8s cubic-bezier(0.25, 0.1, 0.25, 1), opacity 0.3s ease;
|
| 94 |
+
will-change: transform;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
body {
|
| 98 |
+
font-family: var(--font-sans);
|
| 99 |
+
background-color: var(--bg);
|
| 100 |
+
color: var(--text);
|
| 101 |
+
line-height: 1.5;
|
| 102 |
+
min-height: 100vh;
|
| 103 |
+
display: flex;
|
| 104 |
+
flex-direction: column;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/* Utility Classes */
|
| 108 |
+
.container {
|
| 109 |
+
width: 100%;
|
| 110 |
+
max-width: 1200px;
|
| 111 |
+
margin: 0 auto;
|
| 112 |
+
padding: 0 var(--sp-4);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
.card {
|
| 116 |
+
background-color: var(--panel);
|
| 117 |
+
border-radius: var(--r);
|
| 118 |
+
box-shadow: var(--shadow-1);
|
| 119 |
+
padding: var(--sp-5);
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
.btn {
|
| 123 |
+
display: inline-flex;
|
| 124 |
+
align-items: center;
|
| 125 |
+
justify-content: center;
|
| 126 |
+
padding: var(--sp-2) var(--sp-4);
|
| 127 |
+
border-radius: var(--r-pill);
|
| 128 |
+
font-weight: 500;
|
| 129 |
+
cursor: pointer;
|
| 130 |
+
transition: all 0.15s ease;
|
| 131 |
+
border: none;
|
| 132 |
+
outline: none;
|
| 133 |
+
gap: var(--sp-2);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
.btn--primary {
|
| 137 |
+
background-color: var(--pri);
|
| 138 |
+
color: var(--bg);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
.btn--primary:hover {
|
| 142 |
+
background-color: var(--pri-600);
|
| 143 |
+
box-shadow: 0 4px 12px rgba(125, 211, 252, 0.25);
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
.btn--primary:active {
|
| 147 |
+
transform: scale(0.98);
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
.btn--primary:focus-visible {
|
| 151 |
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--pri) 35%, transparent);
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
.btn--ghost {
|
| 155 |
+
background-color: transparent;
|
| 156 |
+
color: var(--pri);
|
| 157 |
+
border: 1px solid rgba(125, 211, 252, 0.3);
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
.btn--ghost:hover {
|
| 161 |
+
background-color: rgba(125, 211, 252, 0.1);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
.badge {
|
| 165 |
+
display: inline-flex;
|
| 166 |
+
align-items: center;
|
| 167 |
+
padding: var(--sp-1) var(--sp-2);
|
| 168 |
+
border-radius: var(--r-pill);
|
| 169 |
+
font-size: var(--text-xs);
|
| 170 |
+
font-weight: 500;
|
| 171 |
+
background-color: rgba(125, 211, 252, 0.1);
|
| 172 |
+
color: var(--pri);
|
| 173 |
+
gap: var(--sp-1);
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
.input {
|
| 177 |
+
width: 100%;
|
| 178 |
+
padding: var(--sp-3);
|
| 179 |
+
background-color: var(--bg-elev);
|
| 180 |
+
border: 1px solid transparent;
|
| 181 |
+
border-radius: var(--r-sm);
|
| 182 |
+
color: var(--text);
|
| 183 |
+
font-family: var(--font-mono);
|
| 184 |
+
font-size: var(--text-sm);
|
| 185 |
+
transition: all 0.15s ease;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
.input:focus {
|
| 189 |
+
outline: none;
|
| 190 |
+
border-color: var(--pri);
|
| 191 |
+
box-shadow: 0 0 0 1px var(--pri);
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
.input.is-invalid {
|
| 195 |
+
border-color: var(--err);
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
.tabs {
|
| 199 |
+
display: flex;
|
| 200 |
+
gap: var(--sp-2);
|
| 201 |
+
margin-bottom: var(--sp-4);
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
.tab {
|
| 205 |
+
padding: var(--sp-2) var(--sp-4);
|
| 206 |
+
border-radius: var(--r-pill);
|
| 207 |
+
font-weight: 500;
|
| 208 |
+
cursor: pointer;
|
| 209 |
+
transition: all 0.15s ease;
|
| 210 |
+
position: relative;
|
| 211 |
+
color: var(--text-muted);
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
.tab.is-active {
|
| 215 |
+
color: var(--pri);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
.tab.is-active::after {
|
| 219 |
+
content: '';
|
| 220 |
+
position: absolute;
|
| 221 |
+
bottom: -2px;
|
| 222 |
+
left: 50%;
|
| 223 |
+
transform: translateX(-50%);
|
| 224 |
+
width: 50%;
|
| 225 |
+
height: 2px;
|
| 226 |
+
background-color: var(--pri);
|
| 227 |
+
border-radius: 1px;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
/* Header */
|
| 231 |
+
.header {
|
| 232 |
+
position: sticky;
|
| 233 |
+
top: 0;
|
| 234 |
+
z-index: 50;
|
| 235 |
+
backdrop-filter: blur(8px);
|
| 236 |
+
background-color: rgba(18, 23, 32, 0.6);
|
| 237 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
.header-container {
|
| 241 |
+
display: flex;
|
| 242 |
+
align-items: center;
|
| 243 |
+
justify-content: space-between;
|
| 244 |
+
padding: var(--sp-3) 0;
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
.logo {
|
| 248 |
+
display: flex;
|
| 249 |
+
flex-direction: column;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
.logo h1 {
|
| 253 |
+
font-size: var(--text-xl);
|
| 254 |
+
font-weight: 600;
|
| 255 |
+
line-height: 1.2;
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
.logo p {
|
| 259 |
+
font-size: var(--text-xs);
|
| 260 |
+
color: var(--text-muted);
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
.header-actions {
|
| 264 |
+
display: flex;
|
| 265 |
+
align-items: center;
|
| 266 |
+
gap: var(--sp-4);
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
.badge-group {
|
| 270 |
+
display: flex;
|
| 271 |
+
gap: var(--sp-2);
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
/* Hero */
|
| 275 |
+
.hero {
|
| 276 |
+
padding: var(--sp-6) 0 var(--sp-4);
|
| 277 |
+
text-align: center;
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
.hero p {
|
| 281 |
+
color: var(--text-muted);
|
| 282 |
+
font-size: var(--text-sm);
|
| 283 |
+
margin-top: var(--sp-2);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
/* Main Content */
|
| 287 |
+
.main {
|
| 288 |
+
flex: 1;
|
| 289 |
+
padding-bottom: var(--sp-6);
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
.content-grid {
|
| 293 |
+
display: grid;
|
| 294 |
+
grid-template-columns: 1fr 1fr;
|
| 295 |
+
gap: var(--sp-4);
|
| 296 |
+
margin-top: var(--sp-4);
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
/* Dropzone */
|
| 300 |
+
.dropzone {
|
| 301 |
+
border: 2px dashed var(--muted);
|
| 302 |
+
border-radius: var(--r);
|
| 303 |
+
padding: var(--sp-6);
|
| 304 |
+
display: flex;
|
| 305 |
+
flex-direction: column;
|
| 306 |
+
align-items: center;
|
| 307 |
+
justify-content: center;
|
| 308 |
+
text-align: center;
|
| 309 |
+
cursor: pointer;
|
| 310 |
+
transition: all 0.15s ease;
|
| 311 |
+
min-height: 200px;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
.dropzone:hover {
|
| 315 |
+
border-color: var(--pri);
|
| 316 |
+
background-color: rgba(125, 211, 252, 0.05);
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
.dropzone.is-active {
|
| 320 |
+
border-color: var(--ok);
|
| 321 |
+
background-color: rgba(52, 211, 153, 0.05);
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
.dropzone-icon {
|
| 325 |
+
width: 48px;
|
| 326 |
+
height: 48px;
|
| 327 |
+
margin-bottom: var(--sp-3);
|
| 328 |
+
color: var(--muted);
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
.dropzone:hover .dropzone-icon {
|
| 332 |
+
color: var(--pri);
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
/* Output Actions */
|
| 336 |
+
.output-actions {
|
| 337 |
+
display: flex;
|
| 338 |
+
gap: var(--sp-2);
|
| 339 |
+
margin-top: var(--sp-4);
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
/* Advanced Panel */
|
| 343 |
+
.advanced-panel {
|
| 344 |
+
overflow: hidden;
|
| 345 |
+
max-height: 0;
|
| 346 |
+
opacity: 0;
|
| 347 |
+
transition: all 0.3s ease;
|
| 348 |
+
background-color: var(--bg-elev);
|
| 349 |
+
border-radius: 0 0 var(--r) var(--r);
|
| 350 |
+
margin-top: -1px;
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
.advanced-panel.is-open {
|
| 354 |
+
max-height: 500px;
|
| 355 |
+
opacity: 1;
|
| 356 |
+
padding: var(--sp-4);
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
/* Toasts */
|
| 360 |
+
.toast-container {
|
| 361 |
+
position: fixed;
|
| 362 |
+
top: var(--sp-4);
|
| 363 |
+
right: var(--sp-4);
|
| 364 |
+
display: flex;
|
| 365 |
+
flex-direction: column;
|
| 366 |
+
gap: var(--sp-2);
|
| 367 |
+
z-index: 100;
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
.toast {
|
| 371 |
+
padding: var(--sp-3) var(--sp-4);
|
| 372 |
+
border-radius: var(--r-sm);
|
| 373 |
+
background-color: var(--panel);
|
| 374 |
+
box-shadow: var(--shadow-2);
|
| 375 |
+
display: flex;
|
| 376 |
+
align-items: center;
|
| 377 |
+
gap: var(--sp-3);
|
| 378 |
+
animation: slideIn 0.3s ease;
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
.toast--success {
|
| 382 |
+
border-left: 4px solid var(--ok);
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
.toast--error {
|
| 386 |
+
border-left: 4px solid var(--err);
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
.toast--info {
|
| 390 |
+
border-left: 4px solid var(--info);
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
@keyframes slideIn {
|
| 394 |
+
from {
|
| 395 |
+
transform: translateY(-20px);
|
| 396 |
+
opacity: 0;
|
| 397 |
+
}
|
| 398 |
+
to {
|
| 399 |
+
transform: translateY(0);
|
| 400 |
+
opacity: 1;
|
| 401 |
+
}
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
/* Modal */
|
| 405 |
+
.modal {
|
| 406 |
+
position: fixed;
|
| 407 |
+
top: 0;
|
| 408 |
+
left: 0;
|
| 409 |
+
right: 0;
|
| 410 |
+
bottom: 0;
|
| 411 |
+
background-color: rgba(11, 15, 20, 0.8);
|
| 412 |
+
backdrop-filter: blur(4px);
|
| 413 |
+
display: flex;
|
| 414 |
+
align-items: center;
|
| 415 |
+
justify-content: center;
|
| 416 |
+
z-index: 200;
|
| 417 |
+
opacity: 0;
|
| 418 |
+
pointer-events: none;
|
| 419 |
+
transition: all 0.3s ease;
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
.modal.is-open {
|
| 423 |
+
opacity: 1;
|
| 424 |
+
pointer-events: all;
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
.modal-content {
|
| 428 |
+
background-color: var(--panel);
|
| 429 |
+
border-radius: var(--r);
|
| 430 |
+
width: 100%;
|
| 431 |
+
max-width: 500px;
|
| 432 |
+
padding: var(--sp-5);
|
| 433 |
+
box-shadow: var(--shadow-2);
|
| 434 |
+
transform: translateY(20px);
|
| 435 |
+
transition: all 0.3s ease;
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
.modal.is-open .modal-content {
|
| 439 |
+
transform: translateY(0);
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
.modal-header {
|
| 443 |
+
display: flex;
|
| 444 |
+
justify-content: space-between;
|
| 445 |
+
align-items: center;
|
| 446 |
+
margin-bottom: var(--sp-4);
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
.modal-title {
|
| 450 |
+
font-size: var(--text-xl);
|
| 451 |
+
font-weight: 600;
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
/* Progress */
|
| 455 |
+
.progress {
|
| 456 |
+
height: 4px;
|
| 457 |
+
background-color: var(--bg-elev);
|
| 458 |
+
border-radius: 2px;
|
| 459 |
+
overflow: hidden;
|
| 460 |
+
margin-top: var(--sp-4);
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
.progress-bar {
|
| 464 |
+
height: 100%;
|
| 465 |
+
background-color: var(--pri);
|
| 466 |
+
transition: width 0.3s ease;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
/* Responsive */
|
| 470 |
+
@media (max-width: 768px) {
|
| 471 |
+
.content-grid {
|
| 472 |
+
grid-template-columns: 1fr;
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
.header-container {
|
| 476 |
+
flex-direction: column;
|
| 477 |
+
align-items: flex-start;
|
| 478 |
+
gap: var(--sp-3);
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
.header-actions {
|
| 482 |
+
width: 100%;
|
| 483 |
+
justify-content: space-between;
|
| 484 |
+
}
|
| 485 |
+
}
|
| 486 |
+
</style>
|
| 487 |
+
</head>
|
| 488 |
+
<body>
|
| 489 |
+
<!-- Header -->
|
| 490 |
+
<header class="header">
|
| 491 |
+
<div class="container header-container">
|
| 492 |
+
<div class="logo">
|
| 493 |
+
<h1>SecureCrypt</h1>
|
| 494 |
+
<p>Client-Side Encryption</p>
|
| 495 |
+
</div>
|
| 496 |
+
<div class="header-actions">
|
| 497 |
+
<div class="badge-group">
|
| 498 |
+
<span class="badge">AES-GCM 256</span>
|
| 499 |
+
<span class="badge">PBKDF2 600k</span>
|
| 500 |
+
<span class="badge">10 MB</span>
|
| 501 |
+
</div>
|
| 502 |
+
<button class="btn btn--ghost" id="theme-toggle">
|
| 503 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 504 |
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
| 505 |
+
</svg>
|
| 506 |
+
Theme
|
| 507 |
+
</button>
|
| 508 |
+
</div>
|
| 509 |
+
</div>
|
| 510 |
+
</header>
|
| 511 |
+
|
| 512 |
+
<!-- Hero -->
|
| 513 |
+
<section class="hero">
|
| 514 |
+
<div class="container">
|
| 515 |
+
<h2 class="text-2xl">Secure Encryption & Decryption</h2>
|
| 516 |
+
<p>100% client-side · no uploads</p>
|
| 517 |
+
</div>
|
| 518 |
+
</section>
|
| 519 |
+
|
| 520 |
+
<!-- User Instructions -->
|
| 521 |
+
<section class="card" style="margin: var(--sp-4) auto; max-width: 1200px;">
|
| 522 |
+
<h3>How to Use SecureCrypt</h3>
|
| 523 |
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--sp-4); margin-top: var(--sp-3);">
|
| 524 |
+
<div>
|
| 525 |
+
<h4 style="display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2);">
|
| 526 |
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 527 |
+
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"></path>
|
| 528 |
+
</svg>
|
| 529 |
+
Step 1: Choose Mode
|
| 530 |
+
</h4>
|
| 531 |
+
<p>Select either <strong>Text</strong> for encrypting/decrypting messages or <strong>File</strong> for documents (max 10MB).</p>
|
| 532 |
+
</div>
|
| 533 |
+
<div>
|
| 534 |
+
<h4 style="display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2);">
|
| 535 |
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 536 |
+
<path d="M12 15l8-8-8-8-8 8z"></path>
|
| 537 |
+
</svg>
|
| 538 |
+
Step 2: Set Key
|
| 539 |
+
</h4>
|
| 540 |
+
<p>Enter a strong passphrase or generate a secure 256-bit key. <strong>Never lose your key!</strong></p>
|
| 541 |
+
</div>
|
| 542 |
+
<div>
|
| 543 |
+
<h4 style="display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2);">
|
| 544 |
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 545 |
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
| 546 |
+
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
| 547 |
+
</svg>
|
| 548 |
+
Step 3: Encrypt/Decrypt
|
| 549 |
+
</h4>
|
| 550 |
+
<p>Process your content and securely download the results.</p>
|
| 551 |
+
</div>
|
| 552 |
+
</div>
|
| 553 |
+
<div style="background-color: var(--bg-elev); padding: var(--sp-3); border-radius: var(--r-sm); margin-top: var(--sp-4);">
|
| 554 |
+
<p style="color: var(--err); font-weight: 500;">
|
| 555 |
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align: middle; margin-right: var(--sp-2);">
|
| 556 |
+
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
|
| 557 |
+
<line x1="12" y1="9" x2="12" y2="13"></line>
|
| 558 |
+
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
| 559 |
+
</svg>
|
| 560 |
+
Security Warning: If you lose your key, your data cannot be recovered!
|
| 561 |
+
</p>
|
| 562 |
+
</div>
|
| 563 |
+
</section>
|
| 564 |
+
|
| 565 |
+
<!-- Main Content -->
|
| 566 |
+
<main class="main">
|
| 567 |
+
<div class="container">
|
| 568 |
+
<!-- Tabs -->
|
| 569 |
+
<div class="tabs">
|
| 570 |
+
<div class="tab is-active" data-tab="text">Text</div>
|
| 571 |
+
<div class="tab" data-tab="file">File</div>
|
| 572 |
+
</div>
|
| 573 |
+
|
| 574 |
+
<!-- Text Tab Content -->
|
| 575 |
+
<div class="content-grid" id="text-tab">
|
| 576 |
+
<!-- Input Card -->
|
| 577 |
+
<div class="card">
|
| 578 |
+
<h3>Input</h3>
|
| 579 |
+
<textarea class="input" id="text-input" rows="10" placeholder="Enter text to encrypt or decrypt..."></textarea>
|
| 580 |
+
<div class="output-actions">
|
| 581 |
+
<button class="btn btn--primary" id="encrypt-btn">
|
| 582 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 583 |
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
| 584 |
+
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
| 585 |
+
</svg>
|
| 586 |
+
Encrypt
|
| 587 |
+
</button>
|
| 588 |
+
<button class="btn btn--primary" id="decrypt-btn">
|
| 589 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 590 |
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
| 591 |
+
<path d="M7 11V7a5 5 0 0 1 9.9-1"></path>
|
| 592 |
+
</svg>
|
| 593 |
+
Decrypt
|
| 594 |
+
</button>
|
| 595 |
+
</div>
|
| 596 |
+
</div>
|
| 597 |
+
|
| 598 |
+
<!-- Output Card -->
|
| 599 |
+
<div class="card">
|
| 600 |
+
<h3>Output</h3>
|
| 601 |
+
<textarea class="input" id="text-output" rows="10" placeholder="Result will appear here..." readonly></textarea>
|
| 602 |
+
<div class="output-actions">
|
| 603 |
+
<button class="btn btn--ghost" id="copy-output-btn">
|
| 604 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 605 |
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
| 606 |
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
| 607 |
+
</svg>
|
| 608 |
+
Copy
|
| 609 |
+
</button>
|
| 610 |
+
<button class="btn btn--ghost" id="download-output-btn">
|
| 611 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 612 |
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
| 613 |
+
<polyline points="7 10 12 15 17 10"></polyline>
|
| 614 |
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
| 615 |
+
</svg>
|
| 616 |
+
Download
|
| 617 |
+
</button>
|
| 618 |
+
</div>
|
| 619 |
+
</div>
|
| 620 |
+
</div>
|
| 621 |
+
|
| 622 |
+
<!-- File Tab Content (Hidden by default) -->
|
| 623 |
+
<div class="content-grid" id="file-tab" style="display: none;">
|
| 624 |
+
<!-- Input Card -->
|
| 625 |
+
<div class="card">
|
| 626 |
+
<h3>Input File</h3>
|
| 627 |
+
<div class="dropzone" id="file-dropzone">
|
| 628 |
+
<svg class="dropzone-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 629 |
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
| 630 |
+
<polyline points="17 8 12 3 7 8"></polyline>
|
| 631 |
+
<line x1="12" y1="3" x2="12" y2="15"></line>
|
| 632 |
+
</svg>
|
| 633 |
+
<p>Drag & drop your file here</p>
|
| 634 |
+
<p class="text-muted">or click to browse</p>
|
| 635 |
+
<input type="file" id="file-input" style="display: none;">
|
| 636 |
+
</div>
|
| 637 |
+
<div id="file-info" style="display: none; margin-top: var(--sp-3);">
|
| 638 |
+
<p><strong>File:</strong> <span id="file-name"></span></p>
|
| 639 |
+
<p><strong>Size:</strong> <span id="file-size"></span></p>
|
| 640 |
+
</div>
|
| 641 |
+
<div class="output-actions">
|
| 642 |
+
<button class="btn btn--primary" id="encrypt-file-btn" disabled>
|
| 643 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 644 |
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
| 645 |
+
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
| 646 |
+
</svg>
|
| 647 |
+
Encrypt File
|
| 648 |
+
</button>
|
| 649 |
+
<button class="btn btn--primary" id="decrypt-file-btn" disabled>
|
| 650 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 651 |
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
| 652 |
+
<path d="M7 11V7a5 5 0 0 1 9.9-1"></path>
|
| 653 |
+
</svg>
|
| 654 |
+
Decrypt File
|
| 655 |
+
</button>
|
| 656 |
+
</div>
|
| 657 |
+
</div>
|
| 658 |
+
|
| 659 |
+
<!-- Output Card -->
|
| 660 |
+
<div class="card">
|
| 661 |
+
<h3>Output File</h3>
|
| 662 |
+
<div id="file-output-placeholder" style="text-align: center; padding: var(--sp-6);">
|
| 663 |
+
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-bottom: var(--sp-3);">
|
| 664 |
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
| 665 |
+
<polyline points="14 2 14 8 20 8"></polyline>
|
| 666 |
+
</svg>
|
| 667 |
+
<p>Processed file will appear here</p>
|
| 668 |
+
</div>
|
| 669 |
+
<div id="file-output-info" style="display: none;">
|
| 670 |
+
<p><strong>File:</strong> <span id="output-file-name"></span></p>
|
| 671 |
+
<p><strong>Size:</strong> <span id="output-file-size"></span></p>
|
| 672 |
+
</div>
|
| 673 |
+
<div class="output-actions" id="file-output-actions" style="display: none;">
|
| 674 |
+
<button class="btn btn--ghost" id="download-file-btn">
|
| 675 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 676 |
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
| 677 |
+
<polyline points="7 10 12 15 17 10"></polyline>
|
| 678 |
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
| 679 |
+
</svg>
|
| 680 |
+
Download
|
| 681 |
+
</button>
|
| 682 |
+
</div>
|
| 683 |
+
</div>
|
| 684 |
+
</div>
|
| 685 |
+
|
| 686 |
+
<!-- Key Input -->
|
| 687 |
+
<div class="card" style="margin-top: var(--sp-4);">
|
| 688 |
+
<h3>Encryption Key</h3>
|
| 689 |
+
<div style="display: flex; gap: var(--sp-2); margin-top: var(--sp-2);">
|
| 690 |
+
<input type="password" class="input" id="key-input" placeholder="Enter your encryption key or passphrase">
|
| 691 |
+
<button class="btn btn--ghost" id="toggle-key-visibility">
|
| 692 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 693 |
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
|
| 694 |
+
<circle cx="12" cy="12" r="3"></circle>
|
| 695 |
+
</svg>
|
| 696 |
+
</button>
|
| 697 |
+
<button class="btn btn--ghost" id="generate-key-btn">
|
| 698 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 699 |
+
<path d="M12 22s8-4 8-10V5l-7-1-7 1v7c0 6 8 10 8 10z"></path>
|
| 700 |
+
</svg>
|
| 701 |
+
Generate
|
| 702 |
+
</button>
|
| 703 |
+
</div>
|
| 704 |
+
<div class="progress" style="display: none;" id="progress-bar">
|
| 705 |
+
<div class="progress-bar" id="progress-bar-fill" style="width: 0%"></div>
|
| 706 |
+
</div>
|
| 707 |
+
</div>
|
| 708 |
+
|
| 709 |
+
<!-- Advanced Panel Toggle -->
|
| 710 |
+
<button class="btn btn--ghost" id="advanced-toggle" style="margin-top: var(--sp-4); width: 100%;">
|
| 711 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 712 |
+
<polyline points="6 9 12 15 18 9"></polyline>
|
| 713 |
+
</svg>
|
| 714 |
+
Advanced Information
|
| 715 |
+
</button>
|
| 716 |
+
|
| 717 |
+
<!-- Advanced Panel -->
|
| 718 |
+
<div class="advanced-panel" id="advanced-panel">
|
| 719 |
+
<h3>Technical Specifications</h3>
|
| 720 |
+
<div style="margin-top: var(--sp-3);">
|
| 721 |
+
<h4 style="margin-bottom: var(--sp-2);">Encryption Specifications</h4>
|
| 722 |
+
<p style="margin-bottom: var(--sp-3);">
|
| 723 |
+
SecureCrypt implements industry-standard cryptographic protocols:
|
| 724 |
+
</p>
|
| 725 |
+
<ul style="margin-bottom: var(--sp-3); padding-left: var(--sp-3);">
|
| 726 |
+
<li style="margin-bottom: var(--sp-2);"><strong>AES-256-GCM</strong> - 256-bit key size with Galois/Counter Mode (NIST approved)</li>
|
| 727 |
+
<li style="margin-bottom: var(--sp-2);"><strong>Key Generation</strong> - 32-byte (256-bit) cryptographically secure random keys</li>
|
| 728 |
+
<li style="margin-bottom: var(--sp-2);"><strong>Initialization Vector</strong> - 12-byte random IV per encryption</li>
|
| 729 |
+
<li style="margin-bottom: var(--sp-2);"><strong>Authentication</strong> - 128-bit GCM authentication tags</li>
|
| 730 |
+
<li><strong>Key Wrapping</strong> - PBKDF2 with SHA-256 for passphrase strengthening</li>
|
| 731 |
+
</ul>
|
| 732 |
+
|
| 733 |
+
<h4 style="margin-bottom: var(--sp-2);">Key Derivation Details</h4>
|
| 734 |
+
<p style="margin-bottom: var(--sp-3);">
|
| 735 |
+
When using a passphrase instead of a random key:
|
| 736 |
+
</p>
|
| 737 |
+
<ul style="margin-bottom: var(--sp-3); padding-left: var(--sp-3);">
|
| 738 |
+
<li style="margin-bottom: var(--sp-2);"><strong>PBKDF2-HMAC-SHA256</strong> - Password-Based Key Derivation Function 2</li>
|
| 739 |
+
<li style="margin-bottom: var(--sp-2);"><strong>Iterations</strong> - 600,000 (NIST recommended minimum)</li>
|
| 740 |
+
<li style="margin-bottom: var(--sp-2);"><strong>Salt</strong> - 16-byte cryptographically random per derivation</li>
|
| 741 |
+
<li><strong>Output</strong> - 32-byte derived key material</li>
|
| 742 |
+
</ul>
|
| 743 |
+
|
| 744 |
+
<h4 style="margin-bottom: var(--sp-2);">Data Container Format</h4>
|
| 745 |
+
<p style="margin-bottom: var(--sp-3);">
|
| 746 |
+
All encrypted data follows the ENCv1 specification:
|
| 747 |
+
</p>
|
| 748 |
+
<pre style="background-color: var(--bg-elev); padding: var(--sp-3); border-radius: var(--r-sm); margin-bottom: var(--sp-3); font-family: var(--font-mono); font-size: var(--text-sm); overflow-x: auto;">
|
| 749 |
+
{
|
| 750 |
+
"v": 1, // Format version
|
| 751 |
+
"alg": "AES-GCM", // Encryption algorithm
|
| 752 |
+
"kdf": { // Key derivation params
|
| 753 |
+
"name": "PBKDF2",
|
| 754 |
+
"hash": "SHA-256",
|
| 755 |
+
"iters": 600000,
|
| 756 |
+
"salt_b64": "••••••••••••" // Random salt
|
| 757 |
+
},
|
| 758 |
+
"iv_b64": "••••••••••••", // Initialization vector
|
| 759 |
+
"keyType": "passphrase", // Key source
|
| 760 |
+
"created": "2025-09-06T00:00:00Z",
|
| 761 |
+
"type": "text", // Content type
|
| 762 |
+
"orig": { // Original file info (if applicable)
|
| 763 |
+
"name": "document.pdf",
|
| 764 |
+
"mime": "application/pdf",
|
| 765 |
+
"size": 123456
|
| 766 |
+
}
|
| 767 |
+
}</pre>
|
| 768 |
+
|
| 769 |
+
<div style="background-color: var(--bg-elev); padding: var(--sp-3); border-radius: var(--r-sm);">
|
| 770 |
+
<h4 style="margin-bottom: var(--sp-2);">Security Considerations</h4>
|
| 771 |
+
<ul style="padding-left: var(--sp-3);">
|
| 772 |
+
<li style="margin-bottom: var(--sp-2);">All operations occur <strong>locally in your browser</strong></li>
|
| 773 |
+
<li style="margin-bottom: var(--sp-2);">No data is ever transmitted over the network</li>
|
| 774 |
+
<li style="margin-bottom: var(--sp-2);">Keys and plaintext are <strong>never stored</strong> on disk</li>
|
| 775 |
+
<li>Protects against <strong>offline attacks</strong> but not compromised devices</li>
|
| 776 |
+
</ul>
|
| 777 |
+
</div>
|
| 778 |
+
</div>
|
| 779 |
+
</div>
|
| 780 |
+
</div>
|
| 781 |
+
</main>
|
| 782 |
+
|
| 783 |
+
<!-- Key Generation Modal -->
|
| 784 |
+
<div class="modal" id="key-modal">
|
| 785 |
+
<div class="modal-content">
|
| 786 |
+
<div class="modal-header">
|
| 787 |
+
<h3 class="modal-title">Generate Secure Key</h3>
|
| 788 |
+
<button class="btn btn--ghost" id="close-modal">
|
| 789 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 790 |
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
| 791 |
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
| 792 |
+
</svg>
|
| 793 |
+
</button>
|
| 794 |
+
</div>
|
| 795 |
+
<p style="margin-bottom: var(--sp-3);">For maximum security, use a 32-byte (256-bit) random key. You can also use a passphrase, but it will be strengthened with PBKDF2.</p>
|
| 796 |
+
|
| 797 |
+
<div style="margin-bottom: var(--sp-3);">
|
| 798 |
+
<label style="display: block; margin-bottom: var(--sp-2);">Key Type</label>
|
| 799 |
+
<div style="display: flex; gap: var(--sp-3);">
|
| 800 |
+
<label style="display: flex; align-items: center; gap: var(--sp-2);">
|
| 801 |
+
<input type="radio" name="key-type" value="random" checked>
|
| 802 |
+
Random Key (Recommended)
|
| 803 |
+
</label>
|
| 804 |
+
<label style="display: flex; align-items: center; gap: var(--sp-2);">
|
| 805 |
+
<input type="radio" name="key-type" value="passphrase">
|
| 806 |
+
Passphrase
|
| 807 |
+
</label>
|
| 808 |
+
</div>
|
| 809 |
+
</div>
|
| 810 |
+
|
| 811 |
+
<div id="passphrase-input" style="display: none; margin-bottom: var(--sp-3);">
|
| 812 |
+
<label style="display: block; margin-bottom: var(--sp-2);">Passphrase</label>
|
| 813 |
+
<input type="text" class="input" id="passphrase-field" placeholder="Enter a strong passphrase">
|
| 814 |
+
</div>
|
| 815 |
+
|
| 816 |
+
<div style="margin-bottom: var(--sp-3);">
|
| 817 |
+
<label style="display: block; margin-bottom: var(--sp-2);">Generated Key</label>
|
| 818 |
+
<textarea class="input" id="generated-key" rows="3" readonly style="font-family: var(--font-mono);"></textarea>
|
| 819 |
+
</div>
|
| 820 |
+
|
| 821 |
+
<div style="display: flex; gap: var(--sp-2);">
|
| 822 |
+
<button class="btn btn--ghost" id="copy-key-btn">
|
| 823 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 824 |
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
| 825 |
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
| 826 |
+
</svg>
|
| 827 |
+
Copy
|
| 828 |
+
</button>
|
| 829 |
+
<button class="btn btn--ghost" id="download-key-btn">
|
| 830 |
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 831 |
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
| 832 |
+
<polyline points="7 10 12 15 17 10"></polyline>
|
| 833 |
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
| 834 |
+
</svg>
|
| 835 |
+
Download
|
| 836 |
+
</button>
|
| 837 |
+
<button class="btn btn--primary" id="use-key-btn" style="margin-left: auto;">
|
| 838 |
+
Use This Key
|
| 839 |
+
</button>
|
| 840 |
+
</div>
|
| 841 |
+
</div>
|
| 842 |
+
</div>
|
| 843 |
+
|
| 844 |
+
<!-- Toast Container -->
|
| 845 |
+
<div class="toast-container" id="toast-container"></div>
|
| 846 |
+
|
| 847 |
+
<!-- Animated Background -->
|
| 848 |
+
<div class="bg-animation" id="bg-animation">
|
| 849 |
+
<svg class="bg-lock" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 850 |
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
| 851 |
+
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
| 852 |
+
</svg>
|
| 853 |
+
<svg class="bg-key" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 854 |
+
<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path>
|
| 855 |
+
</svg>
|
| 856 |
+
<svg class="bg-shield" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 857 |
+
<path d="M12 22s8-4 8-10V5l-7-1-7 1v7c0 6 8 10 8 10z"></path>
|
| 858 |
+
</svg>
|
| 859 |
+
</div>
|
| 860 |
+
|
| 861 |
+
<script>
|
| 862 |
+
// Animated Background
|
| 863 |
+
const bgAnimation = document.getElementById('bg-animation');
|
| 864 |
+
const icons = document.querySelectorAll('.bg-lock, .bg-key, .bg-shield');
|
| 865 |
+
const colors = ['var(--pri)', 'var(--pri-600)', 'var(--pri-700)', 'var(--info)', 'var(--ok)'];
|
| 866 |
+
|
| 867 |
+
// Position icons randomly
|
| 868 |
+
icons.forEach(icon => {
|
| 869 |
+
// Random size between 40-80px
|
| 870 |
+
const size = Math.random() * 40 + 40;
|
| 871 |
+
icon.style.width = `${size}px`;
|
| 872 |
+
icon.style.height = `${size}px`;
|
| 873 |
+
|
| 874 |
+
// Random color from our palette
|
| 875 |
+
icon.style.color = colors[Math.floor(Math.random() * colors.length)];
|
| 876 |
+
|
| 877 |
+
// Random initial position
|
| 878 |
+
icon.style.left = `${Math.random() * 100}%`;
|
| 879 |
+
icon.style.top = `${Math.random() * 100}%`;
|
| 880 |
+
icon.style.opacity = '0.2';
|
| 881 |
+
|
| 882 |
+
// Random rotation
|
| 883 |
+
icon.style.transform = `rotate(${Math.random() * 360}deg)`;
|
| 884 |
+
});
|
| 885 |
+
|
| 886 |
+
// Mouse move animation
|
| 887 |
+
document.addEventListener('mousemove', (e) => {
|
| 888 |
+
const x = e.clientX;
|
| 889 |
+
const y = e.clientY;
|
| 890 |
+
|
| 891 |
+
icons.forEach((icon, i) => {
|
| 892 |
+
// Each icon responds with different delay and intensity
|
| 893 |
+
const delay = i * 0.1;
|
| 894 |
+
const intensity = 0.3 + (i * 0.05);
|
| 895 |
+
|
| 896 |
+
setTimeout(() => {
|
| 897 |
+
const newX = x * intensity - (size * 0.5);
|
| 898 |
+
const newY = y * intensity - (size * 0.5);
|
| 899 |
+
|
| 900 |
+
icon.style.transform = `translate(${newX}px, ${newY}px) rotate(${Math.random() * 15 + (i * 10)}deg)`;
|
| 901 |
+
}, delay * 1000);
|
| 902 |
+
});
|
| 903 |
+
});
|
| 904 |
+
|
| 905 |
+
// Theme Toggle
|
| 906 |
+
const themeToggle = document.getElementById('theme-toggle');
|
| 907 |
+
const html = document.documentElement;
|
| 908 |
+
|
| 909 |
+
// Check for saved theme preference or use the color scheme preference
|
| 910 |
+
const savedTheme = localStorage.getItem('theme');
|
| 911 |
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
| 912 |
+
|
| 913 |
+
if (savedTheme) {
|
| 914 |
+
html.classList.toggle('theme-light', savedTheme === 'light');
|
| 915 |
+
} else if (!prefersDark) {
|
| 916 |
+
html.classList.add('theme-light');
|
| 917 |
+
}
|
| 918 |
+
|
| 919 |
+
themeToggle.addEventListener('click', () => {
|
| 920 |
+
html.classList.toggle('theme-light');
|
| 921 |
+
const theme = html.classList.contains('theme-light') ? 'light' : 'dark';
|
| 922 |
+
localStorage.setItem('theme', theme);
|
| 923 |
+
});
|
| 924 |
+
|
| 925 |
+
// Tab Switching
|
| 926 |
+
const tabs = document.querySelectorAll('.tab');
|
| 927 |
+
const textTab = document.getElementById('text-tab');
|
| 928 |
+
const fileTab = document.getElementById('file-tab');
|
| 929 |
+
|
| 930 |
+
tabs.forEach(tab => {
|
| 931 |
+
tab.addEventListener('click', () => {
|
| 932 |
+
tabs.forEach(t => t.classList.remove('is-active'));
|
| 933 |
+
tab.classList.add('is-active');
|
| 934 |
+
|
| 935 |
+
if (tab.dataset.tab === 'text') {
|
| 936 |
+
textTab.style.display = 'grid';
|
| 937 |
+
fileTab.style.display = 'none';
|
| 938 |
+
} else {
|
| 939 |
+
textTab.style.display = 'none';
|
| 940 |
+
fileTab.style.display = 'grid';
|
| 941 |
+
}
|
| 942 |
+
});
|
| 943 |
+
});
|
| 944 |
+
|
| 945 |
+
// Key Visibility Toggle
|
| 946 |
+
const keyInput = document.getElementById('key-input');
|
| 947 |
+
const toggleKeyVisibility = document.getElementById('toggle-key-visibility');
|
| 948 |
+
|
| 949 |
+
toggleKeyVisibility.addEventListener('click', () => {
|
| 950 |
+
const isPassword = keyInput.type === 'password';
|
| 951 |
+
keyInput.type = isPassword ? 'text' : 'password';
|
| 952 |
+
|
| 953 |
+
toggleKeyVisibility.innerHTML = isPassword ?
|
| 954 |
+
`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 955 |
+
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
|
| 956 |
+
<line x1="1" y1="1" x2="23" y2="23"></line>
|
| 957 |
+
</svg>` :
|
| 958 |
+
`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 959 |
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
|
| 960 |
+
<circle cx="12" cy="12" r="3"></circle>
|
| 961 |
+
</svg>`;
|
| 962 |
+
});
|
| 963 |
+
|
| 964 |
+
// Advanced Panel Toggle
|
| 965 |
+
const advancedToggle = document.getElementById('advanced-toggle');
|
| 966 |
+
const advancedPanel = document.getElementById('advanced-panel');
|
| 967 |
+
|
| 968 |
+
advancedToggle.addEventListener('click', () => {
|
| 969 |
+
advancedPanel.classList.toggle('is-open');
|
| 970 |
+
advancedToggle.innerHTML = advancedPanel.classList.contains('is-open') ?
|
| 971 |
+
`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 972 |
+
<polyline points="18 15 12 9 6 15"></polyline>
|
| 973 |
+
</svg>
|
| 974 |
+
Advanced Settings` :
|
| 975 |
+
`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 976 |
+
<polyline points="6 9 12 15 18 9"></polyline>
|
| 977 |
+
</svg>
|
| 978 |
+
Advanced Settings`;
|
| 979 |
+
});
|
| 980 |
+
|
| 981 |
+
// Key Generation Modal
|
| 982 |
+
const generateKeyBtn = document.getElementById('generate-key-btn');
|
| 983 |
+
const keyModal = document.getElementById('key-modal');
|
| 984 |
+
const closeModal = document.getElementById('close-modal');
|
| 985 |
+
const keyTypeRadios = document.querySelectorAll('input[name="key-type"]');
|
| 986 |
+
const passphraseInput = document.getElementById('passphrase-input');
|
| 987 |
+
const passphraseField = document.getElementById('passphrase-field');
|
| 988 |
+
const generatedKey = document.getElementById('generated-key');
|
| 989 |
+
const copyKeyBtn = document.getElementById('copy-key-btn');
|
| 990 |
+
const downloadKeyBtn = document.getElementById('download-key-btn');
|
| 991 |
+
const useKeyBtn = document.getElementById('use-key-btn');
|
| 992 |
+
|
| 993 |
+
generateKeyBtn.addEventListener('click', () => {
|
| 994 |
+
keyModal.classList.add('is-open');
|
| 995 |
+
});
|
| 996 |
+
|
| 997 |
+
closeModal.addEventListener('click', () => {
|
| 998 |
+
keyModal.classList.remove('is-open');
|
| 999 |
+
});
|
| 1000 |
+
|
| 1001 |
+
keyTypeRadios.forEach(radio => {
|
| 1002 |
+
radio.addEventListener('change', () => {
|
| 1003 |
+
passphraseInput.style.display = radio.value === 'passphrase' ? 'block' : 'none';
|
| 1004 |
+
if (radio.value === 'random') {
|
| 1005 |
+
generateRandomKey();
|
| 1006 |
+
} else {
|
| 1007 |
+
generatedKey.value = '';
|
| 1008 |
+
}
|
| 1009 |
+
});
|
| 1010 |
+
});
|
| 1011 |
+
|
| 1012 |
+
passphraseField.addEventListener('input', () => {
|
| 1013 |
+
if (passphraseField.value.length > 0) {
|
| 1014 |
+
generatedKey.value = 'Key will be derived from passphrase using PBKDF2';
|
| 1015 |
+
} else {
|
| 1016 |
+
generatedKey.value = '';
|
| 1017 |
+
}
|
| 1018 |
+
});
|
| 1019 |
+
|
| 1020 |
+
function generateRandomKey() {
|
| 1021 |
+
const randomBytes = new Uint8Array(32);
|
| 1022 |
+
window.crypto.getRandomValues(randomBytes);
|
| 1023 |
+
const keyBase64 = btoa(String.fromCharCode(...randomBytes));
|
| 1024 |
+
generatedKey.value = keyBase64;
|
| 1025 |
+
}
|
| 1026 |
+
|
| 1027 |
+
copyKeyBtn.addEventListener('click', () => {
|
| 1028 |
+
if (generatedKey.value) {
|
| 1029 |
+
navigator.clipboard.writeText(generatedKey.value);
|
| 1030 |
+
showToast('Key copied to clipboard', 'success');
|
| 1031 |
+
}
|
| 1032 |
+
});
|
| 1033 |
+
|
| 1034 |
+
downloadKeyBtn.addEventListener('click', () => {
|
| 1035 |
+
if (generatedKey.value) {
|
| 1036 |
+
const blob = new Blob([generatedKey.value], { type: 'text/plain' });
|
| 1037 |
+
const url = URL.createObjectURL(blob);
|
| 1038 |
+
const a = document.createElement('a');
|
| 1039 |
+
a.href = url;
|
| 1040 |
+
a.download = 'securecrypt-key.txt';
|
| 1041 |
+
document.body.appendChild(a);
|
| 1042 |
+
a.click();
|
| 1043 |
+
document.body.removeChild(a);
|
| 1044 |
+
URL.revokeObjectURL(url);
|
| 1045 |
+
showToast('Key download started', 'success');
|
| 1046 |
+
}
|
| 1047 |
+
});
|
| 1048 |
+
|
| 1049 |
+
useKeyBtn.addEventListener('click', () => {
|
| 1050 |
+
if (generatedKey.value) {
|
| 1051 |
+
keyInput.value = generatedKey.value;
|
| 1052 |
+
keyModal.classList.remove('is-open');
|
| 1053 |
+
showToast('Key applied to input', 'success');
|
| 1054 |
+
}
|
| 1055 |
+
});
|
| 1056 |
+
|
| 1057 |
+
// Generate a random key when modal opens
|
| 1058 |
+
keyModal.addEventListener('click', (e) => {
|
| 1059 |
+
if (e.target === keyModal) {
|
| 1060 |
+
keyModal.classList.remove('is-open');
|
| 1061 |
+
}
|
| 1062 |
+
});
|
| 1063 |
+
|
| 1064 |
+
// File Dropzone
|
| 1065 |
+
const fileDropzone = document.getElementById('file-dropzone');
|
| 1066 |
+
const fileInput = document.getElementById('file-input');
|
| 1067 |
+
const fileInfo = document.getElementById('file-info');
|
| 1068 |
+
const fileName = document.getElementById('file-name');
|
| 1069 |
+
const fileSize = document.getElementById('file-size');
|
| 1070 |
+
const encryptFileBtn = document.getElementById('encrypt-file-btn');
|
| 1071 |
+
const decryptFileBtn = document.getElementById('decrypt-file-btn');
|
| 1072 |
+
|
| 1073 |
+
fileDropzone.addEventListener('click', () => {
|
| 1074 |
+
fileInput.click();
|
| 1075 |
+
});
|
| 1076 |
+
|
| 1077 |
+
fileInput.addEventListener('change', handleFileSelect);
|
| 1078 |
+
|
| 1079 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
| 1080 |
+
fileDropzone.addEventListener(eventName, preventDefaults, false);
|
| 1081 |
+
});
|
| 1082 |
+
|
| 1083 |
+
function preventDefaults(e) {
|
| 1084 |
+
e.preventDefault();
|
| 1085 |
+
e.stopPropagation();
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
['dragenter', 'dragover'].forEach(eventName => {
|
| 1089 |
+
fileDropzone.addEventListener(eventName, highlight, false);
|
| 1090 |
+
});
|
| 1091 |
+
|
| 1092 |
+
['dragleave', 'drop'].forEach(eventName => {
|
| 1093 |
+
fileDropzone.addEventListener(eventName, unhighlight, false);
|
| 1094 |
+
});
|
| 1095 |
+
|
| 1096 |
+
function highlight() {
|
| 1097 |
+
fileDropzone.classList.add('is-active');
|
| 1098 |
+
}
|
| 1099 |
+
|
| 1100 |
+
function unhighlight() {
|
| 1101 |
+
fileDropzone.classList.remove('is-active');
|
| 1102 |
+
}
|
| 1103 |
+
|
| 1104 |
+
fileDropzone.addEventListener('drop', handleDrop, false);
|
| 1105 |
+
|
| 1106 |
+
function handleDrop(e) {
|
| 1107 |
+
const dt = e.dataTransfer;
|
| 1108 |
+
const files = dt.files;
|
| 1109 |
+
if (files.length) {
|
| 1110 |
+
handleFiles(files);
|
| 1111 |
+
}
|
| 1112 |
+
}
|
| 1113 |
+
|
| 1114 |
+
function handleFileSelect(e) {
|
| 1115 |
+
const files = e.target.files;
|
| 1116 |
+
if (files.length) {
|
| 1117 |
+
handleFiles(files);
|
| 1118 |
+
}
|
| 1119 |
+
}
|
| 1120 |
+
|
| 1121 |
+
function handleFiles(files) {
|
| 1122 |
+
const file = files[0];
|
| 1123 |
+
|
| 1124 |
+
// Check file size (10MB limit)
|
| 1125 |
+
if (file.size > 10 * 1024 * 1024) {
|
| 1126 |
+
showToast('File is too large (max 10MB)', 'error');
|
| 1127 |
+
return;
|
| 1128 |
+
}
|
| 1129 |
+
|
| 1130 |
+
fileName.textContent = file.name;
|
| 1131 |
+
fileSize.textContent = formatFileSize(file.size);
|
| 1132 |
+
fileInfo.style.display = 'block';
|
| 1133 |
+
|
| 1134 |
+
encryptFileBtn.disabled = false;
|
| 1135 |
+
decryptFileBtn.disabled = false;
|
| 1136 |
+
}
|
| 1137 |
+
|
| 1138 |
+
function formatFileSize(bytes) {
|
| 1139 |
+
if (bytes < 1024) return bytes + ' bytes';
|
| 1140 |
+
else if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
| 1141 |
+
else return (bytes / 1048576).toFixed(1) + ' MB';
|
| 1142 |
+
}
|
| 1143 |
+
|
| 1144 |
+
// Toast Notifications
|
| 1145 |
+
function showToast(message, type) {
|
| 1146 |
+
const toastContainer = document.getElementById('toast-container');
|
| 1147 |
+
const toast = document.createElement('div');
|
| 1148 |
+
toast.className = `toast toast--${type}`;
|
| 1149 |
+
toast.setAttribute('role', 'status');
|
| 1150 |
+
|
| 1151 |
+
let icon;
|
| 1152 |
+
switch (type) {
|
| 1153 |
+
case 'success':
|
| 1154 |
+
icon = `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 1155 |
+
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
| 1156 |
+
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
| 1157 |
+
</svg>`;
|
| 1158 |
+
break;
|
| 1159 |
+
case 'error':
|
| 1160 |
+
icon = `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 1161 |
+
<circle cx="12" cy="12" r="10"></circle>
|
| 1162 |
+
<line x1="12" y1="8" x2="12" y2="12"></line>
|
| 1163 |
+
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
| 1164 |
+
</svg>`;
|
| 1165 |
+
break;
|
| 1166 |
+
default:
|
| 1167 |
+
icon = `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 1168 |
+
<circle cx="12" cy="12" r="10"></circle>
|
| 1169 |
+
<line x1="12" y1="16" x2="12" y2="12"></line>
|
| 1170 |
+
<line x1="12" y1="8" x2="12.01" y2="8"></line>
|
| 1171 |
+
</svg>`;
|
| 1172 |
+
}
|
| 1173 |
+
|
| 1174 |
+
toast.innerHTML = `${icon}<span>${message}</span>`;
|
| 1175 |
+
toastContainer.appendChild(toast);
|
| 1176 |
+
|
| 1177 |
+
setTimeout(() => {
|
| 1178 |
+
toast.style.opacity = '0';
|
| 1179 |
+
setTimeout(() => {
|
| 1180 |
+
toast.remove();
|
| 1181 |
+
}, 300);
|
| 1182 |
+
}, 5000);
|
| 1183 |
+
}
|
| 1184 |
+
|
| 1185 |
+
// Simulate some functionality for demo purposes
|
| 1186 |
+
document.getElementById('encrypt-btn').addEventListener('click', () => {
|
| 1187 |
+
const textInput = document.getElementById('text-input');
|
| 1188 |
+
if (textInput.value.trim() === '') {
|
| 1189 |
+
showToast('Please enter text to encrypt', 'error');
|
| 1190 |
+
return;
|
| 1191 |
+
}
|
| 1192 |
+
|
| 1193 |
+
if (keyInput.value.trim() === '') {
|
| 1194 |
+
showToast('Please enter an encryption key', 'error');
|
| 1195 |
+
return;
|
| 1196 |
+
}
|
| 1197 |
+
|
| 1198 |
+
// Simulate encryption process
|
| 1199 |
+
const progressBar = document.getElementById('progress-bar');
|
| 1200 |
+
const progressFill = document.getElementById('progress-bar-fill');
|
| 1201 |
+
|
| 1202 |
+
progressBar.style.display = 'block';
|
| 1203 |
+
progressFill.style.width = '0%';
|
| 1204 |
+
|
| 1205 |
+
let progress = 0;
|
| 1206 |
+
const interval = setInterval(() => {
|
| 1207 |
+
progress += 5;
|
| 1208 |
+
progressFill.style.width = `${progress}%`;
|
| 1209 |
+
|
| 1210 |
+
if (progress >= 100) {
|
| 1211 |
+
clearInterval(interval);
|
| 1212 |
+
setTimeout(() => {
|
| 1213 |
+
document.getElementById('text-output').value = 'Encrypted: ' + btoa(textInput.value);
|
| 1214 |
+
progressBar.style.display = 'none';
|
| 1215 |
+
showToast('Text encrypted successfully', 'success');
|
| 1216 |
+
}, 200);
|
| 1217 |
+
}
|
| 1218 |
+
}, 50);
|
| 1219 |
+
});
|
| 1220 |
+
|
| 1221 |
+
document.getElementById('decrypt-btn').addEventListener('click', () => {
|
| 1222 |
+
const textInput = document.getElementById('text-input');
|
| 1223 |
+
if (textInput.value.trim() === '') {
|
| 1224 |
+
showToast('Please enter text to decrypt', 'error');
|
| 1225 |
+
return;
|
| 1226 |
+
}
|
| 1227 |
+
|
| 1228 |
+
if (keyInput.value.trim() === '') {
|
| 1229 |
+
showToast('Please enter an encryption key', 'error');
|
| 1230 |
+
return;
|
| 1231 |
+
}
|
| 1232 |
+
|
| 1233 |
+
// Simulate decryption process
|
| 1234 |
+
const progressBar = document.getElementById('progress-bar');
|
| 1235 |
+
const progressFill = document.getElementById('progress-bar-fill');
|
| 1236 |
+
|
| 1237 |
+
progressBar.style.display = 'block';
|
| 1238 |
+
progressFill.style.width = '0%';
|
| 1239 |
+
|
| 1240 |
+
let progress = 0;
|
| 1241 |
+
const interval = setInterval(() => {
|
| 1242 |
+
progress += 5;
|
| 1243 |
+
progressFill.style.width = `${progress}%`;
|
| 1244 |
+
|
| 1245 |
+
if (progress >= 100) {
|
| 1246 |
+
clearInterval(interval);
|
| 1247 |
+
setTimeout(() => {
|
| 1248 |
+
try {
|
| 1249 |
+
document.getElementById('text-output').value = 'Decrypted: ' + atob(textInput.value.replace('Encrypted: ', ''));
|
| 1250 |
+
showToast('Text decrypted successfully', 'success');
|
| 1251 |
+
} catch (e) {
|
| 1252 |
+
document.getElementById('text-output').value = 'Error: Invalid encrypted text';
|
| 1253 |
+
showToast('Decryption failed', 'error');
|
| 1254 |
+
}
|
| 1255 |
+
progressBar.style.display = 'none';
|
| 1256 |
+
}, 200);
|
| 1257 |
+
}
|
| 1258 |
+
}, 50);
|
| 1259 |
+
});
|
| 1260 |
+
|
| 1261 |
+
document.getElementById('copy-output-btn').addEventListener('click', () => {
|
| 1262 |
+
const textOutput = document.getElementById('text-output');
|
| 1263 |
+
if (textOutput.value.trim() === '') {
|
| 1264 |
+
showToast('No output to copy', 'error');
|
| 1265 |
+
return;
|
| 1266 |
+
}
|
| 1267 |
+
|
| 1268 |
+
navigator.clipboard.writeText(textOutput.value);
|
| 1269 |
+
showToast('Output copied to clipboard', 'success');
|
| 1270 |
+
});
|
| 1271 |
+
|
| 1272 |
+
document.getElementById('download-output-btn').addEventListener('click', () => {
|
| 1273 |
+
const textOutput = document.getElementById('text-output');
|
| 1274 |
+
if (textOutput.value.trim() === '') {
|
| 1275 |
+
showToast('No output to download', 'error');
|
| 1276 |
+
return;
|
| 1277 |
+
}
|
| 1278 |
+
|
| 1279 |
+
const blob = new Blob([textOutput.value], { type: 'text/plain' });
|
| 1280 |
+
const url = URL.createObjectURL(blob);
|
| 1281 |
+
const a = document.createElement('a');
|
| 1282 |
+
a.href = url;
|
| 1283 |
+
a.download = 'securecrypt-output.txt';
|
| 1284 |
+
document.body.appendChild(a);
|
| 1285 |
+
a.click();
|
| 1286 |
+
document.body.removeChild(a);
|
| 1287 |
+
URL.revokeObjectURL(url);
|
| 1288 |
+
showToast('Output download started', 'success');
|
| 1289 |
+
});
|
| 1290 |
+
|
| 1291 |
+
// Generate a random key when the page loads
|
| 1292 |
+
window.addEventListener('load', () => {
|
| 1293 |
+
generateRandomKey();
|
| 1294 |
+
|
| 1295 |
+
// Animate circles on load
|
| 1296 |
+
circles.forEach(circle => {
|
| 1297 |
+
const x = Math.random() * window.innerWidth;
|
| 1298 |
+
const y = Math.random() * window.innerHeight;
|
| 1299 |
+
circle.style.transform = `translate(${x}px, ${y}px)`;
|
| 1300 |
+
});
|
| 1301 |
+
|
| 1302 |
+
// Show welcome toast
|
| 1303 |
+
setTimeout(() => {
|
| 1304 |
+
showToast('Welcome to SecureCrypt! All encryption happens locally in your browser.', 'info');
|
| 1305 |
+
}, 1000);
|
| 1306 |
+
});
|
| 1307 |
+
</script>
|
| 1308 |
+
</body>
|
| 1309 |
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1,1258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Build a Single-File Static Web App for Client-Side Encryption/Decryption (Dark Mode, 10 MB limit)
|
| 2 |
+
Absolutely Required
|
| 3 |
+
|
| 4 |
+
Deliverable: A single self-contained index.html file that runs locally via file:// or any static host.
|
| 5 |
+
|
| 6 |
+
No build tools, no servers, no external assets (no CDN, no Tailwind, no NPM).
|
| 7 |
+
|
| 8 |
+
All HTML, CSS, and JS must be embedded in this one file (inline <style> and <script type="module">).
|
| 9 |
+
|
| 10 |
+
Must work in modern Chromium/Firefox/Safari.
|
| 11 |
+
|
| 12 |
+
Goal
|
| 13 |
+
|
| 14 |
+
Create a modern, responsive, dark-mode single page that performs 100% client-side encryption and decryption of entered text or uploaded files (max 10 MB). No data ever leaves the browser.
|
| 15 |
+
|
| 16 |
+
Cryptography (Web Crypto API only)
|
| 17 |
+
|
| 18 |
+
Symmetric encryption: AES-GCM (256-bit) via window.crypto.subtle.
|
| 19 |
+
|
| 20 |
+
Passphrase → key: PBKDF2/SHA-256, 16-byte random salt, ≥ 600,000 iterations (configurable).
|
| 21 |
+
|
| 22 |
+
12-byte random IV per encryption.
|
| 23 |
+
|
| 24 |
+
Integrity: rely on AES-GCM auth tag; show clear success/failure on decrypt.
|
| 25 |
+
|
| 26 |
+
Raw key option: if user supplies a 32-byte random key (Base64/URL-safe), skip PBKDF2 and import directly for AES-GCM.
|
| 27 |
+
|
| 28 |
+
Never roll your own crypto; no third-party crypto libraries.
|
| 29 |
+
|
| 30 |
+
Package/Container Format
|
| 31 |
+
|
| 32 |
+
Support a compact, versioned container for both text and files. Use a Base64-armored string with a magic prefix, e.g. ENCv1: followed by Base64 of:
|
| 33 |
+
|
| 34 |
+
UTF-8 JSON header (first), then a newline \n,
|
| 35 |
+
|
| 36 |
+
then raw ciphertext bytes (including GCM tag).
|
| 37 |
+
|
| 38 |
+
Header JSON example:
|
| 39 |
+
|
| 40 |
+
{
|
| 41 |
+
"v": 1,
|
| 42 |
+
"alg": "AES-GCM",
|
| 43 |
+
"kdf": {"name":"PBKDF2","hash":"SHA-256","iters":600000,"salt_b64":"..."},
|
| 44 |
+
"iv_b64": "...",
|
| 45 |
+
"keyType": "passphrase|raw",
|
| 46 |
+
"created": "2025-09-06T00:00:00Z",
|
| 47 |
+
"type": "text|file",
|
| 48 |
+
"orig": {"name":"report.pdf","mime":"application/pdf","size":123456}
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
If using a raw key: "kdf": null, "keyType":"raw".
|
| 53 |
+
|
| 54 |
+
For text mode, omit or simplify "orig".
|
| 55 |
+
|
| 56 |
+
UI/UX Requirements
|
| 57 |
+
|
| 58 |
+
Tabs or segmented controls: Text and File modes.
|
| 59 |
+
|
| 60 |
+
Text tab: textarea input; Encrypt and Decrypt; output area with copy buttons.
|
| 61 |
+
|
| 62 |
+
File tab: drag-and-drop + picker; show filename/size; block > 10 MB with friendly error.
|
| 63 |
+
|
| 64 |
+
On Encrypt, download a .enc file containing the armored package.
|
| 65 |
+
|
| 66 |
+
On Decrypt, reconstruct original file (name/MIME from header) and download.
|
| 67 |
+
|
| 68 |
+
Key input section:
|
| 69 |
+
|
| 70 |
+
Field for passphrase or toggle to Generate secure key (32 random bytes → Base64/URL-safe).
|
| 71 |
+
|
| 72 |
+
Provide Copy and Download .key (text) for generated keys.
|
| 73 |
+
|
| 74 |
+
Clear indicators whether passphrase (PBKDF2) or raw key flow is active.
|
| 75 |
+
|
| 76 |
+
Status & Progress:
|
| 77 |
+
|
| 78 |
+
Progress bar/spinner for file operations; inline success/error toasts.
|
| 79 |
+
|
| 80 |
+
Modern dark UI (default):
|
| 81 |
+
|
| 82 |
+
Sleek, minimal, responsive layout with smooth micro-animations.
|
| 83 |
+
|
| 84 |
+
Include a light/dark toggle.
|
| 85 |
+
|
| 86 |
+
User Instructions (visible panel):
|
| 87 |
+
|
| 88 |
+
Step-by-step: choose Text/File → enter or generate key → Encrypt/Decrypt → manage/download results.
|
| 89 |
+
|
| 90 |
+
Prominent warning: “If you lose the key, you lose the data.”
|
| 91 |
+
|
| 92 |
+
Advanced/Technical Header (collapsible):
|
| 93 |
+
|
| 94 |
+
An accessible toggle button (aria-expanded, aria-controls).
|
| 95 |
+
|
| 96 |
+
On expand, show algorithm details, PBKDF2 iteration count, salt/IV lengths, format version, and a redacted example header from the last operation.
|
| 97 |
+
|
| 98 |
+
Privacy Note:
|
| 99 |
+
|
| 100 |
+
“All operations occur locally in your browser. No data is uploaded.”
|
| 101 |
+
|
| 102 |
+
Validation & Errors
|
| 103 |
+
|
| 104 |
+
Empty inputs, missing key, size limit exceeded → user-friendly inline errors.
|
| 105 |
+
|
| 106 |
+
Wrong key/corruption → “Decryption failed (wrong key or corrupted data).”
|
| 107 |
+
|
| 108 |
+
Unsupported package version → clear error referencing v.
|
| 109 |
+
|
| 110 |
+
Catch and display Web Crypto exceptions.
|
| 111 |
+
|
| 112 |
+
Implementation Notes (Single-File Constraints)
|
| 113 |
+
|
| 114 |
+
Use plain ES modules: a single <script type="module"> block in index.html.
|
| 115 |
+
|
| 116 |
+
Keep secrets in memory only; no LocalStorage/IndexedDB for keys or plaintext.
|
| 117 |
+
|
| 118 |
+
Provide helper functions for:
|
| 119 |
+
|
| 120 |
+
deriveKeyFromPassphrase(pass, salt, iters) → CryptoKey
|
| 121 |
+
|
| 122 |
+
importRawKey(base64) → CryptoKey
|
| 123 |
+
|
| 124 |
+
encryptText, decryptText
|
| 125 |
+
|
| 126 |
+
encryptFile, decryptFile (use Blob/ArrayBuffer, FileReader)
|
| 127 |
+
|
| 128 |
+
encodePackage(headerObj, cipherBytes) → "ENCv1:...base64..."
|
| 129 |
+
|
| 130 |
+
decodePackage(armored) → {header, cipherBytes}
|
| 131 |
+
|
| 132 |
+
Show a short example round-trip in the Advanced panel after first success (parameters only, no secrets).
|
| 133 |
+
|
| 134 |
+
Accessibility
|
| 135 |
+
|
| 136 |
+
Keyboard navigable controls, visible focus states.
|
| 137 |
+
|
| 138 |
+
Proper aria-* for collapsible advanced header, tab controls, and toasts/alerts.
|
| 139 |
+
|
| 140 |
+
Security Footnotes (display in Advanced)
|
| 141 |
+
|
| 142 |
+
Unique salt per KDF, unique IV per message.
|
| 143 |
+
|
| 144 |
+
Recommend long passphrases or random 32-byte keys.
|
| 145 |
+
|
| 146 |
+
Emphasize no recovery if key is lost.
|
| 147 |
+
|
| 148 |
+
Clarify threat model: protects at-rest data; does not protect against a compromised device.
|
| 149 |
+
|
| 150 |
+
Acceptance Criteria
|
| 151 |
+
|
| 152 |
+
Ships as one index.html file; opens and works from file://.
|
| 153 |
+
|
| 154 |
+
Encrypts/decrypts text and files ≤ 10 MB entirely offline.
|
| 155 |
+
|
| 156 |
+
Supports both PBKDF2 passphrase and raw 32-byte key flows.
|
| 157 |
+
|
| 158 |
+
Produces/consumes the specified ENCv1: Base64 format with JSON header.
|
| 159 |
+
|
| 160 |
+
Dark mode by default, responsive, accessible, with a collapsible technical header.
|
| 161 |
+
|
| 162 |
+
Clear errors for wrong key, bad format, or size over limit.
|
| 163 |
+
|
| 164 |
+
Now implement the entire app in a single self-contained index.html with inline CSS and JS (no external resources). Include helpful comments in code.
|
| 165 |
+
UI/UX Overhaul for Single-File Client-Side Crypto App (Dark Mode First)
|
| 166 |
+
Goal
|
| 167 |
+
|
| 168 |
+
Redesign the existing single-file (index.html) app into a sleek, premium, dark-mode-first experience with refined typography, spacing, motion, and states—without adding any external assets (no CDNs, fonts, icon packs, or JS libs). Keep all HTML/CSS/JS inline. Maintain all current crypto features and flows.
|
| 169 |
+
|
| 170 |
+
Design System (define in :root and support dark/light)
|
| 171 |
+
|
| 172 |
+
Color tokens (WCAG AA for text):
|
| 173 |
+
|
| 174 |
+
--bg: #0b0f14, --bg-elev: #121720, --panel: #161c27, --muted: #8ba2b0
|
| 175 |
+
|
| 176 |
+
Accents (choose one primary; compute focus/hover variants):
|
| 177 |
+
|
| 178 |
+
--pri: #7dd3fc (sky), --pri-600: #38bdf8, --pri-700: #0ea5e9
|
| 179 |
+
|
| 180 |
+
Semantic:
|
| 181 |
+
|
| 182 |
+
--ok: #34d399, --warn: #fbbf24, --err: #f87171, --info: #60a5fa
|
| 183 |
+
|
| 184 |
+
Typography (system stack; no external fonts):
|
| 185 |
+
|
| 186 |
+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, "Apple Color Emoji","Segoe UI Emoji";
|
| 187 |
+
|
| 188 |
+
Scale: --text-xs: 12px, --sm: 14px, --base: 16px, --lg: 18px, --xl: 20px, --2xl: 24px
|
| 189 |
+
|
| 190 |
+
Line-height: 1.5 text, 1.2 headings. Tighten letter-spacing on headings.
|
| 191 |
+
|
| 192 |
+
Radii & Shadows:
|
| 193 |
+
|
| 194 |
+
--r: 14px panels, --r-sm: 10px inputs, --r-pill: 999px
|
| 195 |
+
|
| 196 |
+
Soft shadows: --shadow-1: 0 2px 10px rgba(0,0,0,.25), --shadow-2: 0 10px 30px rgba(0,0,0,.35)
|
| 197 |
+
|
| 198 |
+
Spacing (8-pt grid):
|
| 199 |
+
|
| 200 |
+
--sp-1: 8px, --sp-2: 12px, --sp-3: 16px, --sp-4: 20px, --sp-5: 24px, --sp-6: 32px
|
| 201 |
+
|
| 202 |
+
Light mode: implement via .theme-light (class on <html>) or @media (prefers-color-scheme: light) overrides.
|
| 203 |
+
|
| 204 |
+
Layout & Components
|
| 205 |
+
|
| 206 |
+
Header (sticky)
|
| 207 |
+
|
| 208 |
+
App name + small tagline; right side: Theme toggle, Advanced panel toggle (accordion link), GitHub-like inline badges for “AES-GCM 256”, “PBKDF2 600k”, “10 MB”.
|
| 209 |
+
|
| 210 |
+
Use subtle glassmorphism: backdrop blur on header with backdrop-filter: blur(8px); background: rgba(18,23,32,.6); border: 1px solid rgba(255,255,255,.06);
|
| 211 |
+
|
| 212 |
+
Hero strip
|
| 213 |
+
|
| 214 |
+
Two-line intro with tiny privacy note: “100% client-side · no uploads”.
|
| 215 |
+
|
| 216 |
+
Tabs (Text | File)
|
| 217 |
+
|
| 218 |
+
Segmented control with pill buttons; active tab has inner glow.
|
| 219 |
+
|
| 220 |
+
Smooth underline animation on active tab.
|
| 221 |
+
|
| 222 |
+
Cards
|
| 223 |
+
|
| 224 |
+
Split layout for each tab:
|
| 225 |
+
|
| 226 |
+
Left card: input (textarea or dropzone).
|
| 227 |
+
|
| 228 |
+
Right card: output/result with copy + download actions.
|
| 229 |
+
|
| 230 |
+
Cards use --panel background, rounded corners, soft shadow, generous padding.
|
| 231 |
+
|
| 232 |
+
Inputs
|
| 233 |
+
|
| 234 |
+
Minimal “borderless” fields with 1px hairline on focus; large click targets.
|
| 235 |
+
|
| 236 |
+
Password/Key area with show/hide toggle and copy button.
|
| 237 |
+
|
| 238 |
+
Key generation presented in a modal sheet (see below).
|
| 239 |
+
|
| 240 |
+
Drag & drop zone (File tab)
|
| 241 |
+
|
| 242 |
+
Dotted rounded border, hover elevation, icon (inline SVG), file details preview (name, size, type), and size-limit helper.
|
| 243 |
+
|
| 244 |
+
Primary actions
|
| 245 |
+
|
| 246 |
+
“Encrypt” and “Decrypt” as large pill buttons with icon + label; animated hover (elevate + slight glow). Disable when invalid.
|
| 247 |
+
|
| 248 |
+
Status & Progress
|
| 249 |
+
|
| 250 |
+
Progress bar (indeterminate → determinate for files), inline toast notifications (top-right) with semantic colors; auto-dismiss + manual close.
|
| 251 |
+
|
| 252 |
+
Advanced panel
|
| 253 |
+
|
| 254 |
+
Collapsible below header; animate height with max-height + opacity and aria-expanded. Show algorithm details, parameters from last run, and a redacted JSON header rendered in a code block with syntax-like styling.
|
| 255 |
+
|
| 256 |
+
Modal: “Generate Secure Key”
|
| 257 |
+
|
| 258 |
+
Centered sheet with blur backdrop; explains raw vs passphrase, lets user choose 32-byte random key; shows Base64 key with copy + download and “Use this key” button.
|
| 259 |
+
|
| 260 |
+
Motion & Interactions
|
| 261 |
+
|
| 262 |
+
Respect prefers-reduced-motion: reduce.
|
| 263 |
+
|
| 264 |
+
Use subtle micro-interactions:
|
| 265 |
+
|
| 266 |
+
150–220ms transitions on hover/focus/elevation.
|
| 267 |
+
|
| 268 |
+
Button press scale to 0.98; focus ring using box-shadow: 0 0 0 3px color-mix(in srgb, var(--pri) 35%, transparent);
|
| 269 |
+
|
| 270 |
+
Tab switch: fade/slide content (120–180ms).
|
| 271 |
+
|
| 272 |
+
Toasts: slide-in from top-right, fade out on dismiss.
|
| 273 |
+
|
| 274 |
+
Accessibility
|
| 275 |
+
|
| 276 |
+
All interactive elements have visible focus outlines, proper roles/labels, and aria-live="polite" for toasts.
|
| 277 |
+
|
| 278 |
+
Accordion toggles use buttons with aria-controls/aria-expanded.
|
| 279 |
+
|
| 280 |
+
Sufficient color contrast (≥ 4.5:1 for body text).
|
| 281 |
+
|
| 282 |
+
Key field supports paste, reveal, and screen reader labels.
|
| 283 |
+
|
| 284 |
+
Visual Polish Checklist
|
| 285 |
+
|
| 286 |
+
Align content to a max-width container (e.g., 1100–1200px) centered; generous vertical rhythm.
|
| 287 |
+
|
| 288 |
+
Consistent iconography with inline SVGs (stroke-width 1.75–2).
|
| 289 |
+
|
| 290 |
+
Code blocks use mono system font: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
| 291 |
+
|
| 292 |
+
Use subtle separators with linear-gradient hairlines instead of harsh borders.
|
| 293 |
+
|
| 294 |
+
Empty states with friendly copy + ghost illustrations (simple inline SVG shapes).
|
| 295 |
+
|
| 296 |
+
Implementation Tasks
|
| 297 |
+
|
| 298 |
+
Refactor CSS into variables + small utility classes:
|
| 299 |
+
|
| 300 |
+
.btn, .btn--primary, .btn--ghost, .card, .input, .kbd, .badge, .toast, .dropzone, .progress, .sr-only.
|
| 301 |
+
|
| 302 |
+
Add Theme Toggle
|
| 303 |
+
|
| 304 |
+
Toggle adds/removes .theme-light on <html>; remember only the theme in localStorage (keep crypto secrets out of storage).
|
| 305 |
+
|
| 306 |
+
Key Modal
|
| 307 |
+
|
| 308 |
+
Implement as hidden div; open/close via class; trap focus while open; ESC closes.
|
| 309 |
+
|
| 310 |
+
Toasts API
|
| 311 |
+
|
| 312 |
+
notify(type, message) creates/removes toasts; stacked layout; role="status".
|
| 313 |
+
|
| 314 |
+
Advanced Panel
|
| 315 |
+
|
| 316 |
+
Populate with live parameters from last operation (iters, salt length, IV length, alg, version). Show a copyable redacted header sample.
|
| 317 |
+
|
| 318 |
+
Validation States
|
| 319 |
+
|
| 320 |
+
Inputs get .is-invalid class → subtle red ring + helper text.
|
| 321 |
+
|
| 322 |
+
Disable primary buttons until all requirements met.
|
| 323 |
+
|
| 324 |
+
Don’ts
|
| 325 |
+
|
| 326 |
+
No external fonts, icon libraries, or CSS frameworks.
|
| 327 |
+
|
| 328 |
+
No heavy animations or parallax.
|
| 329 |
+
|
| 330 |
+
Don’t store keys/plaintext anywhere persistent.
|
| 331 |
+
|
| 332 |
+
Acceptance Criteria
|
| 333 |
+
|
| 334 |
+
Still a single self-contained index.html (inline CSS/JS).
|
| 335 |
+
|
| 336 |
+
Dark mode by default; light mode toggle works and persists (theme only).
|
| 337 |
+
|
| 338 |
+
Clear, premium visuals: glassy header, elegant cards, tasteful motion, crisp focus states.
|
| 339 |
+
|
| 340 |
+
Keyboard navigable, screen-reader friendly, WCAG AA contrast.
|
| 341 |
+
|
| 342 |
+
Polished progress, toasts, modal, and drag-drop interactions.
|
| 343 |
+
|
| 344 |
+
All current crypto features continue to function unchanged.
|
| 345 |
+
|
| 346 |
+
Optional Nice-to-Haves (if time allows)
|
| 347 |
+
|
| 348 |
+
Tiny onboarding tip (dismissible) near tabs.
|
| 349 |
+
|
| 350 |
+
Quick actions row: “Paste key”, “Copy result”, “Clear all”.
|
| 351 |
+
|
| 352 |
+
Mini checksum preview (e.g., SHA-256 of ciphertext) in Advanced panel.
|
| 353 |
+
|
| 354 |
+
Proceed to implement the visual overhaul now. Keep everything in a single static HTML file and include clear comments explaining structure and style tokens.
|
| 355 |
+
Please improve the user interface by making it more modern and slick and aesthetically pleasing
|
| 356 |
+
UI/UX Overhaul for Single-File Client-Side Crypto App (Dark Mode First)
|
| 357 |
+
Goal
|
| 358 |
+
|
| 359 |
+
Redesign the existing single-file (index.html) app into a sleek, premium, dark-mode-first experience with refined typography, spacing, motion, and states—without adding any external assets (no CDNs, fonts, icon packs, or JS libs). Keep all HTML/CSS/JS inline. Maintain all current crypto features and flows.
|
| 360 |
+
|
| 361 |
+
Design System (define in :root and support dark/light)
|
| 362 |
+
|
| 363 |
+
Color tokens (WCAG AA for text):
|
| 364 |
+
|
| 365 |
+
--bg: #0b0f14, --bg-elev: #121720, --panel: #161c27, --muted: #8ba2b0
|
| 366 |
+
|
| 367 |
+
Accents (choose one primary; compute focus/hover variants):
|
| 368 |
+
|
| 369 |
+
--pri: #7dd3fc (sky), --pri-600: #38bdf8, --pri-700: #0ea5e9
|
| 370 |
+
|
| 371 |
+
Semantic:
|
| 372 |
+
|
| 373 |
+
--ok: #34d399, --warn: #fbbf24, --err: #f87171, --info: #60a5fa
|
| 374 |
+
|
| 375 |
+
Typography (system stack; no external fonts):
|
| 376 |
+
|
| 377 |
+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, "Apple Color Emoji","Segoe UI Emoji";
|
| 378 |
+
|
| 379 |
+
Scale: --text-xs: 12px, --sm: 14px, --base: 16px, --lg: 18px, --xl: 20px, --2xl: 24px
|
| 380 |
+
|
| 381 |
+
Line-height: 1.5 text, 1.2 headings. Tighten letter-spacing on headings.
|
| 382 |
+
|
| 383 |
+
Radii & Shadows:
|
| 384 |
+
|
| 385 |
+
--r: 14px panels, --r-sm: 10px inputs, --r-pill: 999px
|
| 386 |
+
|
| 387 |
+
Soft shadows: --shadow-1: 0 2px 10px rgba(0,0,0,.25), --shadow-2: 0 10px 30px rgba(0,0,0,.35)
|
| 388 |
+
|
| 389 |
+
Spacing (8-pt grid):
|
| 390 |
+
|
| 391 |
+
--sp-1: 8px, --sp-2: 12px, --sp-3: 16px, --sp-4: 20px, --sp-5: 24px, --sp-6: 32px
|
| 392 |
+
|
| 393 |
+
Light mode: implement via .theme-light (class on <html>) or @media (prefers-color-scheme: light) overrides.
|
| 394 |
+
|
| 395 |
+
Layout & Components
|
| 396 |
+
|
| 397 |
+
Header (sticky)
|
| 398 |
+
|
| 399 |
+
App name + small tagline; right side: Theme toggle, Advanced panel toggle (accordion link), GitHub-like inline badges for “AES-GCM 256”, “PBKDF2 600k”, “10 MB”.
|
| 400 |
+
|
| 401 |
+
Use subtle glassmorphism: backdrop blur on header with backdrop-filter: blur(8px); background: rgba(18,23,32,.6); border: 1px solid rgba(255,255,255,.06);
|
| 402 |
+
|
| 403 |
+
Hero strip
|
| 404 |
+
|
| 405 |
+
Two-line intro with tiny privacy note: “100% client-side · no uploads”.
|
| 406 |
+
|
| 407 |
+
Tabs (Text | File)
|
| 408 |
+
|
| 409 |
+
Segmented control with pill buttons; active tab has inner glow.
|
| 410 |
+
|
| 411 |
+
Smooth underline animation on active tab.
|
| 412 |
+
|
| 413 |
+
Cards
|
| 414 |
+
|
| 415 |
+
Split layout for each tab:
|
| 416 |
+
|
| 417 |
+
Left card: input (textarea or dropzone).
|
| 418 |
+
|
| 419 |
+
Right card: output/result with copy + download actions.
|
| 420 |
+
|
| 421 |
+
Cards use --panel background, rounded corners, soft shadow, generous padding.
|
| 422 |
+
|
| 423 |
+
Inputs
|
| 424 |
+
|
| 425 |
+
Minimal “borderless” fields with 1px hairline on focus; large click targets.
|
| 426 |
+
|
| 427 |
+
Password/Key area with show/hide toggle and copy button.
|
| 428 |
+
|
| 429 |
+
Key generation presented in a modal sheet (see below).
|
| 430 |
+
|
| 431 |
+
Drag & drop zone (File tab)
|
| 432 |
+
|
| 433 |
+
Dotted rounded border, hover elevation, icon (inline SVG), file details preview (name, size, type), and size-limit helper.
|
| 434 |
+
|
| 435 |
+
Primary actions
|
| 436 |
+
|
| 437 |
+
“Encrypt” and “Decrypt” as large pill buttons with icon + label; animated hover (elevate + slight glow). Disable when invalid.
|
| 438 |
+
|
| 439 |
+
Status & Progress
|
| 440 |
+
|
| 441 |
+
Progress bar (indeterminate → determinate for files), inline toast notifications (top-right) with semantic colors; auto-dismiss + manual close.
|
| 442 |
+
|
| 443 |
+
Advanced panel
|
| 444 |
+
|
| 445 |
+
Collapsible below header; animate height with max-height + opacity and aria-expanded. Show algorithm details, parameters from last run, and a redacted JSON header rendered in a code block with syntax-like styling.
|
| 446 |
+
|
| 447 |
+
Modal: “Generate Secure Key”
|
| 448 |
+
|
| 449 |
+
Centered sheet with blur backdrop; explains raw vs passphrase, lets user choose 32-byte random key; shows Base64 key with copy + download and “Use this key” button.
|
| 450 |
+
|
| 451 |
+
Motion & Interactions
|
| 452 |
+
|
| 453 |
+
Respect prefers-reduced-motion: reduce.
|
| 454 |
+
|
| 455 |
+
Use subtle micro-interactions:
|
| 456 |
+
|
| 457 |
+
150–220ms transitions on hover/focus/elevation.
|
| 458 |
+
|
| 459 |
+
Button press scale to 0.98; focus ring using box-shadow: 0 0 0 3px color-mix(in srgb, var(--pri) 35%, transparent);
|
| 460 |
+
|
| 461 |
+
Tab switch: fade/slide content (120–180ms).
|
| 462 |
+
|
| 463 |
+
Toasts: slide-in from top-right, fade out on dismiss.
|
| 464 |
+
|
| 465 |
+
Accessibility
|
| 466 |
+
|
| 467 |
+
All interactive elements have visible focus outlines, proper roles/labels, and aria-live="polite" for toasts.
|
| 468 |
+
|
| 469 |
+
Accordion toggles use buttons with aria-controls/aria-expanded.
|
| 470 |
+
|
| 471 |
+
Sufficient color contrast (≥ 4.5:1 for body text).
|
| 472 |
+
|
| 473 |
+
Key field supports paste, reveal, and screen reader labels.
|
| 474 |
+
|
| 475 |
+
Visual Polish Checklist
|
| 476 |
+
|
| 477 |
+
Align content to a max-width container (e.g., 1100–1200px) centered; generous vertical rhythm.
|
| 478 |
+
|
| 479 |
+
Consistent iconography with inline SVGs (stroke-width 1.75–2).
|
| 480 |
+
|
| 481 |
+
Code blocks use mono system font: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
| 482 |
+
|
| 483 |
+
Use subtle separators with linear-gradient hairlines instead of harsh borders.
|
| 484 |
+
|
| 485 |
+
Empty states with friendly copy + ghost illustrations (simple inline SVG shapes).
|
| 486 |
+
|
| 487 |
+
Implementation Tasks
|
| 488 |
+
|
| 489 |
+
Refactor CSS into variables + small utility classes:
|
| 490 |
+
|
| 491 |
+
.btn, .btn--primary, .btn--ghost, .card, .input, .kbd, .badge, .toast, .dropzone, .progress, .sr-only.
|
| 492 |
+
|
| 493 |
+
Add Theme Toggle
|
| 494 |
+
|
| 495 |
+
Toggle adds/removes .theme-light on <html>; remember only the theme in localStorage (keep crypto secrets out of storage).
|
| 496 |
+
|
| 497 |
+
Key Modal
|
| 498 |
+
|
| 499 |
+
Implement as hidden div; open/close via class; trap focus while open; ESC closes.
|
| 500 |
+
|
| 501 |
+
Toasts API
|
| 502 |
+
|
| 503 |
+
notify(type, message) creates/removes toasts; stacked layout; role="status".
|
| 504 |
+
|
| 505 |
+
Advanced Panel
|
| 506 |
+
|
| 507 |
+
Populate with live parameters from last operation (iters, salt length, IV length, alg, version). Show a copyable redacted header sample.
|
| 508 |
+
|
| 509 |
+
Validation States
|
| 510 |
+
|
| 511 |
+
Inputs get .is-invalid class → subtle red ring + helper text.
|
| 512 |
+
|
| 513 |
+
Disable primary buttons until all requirements met.
|
| 514 |
+
|
| 515 |
+
Don’ts
|
| 516 |
+
|
| 517 |
+
No external fonts, icon libraries, or CSS frameworks.
|
| 518 |
+
|
| 519 |
+
No heavy animations or parallax.
|
| 520 |
+
|
| 521 |
+
Don’t store keys/plaintext anywhere persistent.
|
| 522 |
+
|
| 523 |
+
Acceptance Criteria
|
| 524 |
+
|
| 525 |
+
Still a single self-contained index.html (inline CSS/JS).
|
| 526 |
+
|
| 527 |
+
Dark mode by default; light mode toggle works and persists (theme only).
|
| 528 |
+
|
| 529 |
+
Clear, premium visuals: glassy header, elegant cards, tasteful motion, crisp focus states.
|
| 530 |
+
|
| 531 |
+
Keyboard navigable, screen-reader friendly, WCAG AA contrast.
|
| 532 |
+
|
| 533 |
+
Polished progress, toasts, modal, and drag-drop interactions.
|
| 534 |
+
|
| 535 |
+
All current crypto features continue to function unchanged.
|
| 536 |
+
|
| 537 |
+
Optional Nice-to-Haves (if time allows)
|
| 538 |
+
|
| 539 |
+
Tiny onboarding tip (dismissible) near tabs.
|
| 540 |
+
|
| 541 |
+
Quick actions row: “Paste key”, “Copy result”, “Clear all”.
|
| 542 |
+
|
| 543 |
+
Mini checksum preview (e.g., SHA-256 of ciphertext) in Advanced panel.
|
| 544 |
+
|
| 545 |
+
Proceed to implement the visual overhaul now. Keep everything in a single static HTML file and include clear comments explaining structure and style tokens.
|
| 546 |
+
UI/UX Overhaul for Single-File Client-Side Crypto App (Dark Mode First)
|
| 547 |
+
Goal
|
| 548 |
+
|
| 549 |
+
Redesign the existing single-file (index.html) app into a sleek, premium, dark-mode-first experience with refined typography, spacing, motion, and states—without adding any external assets (no CDNs, fonts, icon packs, or JS libs). Keep all HTML/CSS/JS inline. Maintain all current crypto features and flows.
|
| 550 |
+
|
| 551 |
+
Design System (define in :root and support dark/light)
|
| 552 |
+
|
| 553 |
+
Color tokens (WCAG AA for text):
|
| 554 |
+
|
| 555 |
+
--bg: #0b0f14, --bg-elev: #121720, --panel: #161c27, --muted: #8ba2b0
|
| 556 |
+
|
| 557 |
+
Accents (choose one primary; compute focus/hover variants):
|
| 558 |
+
|
| 559 |
+
--pri: #7dd3fc (sky), --pri-600: #38bdf8, --pri-700: #0ea5e9
|
| 560 |
+
|
| 561 |
+
Semantic:
|
| 562 |
+
|
| 563 |
+
--ok: #34d399, --warn: #fbbf24, --err: #f87171, --info: #60a5fa
|
| 564 |
+
|
| 565 |
+
Typography (system stack; no external fonts):
|
| 566 |
+
|
| 567 |
+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, "Apple Color Emoji","Segoe UI Emoji";
|
| 568 |
+
|
| 569 |
+
Scale: --text-xs: 12px, --sm: 14px, --base: 16px, --lg: 18px, --xl: 20px, --2xl: 24px
|
| 570 |
+
|
| 571 |
+
Line-height: 1.5 text, 1.2 headings. Tighten letter-spacing on headings.
|
| 572 |
+
|
| 573 |
+
Radii & Shadows:
|
| 574 |
+
|
| 575 |
+
--r: 14px panels, --r-sm: 10px inputs, --r-pill: 999px
|
| 576 |
+
|
| 577 |
+
Soft shadows: --shadow-1: 0 2px 10px rgba(0,0,0,.25), --shadow-2: 0 10px 30px rgba(0,0,0,.35)
|
| 578 |
+
|
| 579 |
+
Spacing (8-pt grid):
|
| 580 |
+
|
| 581 |
+
--sp-1: 8px, --sp-2: 12px, --sp-3: 16px, --sp-4: 20px, --sp-5: 24px, --sp-6: 32px
|
| 582 |
+
|
| 583 |
+
Light mode: implement via .theme-light (class on <html>) or @media (prefers-color-scheme: light) overrides.
|
| 584 |
+
|
| 585 |
+
Layout & Components
|
| 586 |
+
|
| 587 |
+
Header (sticky)
|
| 588 |
+
|
| 589 |
+
App name + small tagline; right side: Theme toggle, Advanced panel toggle (accordion link), GitHub-like inline badges for “AES-GCM 256”, “PBKDF2 600k”, “10 MB”.
|
| 590 |
+
|
| 591 |
+
Use subtle glassmorphism: backdrop blur on header with backdrop-filter: blur(8px); background: rgba(18,23,32,.6); border: 1px solid rgba(255,255,255,.06);
|
| 592 |
+
|
| 593 |
+
Hero strip
|
| 594 |
+
|
| 595 |
+
Two-line intro with tiny privacy note: “100% client-side · no uploads”.
|
| 596 |
+
|
| 597 |
+
Tabs (Text | File)
|
| 598 |
+
|
| 599 |
+
Segmented control with pill buttons; active tab has inner glow.
|
| 600 |
+
|
| 601 |
+
Smooth underline animation on active tab.
|
| 602 |
+
|
| 603 |
+
Cards
|
| 604 |
+
|
| 605 |
+
Split layout for each tab:
|
| 606 |
+
|
| 607 |
+
Left card: input (textarea or dropzone).
|
| 608 |
+
|
| 609 |
+
Right card: output/result with copy + download actions.
|
| 610 |
+
|
| 611 |
+
Cards use --panel background, rounded corners, soft shadow, generous padding.
|
| 612 |
+
|
| 613 |
+
Inputs
|
| 614 |
+
|
| 615 |
+
Minimal “borderless” fields with 1px hairline on focus; large click targets.
|
| 616 |
+
|
| 617 |
+
Password/Key area with show/hide toggle and copy button.
|
| 618 |
+
|
| 619 |
+
Key generation presented in a modal sheet (see below).
|
| 620 |
+
|
| 621 |
+
Drag & drop zone (File tab)
|
| 622 |
+
|
| 623 |
+
Dotted rounded border, hover elevation, icon (inline SVG), file details preview (name, size, type), and size-limit helper.
|
| 624 |
+
|
| 625 |
+
Primary actions
|
| 626 |
+
|
| 627 |
+
“Encrypt” and “Decrypt” as large pill buttons with icon + label; animated hover (elevate + slight glow). Disable when invalid.
|
| 628 |
+
|
| 629 |
+
Status & Progress
|
| 630 |
+
|
| 631 |
+
Progress bar (indeterminate → determinate for files), inline toast notifications (top-right) with semantic colors; auto-dismiss + manual close.
|
| 632 |
+
|
| 633 |
+
Advanced panel
|
| 634 |
+
|
| 635 |
+
Collapsible below header; animate height with max-height + opacity and aria-expanded. Show algorithm details, parameters from last run, and a redacted JSON header rendered in a code block with syntax-like styling.
|
| 636 |
+
|
| 637 |
+
Modal: “Generate Secure Key”
|
| 638 |
+
|
| 639 |
+
Centered sheet with blur backdrop; explains raw vs passphrase, lets user choose 32-byte random key; shows Base64 key with copy + download and “Use this key” button.
|
| 640 |
+
|
| 641 |
+
Motion & Interactions
|
| 642 |
+
|
| 643 |
+
Respect prefers-reduced-motion: reduce.
|
| 644 |
+
|
| 645 |
+
Use subtle micro-interactions:
|
| 646 |
+
|
| 647 |
+
150–220ms transitions on hover/focus/elevation.
|
| 648 |
+
|
| 649 |
+
Button press scale to 0.98; focus ring using box-shadow: 0 0 0 3px color-mix(in srgb, var(--pri) 35%, transparent);
|
| 650 |
+
|
| 651 |
+
Tab switch: fade/slide content (120–180ms).
|
| 652 |
+
|
| 653 |
+
Toasts: slide-in from top-right, fade out on dismiss.
|
| 654 |
+
|
| 655 |
+
Accessibility
|
| 656 |
+
|
| 657 |
+
All interactive elements have visible focus outlines, proper roles/labels, and aria-live="polite" for toasts.
|
| 658 |
+
|
| 659 |
+
Accordion toggles use buttons with aria-controls/aria-expanded.
|
| 660 |
+
|
| 661 |
+
Sufficient color contrast (≥ 4.5:1 for body text).
|
| 662 |
+
|
| 663 |
+
Key field supports paste, reveal, and screen reader labels.
|
| 664 |
+
|
| 665 |
+
Visual Polish Checklist
|
| 666 |
+
|
| 667 |
+
Align content to a max-width container (e.g., 1100–1200px) centered; generous vertical rhythm.
|
| 668 |
+
|
| 669 |
+
Consistent iconography with inline SVGs (stroke-width 1.75–2).
|
| 670 |
+
|
| 671 |
+
Code blocks use mono system font: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
| 672 |
+
|
| 673 |
+
Use subtle separators with linear-gradient hairlines instead of harsh borders.
|
| 674 |
+
|
| 675 |
+
Empty states with friendly copy + ghost illustrations (simple inline SVG shapes).
|
| 676 |
+
|
| 677 |
+
Implementation Tasks
|
| 678 |
+
|
| 679 |
+
Refactor CSS into variables + small utility classes:
|
| 680 |
+
|
| 681 |
+
.btn, .btn--primary, .btn--ghost, .card, .input, .kbd, .badge, .toast, .dropzone, .progress, .sr-only.
|
| 682 |
+
|
| 683 |
+
Add Theme Toggle
|
| 684 |
+
|
| 685 |
+
Toggle adds/removes .theme-light on <html>; remember only the theme in localStorage (keep crypto secrets out of storage).
|
| 686 |
+
|
| 687 |
+
Key Modal
|
| 688 |
+
|
| 689 |
+
Implement as hidden div; open/close via class; trap focus while open; ESC closes.
|
| 690 |
+
|
| 691 |
+
Toasts API
|
| 692 |
+
|
| 693 |
+
notify(type, message) creates/removes toasts; stacked layout; role="status".
|
| 694 |
+
|
| 695 |
+
Advanced Panel
|
| 696 |
+
|
| 697 |
+
Populate with live parameters from last operation (iters, salt length, IV length, alg, version). Show a copyable redacted header sample.
|
| 698 |
+
|
| 699 |
+
Validation States
|
| 700 |
+
|
| 701 |
+
Inputs get .is-invalid class → subtle red ring + helper text.
|
| 702 |
+
|
| 703 |
+
Disable primary buttons until all requirements met.
|
| 704 |
+
|
| 705 |
+
Don’ts
|
| 706 |
+
|
| 707 |
+
No external fonts, icon libraries, or CSS frameworks.
|
| 708 |
+
|
| 709 |
+
No heavy animations or parallax.
|
| 710 |
+
|
| 711 |
+
Don’t store keys/plaintext anywhere persistent.
|
| 712 |
+
|
| 713 |
+
Acceptance Criteria
|
| 714 |
+
|
| 715 |
+
Still a single self-contained index.html (inline CSS/JS).
|
| 716 |
+
|
| 717 |
+
Dark mode by default; light mode toggle works and persists (theme only).
|
| 718 |
+
|
| 719 |
+
Clear, premium visuals: glassy header, elegant cards, tasteful motion, crisp focus states.
|
| 720 |
+
|
| 721 |
+
Keyboard navigable, screen-reader friendly, WCAG AA contrast.
|
| 722 |
+
|
| 723 |
+
Polished progress, toasts, modal, and drag-drop interactions.
|
| 724 |
+
|
| 725 |
+
All current crypto features continue to function unchanged.
|
| 726 |
+
|
| 727 |
+
Optional Nice-to-Haves (if time allows)
|
| 728 |
+
|
| 729 |
+
Tiny onboarding tip (dismissible) near tabs.
|
| 730 |
+
|
| 731 |
+
Quick actions row: “Paste key”, “Copy result”, “Clear all”.
|
| 732 |
+
|
| 733 |
+
Mini checksum preview (e.g., SHA-256 of ciphertext) in Advanced panel.
|
| 734 |
+
|
| 735 |
+
Proceed to implement the visual overhaul now. Keep everything in a single static HTML file and include clear comments explaining structure and style tokens.
|
| 736 |
+
UI/UX Overhaul for Single-File Client-Side Crypto App (Dark Mode First)
|
| 737 |
+
Goal
|
| 738 |
+
|
| 739 |
+
Redesign the existing single-file (index.html) app into a sleek, premium, dark-mode-first experience with refined typography, spacing, motion, and states—without adding any external assets (no CDNs, fonts, icon packs, or JS libs). Keep all HTML/CSS/JS inline. Maintain all current crypto features and flows.
|
| 740 |
+
|
| 741 |
+
Design System (define in :root and support dark/light)
|
| 742 |
+
|
| 743 |
+
Color tokens (WCAG AA for text):
|
| 744 |
+
|
| 745 |
+
--bg: #0b0f14, --bg-elev: #121720, --panel: #161c27, --muted: #8ba2b0
|
| 746 |
+
|
| 747 |
+
Accents (choose one primary; compute focus/hover variants):
|
| 748 |
+
|
| 749 |
+
--pri: #7dd3fc (sky), --pri-600: #38bdf8, --pri-700: #0ea5e9
|
| 750 |
+
|
| 751 |
+
Semantic:
|
| 752 |
+
|
| 753 |
+
--ok: #34d399, --warn: #fbbf24, --err: #f87171, --info: #60a5fa
|
| 754 |
+
|
| 755 |
+
Typography (system stack; no external fonts):
|
| 756 |
+
|
| 757 |
+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Inter, Noto Sans, Ubuntu, Cantarell, Helvetica Neue, Arial, "Apple Color Emoji","Segoe UI Emoji";
|
| 758 |
+
|
| 759 |
+
Scale: --text-xs: 12px, --sm: 14px, --base: 16px, --lg: 18px, --xl: 20px, --2xl: 24px
|
| 760 |
+
|
| 761 |
+
Line-height: 1.5 text, 1.2 headings. Tighten letter-spacing on headings.
|
| 762 |
+
|
| 763 |
+
Radii & Shadows:
|
| 764 |
+
|
| 765 |
+
--r: 14px panels, --r-sm: 10px inputs, --r-pill: 999px
|
| 766 |
+
|
| 767 |
+
Soft shadows: --shadow-1: 0 2px 10px rgba(0,0,0,.25), --shadow-2: 0 10px 30px rgba(0,0,0,.35)
|
| 768 |
+
|
| 769 |
+
Spacing (8-pt grid):
|
| 770 |
+
|
| 771 |
+
--sp-1: 8px, --sp-2: 12px, --sp-3: 16px, --sp-4: 20px, --sp-5: 24px, --sp-6: 32px
|
| 772 |
+
|
| 773 |
+
Light mode: implement via .theme-light (class on <html>) or @media (prefers-color-scheme: light) overrides.
|
| 774 |
+
|
| 775 |
+
Layout & Components
|
| 776 |
+
|
| 777 |
+
Header (sticky)
|
| 778 |
+
|
| 779 |
+
App name + small tagline; right side: Theme toggle, Advanced panel toggle (accordion link), GitHub-like inline badges for “AES-GCM 256”, “PBKDF2 600k”, “10 MB”.
|
| 780 |
+
|
| 781 |
+
Use subtle glassmorphism: backdrop blur on header with backdrop-filter: blur(8px); background: rgba(18,23,32,.6); border: 1px solid rgba(255,255,255,.06);
|
| 782 |
+
|
| 783 |
+
Hero strip
|
| 784 |
+
|
| 785 |
+
Two-line intro with tiny privacy note: “100% client-side · no uploads”.
|
| 786 |
+
|
| 787 |
+
Tabs (Text | File)
|
| 788 |
+
|
| 789 |
+
Segmented control with pill buttons; active tab has inner glow.
|
| 790 |
+
|
| 791 |
+
Smooth underline animation on active tab.
|
| 792 |
+
|
| 793 |
+
Cards
|
| 794 |
+
|
| 795 |
+
Split layout for each tab:
|
| 796 |
+
|
| 797 |
+
Left card: input (textarea or dropzone).
|
| 798 |
+
|
| 799 |
+
Right card: output/result with copy + download actions.
|
| 800 |
+
|
| 801 |
+
Cards use --panel background, rounded corners, soft shadow, generous padding.
|
| 802 |
+
|
| 803 |
+
Inputs
|
| 804 |
+
|
| 805 |
+
Minimal “borderless” fields with 1px hairline on focus; large click targets.
|
| 806 |
+
|
| 807 |
+
Password/Key area with show/hide toggle and copy button.
|
| 808 |
+
|
| 809 |
+
Key generation presented in a modal sheet (see below).
|
| 810 |
+
|
| 811 |
+
Drag & drop zone (File tab)
|
| 812 |
+
|
| 813 |
+
Dotted rounded border, hover elevation, icon (inline SVG), file details preview (name, size, type), and size-limit helper.
|
| 814 |
+
|
| 815 |
+
Primary actions
|
| 816 |
+
|
| 817 |
+
“Encrypt” and “Decrypt” as large pill buttons with icon + label; animated hover (elevate + slight glow). Disable when invalid.
|
| 818 |
+
|
| 819 |
+
Status & Progress
|
| 820 |
+
|
| 821 |
+
Progress bar (indeterminate → determinate for files), inline toast notifications (top-right) with semantic colors; auto-dismiss + manual close.
|
| 822 |
+
|
| 823 |
+
Advanced panel
|
| 824 |
+
|
| 825 |
+
Collapsible below header; animate height with max-height + opacity and aria-expanded. Show algorithm details, parameters from last run, and a redacted JSON header rendered in a code block with syntax-like styling.
|
| 826 |
+
|
| 827 |
+
Modal: “Generate Secure Key”
|
| 828 |
+
|
| 829 |
+
Centered sheet with blur backdrop; explains raw vs passphrase, lets user choose 32-byte random key; shows Base64 key with copy + download and “Use this key” button.
|
| 830 |
+
|
| 831 |
+
Motion & Interactions
|
| 832 |
+
|
| 833 |
+
Respect prefers-reduced-motion: reduce.
|
| 834 |
+
|
| 835 |
+
Use subtle micro-interactions:
|
| 836 |
+
|
| 837 |
+
150–220ms transitions on hover/focus/elevation.
|
| 838 |
+
|
| 839 |
+
Button press scale to 0.98; focus ring using box-shadow: 0 0 0 3px color-mix(in srgb, var(--pri) 35%, transparent);
|
| 840 |
+
|
| 841 |
+
Tab switch: fade/slide content (120–180ms).
|
| 842 |
+
|
| 843 |
+
Toasts: slide-in from top-right, fade out on dismiss.
|
| 844 |
+
|
| 845 |
+
Accessibility
|
| 846 |
+
|
| 847 |
+
All interactive elements have visible focus outlines, proper roles/labels, and aria-live="polite" for toasts.
|
| 848 |
+
|
| 849 |
+
Accordion toggles use buttons with aria-controls/aria-expanded.
|
| 850 |
+
|
| 851 |
+
Sufficient color contrast (≥ 4.5:1 for body text).
|
| 852 |
+
|
| 853 |
+
Key field supports paste, reveal, and screen reader labels.
|
| 854 |
+
|
| 855 |
+
Visual Polish Checklist
|
| 856 |
+
|
| 857 |
+
Align content to a max-width container (e.g., 1100–1200px) centered; generous vertical rhythm.
|
| 858 |
+
|
| 859 |
+
Consistent iconography with inline SVGs (stroke-width 1.75–2).
|
| 860 |
+
|
| 861 |
+
Code blocks use mono system font: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
| 862 |
+
|
| 863 |
+
Use subtle separators with linear-gradient hairlines instead of harsh borders.
|
| 864 |
+
|
| 865 |
+
Empty states with friendly copy + ghost illustrations (simple inline SVG shapes).
|
| 866 |
+
|
| 867 |
+
Implementation Tasks
|
| 868 |
+
|
| 869 |
+
Refactor CSS into variables + small utility classes:
|
| 870 |
+
|
| 871 |
+
.btn, .btn--primary, .btn--ghost, .card, .input, .kbd, .badge, .toast, .dropzone, .progress, .sr-only.
|
| 872 |
+
|
| 873 |
+
Add Theme Toggle
|
| 874 |
+
|
| 875 |
+
Toggle adds/removes .theme-light on <html>; remember only the theme in localStorage (keep crypto secrets out of storage).
|
| 876 |
+
|
| 877 |
+
Key Modal
|
| 878 |
+
|
| 879 |
+
Implement as hidden div; open/close via class; trap focus while open; ESC closes.
|
| 880 |
+
|
| 881 |
+
Toasts API
|
| 882 |
+
|
| 883 |
+
notify(type, message) creates/removes toasts; stacked layout; role="status".
|
| 884 |
+
|
| 885 |
+
Advanced Panel
|
| 886 |
+
|
| 887 |
+
Populate with live parameters from last operation (iters, salt length, IV length, alg, version). Show a copyable redacted header sample.
|
| 888 |
+
|
| 889 |
+
Validation States
|
| 890 |
+
|
| 891 |
+
Inputs get .is-invalid class → subtle red ring + helper text.
|
| 892 |
+
|
| 893 |
+
Disable primary buttons until all requirements met.
|
| 894 |
+
|
| 895 |
+
Don’ts
|
| 896 |
+
|
| 897 |
+
No external fonts, icon libraries, or CSS frameworks.
|
| 898 |
+
|
| 899 |
+
No heavy animations or parallax.
|
| 900 |
+
|
| 901 |
+
Don’t store keys/plaintext anywhere persistent.
|
| 902 |
+
|
| 903 |
+
Acceptance Criteria
|
| 904 |
+
|
| 905 |
+
Still a single self-contained index.html (inline CSS/JS).
|
| 906 |
+
|
| 907 |
+
Dark mode by default; light mode toggle works and persists (theme only).
|
| 908 |
+
|
| 909 |
+
Clear, premium visuals: glassy header, elegant cards, tasteful motion, crisp focus states.
|
| 910 |
+
|
| 911 |
+
Keyboard navigable, screen-reader friendly, WCAG AA contrast.
|
| 912 |
+
|
| 913 |
+
Polished progress, toasts, modal, and drag-drop interactions.
|
| 914 |
+
|
| 915 |
+
All current crypto features continue to function unchanged.
|
| 916 |
+
|
| 917 |
+
Optional Nice-to-Haves (if time allows)
|
| 918 |
+
|
| 919 |
+
Tiny onboarding tip (dismissible) near tabs.
|
| 920 |
+
|
| 921 |
+
Quick actions row: “Paste key”, “Copy result”, “Clear all”.
|
| 922 |
+
|
| 923 |
+
Mini checksum preview (e.g., SHA-256 of ciphertext) in Advanced panel.
|
| 924 |
+
|
| 925 |
+
Proceed to implement the visual overhaul now. Keep everything in a single static HTML file and include clear comments explaining structure and style tokens.
|
| 926 |
+
Build a Single-File Static Web App for Client-Side Encryption/Decryption (Dark Mode, 10 MB limit)
|
| 927 |
+
Absolutely Required
|
| 928 |
+
|
| 929 |
+
Deliverable: A single self-contained index.html file that runs locally via file:// or any static host.
|
| 930 |
+
|
| 931 |
+
No build tools, no servers, no external assets (no CDN, no Tailwind, no NPM).
|
| 932 |
+
|
| 933 |
+
All HTML, CSS, and JS must be embedded in this one file (inline <style> and <script type="module">).
|
| 934 |
+
|
| 935 |
+
Must work in modern Chromium/Firefox/Safari.
|
| 936 |
+
|
| 937 |
+
Goal
|
| 938 |
+
|
| 939 |
+
Create a modern, responsive, dark-mode single page that performs 100% client-side encryption and decryption of entered text or uploaded files (max 10 MB). No data ever leaves the browser.
|
| 940 |
+
|
| 941 |
+
Cryptography (Web Crypto API only)
|
| 942 |
+
|
| 943 |
+
Symmetric encryption: AES-GCM (256-bit) via window.crypto.subtle.
|
| 944 |
+
|
| 945 |
+
Passphrase → key: PBKDF2/SHA-256, 16-byte random salt, ≥ 600,000 iterations (configurable).
|
| 946 |
+
|
| 947 |
+
12-byte random IV per encryption.
|
| 948 |
+
|
| 949 |
+
Integrity: rely on AES-GCM auth tag; show clear success/failure on decrypt.
|
| 950 |
+
|
| 951 |
+
Raw key option: if user supplies a 32-byte random key (Base64/URL-safe), skip PBKDF2 and import directly for AES-GCM.
|
| 952 |
+
|
| 953 |
+
Never roll your own crypto; no third-party crypto libraries.
|
| 954 |
+
|
| 955 |
+
Package/Container Format
|
| 956 |
+
|
| 957 |
+
Support a compact, versioned container for both text and files. Use a Base64-armored string with a magic prefix, e.g. ENCv1: followed by Base64 of:
|
| 958 |
+
|
| 959 |
+
UTF-8 JSON header (first), then a newline \n,
|
| 960 |
+
|
| 961 |
+
then raw ciphertext bytes (including GCM tag).
|
| 962 |
+
|
| 963 |
+
Header JSON example:
|
| 964 |
+
|
| 965 |
+
{
|
| 966 |
+
"v": 1,
|
| 967 |
+
"alg": "AES-GCM",
|
| 968 |
+
"kdf": {"name":"PBKDF2","hash":"SHA-256","iters":600000,"salt_b64":"..."},
|
| 969 |
+
"iv_b64": "...",
|
| 970 |
+
"keyType": "passphrase|raw",
|
| 971 |
+
"created": "2025-09-06T00:00:00Z",
|
| 972 |
+
"type": "text|file",
|
| 973 |
+
"orig": {"name":"report.pdf","mime":"application/pdf","size":123456}
|
| 974 |
+
}
|
| 975 |
+
|
| 976 |
+
|
| 977 |
+
If using a raw key: "kdf": null, "keyType":"raw".
|
| 978 |
+
|
| 979 |
+
For text mode, omit or simplify "orig".
|
| 980 |
+
|
| 981 |
+
UI/UX Requirements
|
| 982 |
+
|
| 983 |
+
Tabs or segmented controls: Text and File modes.
|
| 984 |
+
|
| 985 |
+
Text tab: textarea input; Encrypt and Decrypt; output area with copy buttons.
|
| 986 |
+
|
| 987 |
+
File tab: drag-and-drop + picker; show filename/size; block > 10 MB with friendly error.
|
| 988 |
+
|
| 989 |
+
On Encrypt, download a .enc file containing the armored package.
|
| 990 |
+
|
| 991 |
+
On Decrypt, reconstruct original file (name/MIME from header) and download.
|
| 992 |
+
|
| 993 |
+
Key input section:
|
| 994 |
+
|
| 995 |
+
Field for passphrase or toggle to Generate secure key (32 random bytes → Base64/URL-safe).
|
| 996 |
+
|
| 997 |
+
Provide Copy and Download .key (text) for generated keys.
|
| 998 |
+
|
| 999 |
+
Clear indicators whether passphrase (PBKDF2) or raw key flow is active.
|
| 1000 |
+
|
| 1001 |
+
Status & Progress:
|
| 1002 |
+
|
| 1003 |
+
Progress bar/spinner for file operations; inline success/error toasts.
|
| 1004 |
+
|
| 1005 |
+
Modern dark UI (default):
|
| 1006 |
+
|
| 1007 |
+
Sleek, minimal, responsive layout with smooth micro-animations.
|
| 1008 |
+
|
| 1009 |
+
Include a light/dark toggle.
|
| 1010 |
+
|
| 1011 |
+
User Instructions (visible panel):
|
| 1012 |
+
|
| 1013 |
+
Step-by-step: choose Text/File → enter or generate key → Encrypt/Decrypt → manage/download results.
|
| 1014 |
+
|
| 1015 |
+
Prominent warning: “If you lose the key, you lose the data.”
|
| 1016 |
+
|
| 1017 |
+
Advanced/Technical Header (collapsible):
|
| 1018 |
+
|
| 1019 |
+
An accessible toggle button (aria-expanded, aria-controls).
|
| 1020 |
+
|
| 1021 |
+
On expand, show algorithm details, PBKDF2 iteration count, salt/IV lengths, format version, and a redacted example header from the last operation.
|
| 1022 |
+
|
| 1023 |
+
Privacy Note:
|
| 1024 |
+
|
| 1025 |
+
“All operations occur locally in your browser. No data is uploaded.”
|
| 1026 |
+
|
| 1027 |
+
Validation & Errors
|
| 1028 |
+
|
| 1029 |
+
Empty inputs, missing key, size limit exceeded → user-friendly inline errors.
|
| 1030 |
+
|
| 1031 |
+
Wrong key/corruption → “Decryption failed (wrong key or corrupted data).”
|
| 1032 |
+
|
| 1033 |
+
Unsupported package version → clear error referencing v.
|
| 1034 |
+
|
| 1035 |
+
Catch and display Web Crypto exceptions.
|
| 1036 |
+
|
| 1037 |
+
Implementation Notes (Single-File Constraints)
|
| 1038 |
+
|
| 1039 |
+
Use plain ES modules: a single <script type="module"> block in index.html.
|
| 1040 |
+
|
| 1041 |
+
Keep secrets in memory only; no LocalStorage/IndexedDB for keys or plaintext.
|
| 1042 |
+
|
| 1043 |
+
Provide helper functions for:
|
| 1044 |
+
|
| 1045 |
+
deriveKeyFromPassphrase(pass, salt, iters) → CryptoKey
|
| 1046 |
+
|
| 1047 |
+
importRawKey(base64) → CryptoKey
|
| 1048 |
+
|
| 1049 |
+
encryptText, decryptText
|
| 1050 |
+
|
| 1051 |
+
encryptFile, decryptFile (use Blob/ArrayBuffer, FileReader)
|
| 1052 |
+
|
| 1053 |
+
encodePackage(headerObj, cipherBytes) → "ENCv1:...base64..."
|
| 1054 |
+
|
| 1055 |
+
decodePackage(armored) → {header, cipherBytes}
|
| 1056 |
+
|
| 1057 |
+
Show a short example round-trip in the Advanced panel after first success (parameters only, no secrets).
|
| 1058 |
+
|
| 1059 |
+
Accessibility
|
| 1060 |
+
|
| 1061 |
+
Keyboard navigable controls, visible focus states.
|
| 1062 |
+
|
| 1063 |
+
Proper aria-* for collapsible advanced header, tab controls, and toasts/alerts.
|
| 1064 |
+
|
| 1065 |
+
Security Footnotes (display in Advanced)
|
| 1066 |
+
|
| 1067 |
+
Unique salt per KDF, unique IV per message.
|
| 1068 |
+
|
| 1069 |
+
Recommend long passphrases or random 32-byte keys.
|
| 1070 |
+
|
| 1071 |
+
Emphasize no recovery if key is lost.
|
| 1072 |
+
|
| 1073 |
+
Clarify threat model: protects at-rest data; does not protect against a compromised device.
|
| 1074 |
+
|
| 1075 |
+
Acceptance Criteria
|
| 1076 |
+
|
| 1077 |
+
Ships as one index.html file; opens and works from file://.
|
| 1078 |
+
|
| 1079 |
+
Encrypts/decrypts text and files ≤ 10 MB entirely offline.
|
| 1080 |
+
|
| 1081 |
+
Supports both PBKDF2 passphrase and raw 32-byte key flows.
|
| 1082 |
+
|
| 1083 |
+
Produces/consumes the specified ENCv1: Base64 format with JSON header.
|
| 1084 |
+
|
| 1085 |
+
Dark mode by default, responsive, accessible, with a collapsible technical header.
|
| 1086 |
+
|
| 1087 |
+
Clear errors for wrong key, bad format, or size over limit.
|
| 1088 |
+
|
| 1089 |
+
Now implement the entire app in a single self-contained index.html with inline CSS and JS (no external resources). Include helpful comments in code.
|
| 1090 |
+
Build a Single-File Static Web App for Client-Side Encryption/Decryption (Dark Mode, 10 MB limit)
|
| 1091 |
+
Absolutely Required
|
| 1092 |
+
|
| 1093 |
+
Deliverable: A single self-contained index.html file that runs locally via file:// or any static host.
|
| 1094 |
+
|
| 1095 |
+
No build tools, no servers, no external assets (no CDN, no Tailwind, no NPM).
|
| 1096 |
+
|
| 1097 |
+
All HTML, CSS, and JS must be embedded in this one file (inline <style> and <script type="module">).
|
| 1098 |
+
|
| 1099 |
+
Must work in modern Chromium/Firefox/Safari.
|
| 1100 |
+
|
| 1101 |
+
Goal
|
| 1102 |
+
|
| 1103 |
+
Create a modern, responsive, dark-mode single page that performs 100% client-side encryption and decryption of entered text or uploaded files (max 10 MB). No data ever leaves the browser.
|
| 1104 |
+
|
| 1105 |
+
Cryptography (Web Crypto API only)
|
| 1106 |
+
|
| 1107 |
+
Symmetric encryption: AES-GCM (256-bit) via window.crypto.subtle.
|
| 1108 |
+
|
| 1109 |
+
Passphrase → key: PBKDF2/SHA-256, 16-byte random salt, ≥ 600,000 iterations (configurable).
|
| 1110 |
+
|
| 1111 |
+
12-byte random IV per encryption.
|
| 1112 |
+
|
| 1113 |
+
Integrity: rely on AES-GCM auth tag; show clear success/failure on decrypt.
|
| 1114 |
+
|
| 1115 |
+
Raw key option: if user supplies a 32-byte random key (Base64/URL-safe), skip PBKDF2 and import directly for AES-GCM.
|
| 1116 |
+
|
| 1117 |
+
Never roll your own crypto; no third-party crypto libraries.
|
| 1118 |
+
|
| 1119 |
+
Package/Container Format
|
| 1120 |
+
|
| 1121 |
+
Support a compact, versioned container for both text and files. Use a Base64-armored string with a magic prefix, e.g. ENCv1: followed by Base64 of:
|
| 1122 |
+
|
| 1123 |
+
UTF-8 JSON header (first), then a newline \n,
|
| 1124 |
+
|
| 1125 |
+
then raw ciphertext bytes (including GCM tag).
|
| 1126 |
+
|
| 1127 |
+
Header JSON example:
|
| 1128 |
+
|
| 1129 |
+
{
|
| 1130 |
+
"v": 1,
|
| 1131 |
+
"alg": "AES-GCM",
|
| 1132 |
+
"kdf": {"name":"PBKDF2","hash":"SHA-256","iters":600000,"salt_b64":"..."},
|
| 1133 |
+
"iv_b64": "...",
|
| 1134 |
+
"keyType": "passphrase|raw",
|
| 1135 |
+
"created": "2025-09-06T00:00:00Z",
|
| 1136 |
+
"type": "text|file",
|
| 1137 |
+
"orig": {"name":"report.pdf","mime":"application/pdf","size":123456}
|
| 1138 |
+
}
|
| 1139 |
+
|
| 1140 |
+
|
| 1141 |
+
If using a raw key: "kdf": null, "keyType":"raw".
|
| 1142 |
+
|
| 1143 |
+
For text mode, omit or simplify "orig".
|
| 1144 |
+
|
| 1145 |
+
UI/UX Requirements
|
| 1146 |
+
|
| 1147 |
+
Tabs or segmented controls: Text and File modes.
|
| 1148 |
+
|
| 1149 |
+
Text tab: textarea input; Encrypt and Decrypt; output area with copy buttons.
|
| 1150 |
+
|
| 1151 |
+
File tab: drag-and-drop + picker; show filename/size; block > 10 MB with friendly error.
|
| 1152 |
+
|
| 1153 |
+
On Encrypt, download a .enc file containing the armored package.
|
| 1154 |
+
|
| 1155 |
+
On Decrypt, reconstruct original file (name/MIME from header) and download.
|
| 1156 |
+
|
| 1157 |
+
Key input section:
|
| 1158 |
+
|
| 1159 |
+
Field for passphrase or toggle to Generate secure key (32 random bytes → Base64/URL-safe).
|
| 1160 |
+
|
| 1161 |
+
Provide Copy and Download .key (text) for generated keys.
|
| 1162 |
+
|
| 1163 |
+
Clear indicators whether passphrase (PBKDF2) or raw key flow is active.
|
| 1164 |
+
|
| 1165 |
+
Status & Progress:
|
| 1166 |
+
|
| 1167 |
+
Progress bar/spinner for file operations; inline success/error toasts.
|
| 1168 |
+
|
| 1169 |
+
Modern dark UI (default):
|
| 1170 |
+
|
| 1171 |
+
Sleek, minimal, responsive layout with smooth micro-animations.
|
| 1172 |
+
|
| 1173 |
+
Include a light/dark toggle.
|
| 1174 |
+
|
| 1175 |
+
User Instructions (visible panel):
|
| 1176 |
+
|
| 1177 |
+
Step-by-step: choose Text/File → enter or generate key → Encrypt/Decrypt → manage/download results.
|
| 1178 |
+
|
| 1179 |
+
Prominent warning: “If you lose the key, you lose the data.”
|
| 1180 |
+
|
| 1181 |
+
Advanced/Technical Header (collapsible):
|
| 1182 |
+
|
| 1183 |
+
An accessible toggle button (aria-expanded, aria-controls).
|
| 1184 |
+
|
| 1185 |
+
On expand, show algorithm details, PBKDF2 iteration count, salt/IV lengths, format version, and a redacted example header from the last operation.
|
| 1186 |
+
|
| 1187 |
+
Privacy Note:
|
| 1188 |
+
|
| 1189 |
+
“All operations occur locally in your browser. No data is uploaded.”
|
| 1190 |
+
|
| 1191 |
+
Validation & Errors
|
| 1192 |
+
|
| 1193 |
+
Empty inputs, missing key, size limit exceeded → user-friendly inline errors.
|
| 1194 |
+
|
| 1195 |
+
Wrong key/corruption → “Decryption failed (wrong key or corrupted data).”
|
| 1196 |
+
|
| 1197 |
+
Unsupported package version → clear error referencing v.
|
| 1198 |
+
|
| 1199 |
+
Catch and display Web Crypto exceptions.
|
| 1200 |
+
|
| 1201 |
+
Implementation Notes (Single-File Constraints)
|
| 1202 |
+
|
| 1203 |
+
Use plain ES modules: a single <script type="module"> block in index.html.
|
| 1204 |
+
|
| 1205 |
+
Keep secrets in memory only; no LocalStorage/IndexedDB for keys or plaintext.
|
| 1206 |
+
|
| 1207 |
+
Provide helper functions for:
|
| 1208 |
+
|
| 1209 |
+
deriveKeyFromPassphrase(pass, salt, iters) → CryptoKey
|
| 1210 |
+
|
| 1211 |
+
importRawKey(base64) → CryptoKey
|
| 1212 |
+
|
| 1213 |
+
encryptText, decryptText
|
| 1214 |
+
|
| 1215 |
+
encryptFile, decryptFile (use Blob/ArrayBuffer, FileReader)
|
| 1216 |
+
|
| 1217 |
+
encodePackage(headerObj, cipherBytes) → "ENCv1:...base64..."
|
| 1218 |
+
|
| 1219 |
+
decodePackage(armored) → {header, cipherBytes}
|
| 1220 |
+
|
| 1221 |
+
Show a short example round-trip in the Advanced panel after first success (parameters only, no secrets).
|
| 1222 |
+
|
| 1223 |
+
Accessibility
|
| 1224 |
+
|
| 1225 |
+
Keyboard navigable controls, visible focus states.
|
| 1226 |
+
|
| 1227 |
+
Proper aria-* for collapsible advanced header, tab controls, and toasts/alerts.
|
| 1228 |
+
|
| 1229 |
+
Security Footnotes (display in Advanced)
|
| 1230 |
+
|
| 1231 |
+
Unique salt per KDF, unique IV per message.
|
| 1232 |
+
|
| 1233 |
+
Recommend long passphrases or random 32-byte keys.
|
| 1234 |
+
|
| 1235 |
+
Emphasize no recovery if key is lost.
|
| 1236 |
+
|
| 1237 |
+
Clarify threat model: protects at-rest data; does not protect against a compromised device.
|
| 1238 |
+
|
| 1239 |
+
Acceptance Criteria
|
| 1240 |
+
|
| 1241 |
+
Ships as one index.html file; opens and works from file://.
|
| 1242 |
+
|
| 1243 |
+
Encrypts/decrypts text and files ≤ 10 MB entirely offline.
|
| 1244 |
+
|
| 1245 |
+
Supports both PBKDF2 passphrase and raw 32-byte key flows.
|
| 1246 |
+
|
| 1247 |
+
Produces/consumes the specified ENCv1: Base64 format with JSON header.
|
| 1248 |
+
|
| 1249 |
+
Dark mode by default, responsive, accessible, with a collapsible technical header.
|
| 1250 |
+
|
| 1251 |
+
Clear errors for wrong key, bad format, or size over limit.
|
| 1252 |
+
|
| 1253 |
+
Now implement the entire app in a single self-contained index.html with inline CSS and JS (no external resources). Include helpful comments in code.
|
| 1254 |
+
add an animated background that moves in response to the mouse cursor
|
| 1255 |
+
Add user-instructions and an expendable header with more advanced information about the encryption that is used and how it works.
|
| 1256 |
+
Rename 'advanced settings' to 'Advanced Information' and make sure the information is accurate and complete. Additionaly, replace the animated background with another animated background that is more fitting for the webpages functionality.
|
| 1257 |
+
Rename 'advanced settings' to 'Advanced Information' and make sure the information is accurate and complete.
|
| 1258 |
+
Change the animated background so it matches the theme of cryptography
|