HerzaJ commited on
Commit
8d22540
·
verified ·
1 Parent(s): 699f310

Upload 12 files

Browse files
public/auth.html ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DashX - Authentication</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.css" rel="stylesheet">
9
+ <link href="styles.css" rel="stylesheet">
10
+ </head>
11
+ <body>
12
+ <nav class="navbar">
13
+ <div class="nav-container">
14
+ <div class="nav-brand">
15
+ <a href="/">
16
+ <h2><i class="fas fa-bolt"></i> DashX</h2>
17
+ </a>
18
+ </div>
19
+ </div>
20
+ </nav>
21
+
22
+ <div class="auth-container">
23
+ <div class="auth-card">
24
+ <div class="auth-tabs">
25
+ <button class="tab-btn active" onclick="switchTab('login')">
26
+ <i class="fas fa-sign-in-alt"></i> Login
27
+ </button>
28
+ <button class="tab-btn" onclick="switchTab('register')">
29
+ <i class="fas fa-user-plus"></i> Register
30
+ </button>
31
+ </div>
32
+
33
+ <form id="loginForm" class="auth-form">
34
+ <h2><i class="fas fa-sign-in-alt"></i> Login to DashX</h2>
35
+ <div class="form-group">
36
+ <label><i class="fas fa-envelope"></i> Email</label>
37
+ <input type="email" name="email" required placeholder="Enter your email">
38
+ </div>
39
+ <div class="form-group">
40
+ <label><i class="fas fa-lock"></i> Password</label>
41
+ <input type="password" name="password" required placeholder="Enter your password">
42
+ </div>
43
+ <button type="submit" class="btn btn-primary">
44
+ <i class="fas fa-sign-in-alt"></i> Login
45
+ </button>
46
+ </form>
47
+
48
+ <form id="registerForm" class="auth-form" style="display: none;">
49
+ <h2><i class="fas fa-user-plus"></i> Create Account</h2>
50
+ <div class="form-group">
51
+ <label><i class="fas fa-user"></i> Username</label>
52
+ <input type="text" name="username" required placeholder="Choose a username">
53
+ </div>
54
+ <div class="form-group">
55
+ <label><i class="fas fa-envelope"></i> Email</label>
56
+ <input type="email" name="email" required placeholder="Enter your email">
57
+ </div>
58
+ <div class="form-group">
59
+ <label><i class="fas fa-lock"></i> Password</label>
60
+ <input type="password" name="password" required placeholder="Choose a password">
61
+ </div>
62
+ <button type="submit" class="btn btn-primary">
63
+ <i class="fas fa-user-plus"></i> Register
64
+ </button>
65
+ </form>
66
+
67
+ <form id="adminForm" class="auth-form" style="display: none;">
68
+ <h2><i class="fas fa-user-shield"></i> Admin Login</h2>
69
+ <div class="form-group">
70
+ <label><i class="fas fa-user"></i> Username</label>
71
+ <input type="text" name="username" required placeholder="Admin username">
72
+ </div>
73
+ <div class="form-group">
74
+ <label><i class="fas fa-lock"></i> Password</label>
75
+ <input type="password" name="password" required placeholder="Admin password">
76
+ </div>
77
+ <button type="submit" class="btn btn-primary">
78
+
79
+ </button>
80
+ </form>
81
+
82
+ <form id="verifyForm" class="auth-form" style="display: none;">
83
+ <h2><i class="fas fa-envelope-open"></i> Verify Email</h2>
84
+ <p style="text-align: center; margin-bottom: 1.5rem; opacity: 0.8;">
85
+ Check your email for the verification code
86
+ </p>
87
+ <div class="form-group">
88
+ <label><i class="fas fa-envelope"></i> Email</label>
89
+ <input type="email" name="email" required placeholder="Your email address">
90
+ </div>
91
+ <div class="form-group">
92
+ <label><i class="fas fa-key"></i> Verification Code</label>
93
+ <input type="text" name="code" required placeholder="Enter 6-digit code" maxlength="6" style="text-transform: uppercase; letter-spacing: 2px;">
94
+ </div>
95
+ <button type="submit" class="btn btn-primary">
96
+ <i class="fas fa-check"></i> Verify
97
+ </button>
98
+ <div style="text-align: center; margin-top: 1rem;">
99
+ <button type="button" class="btn btn-secondary" onclick="switchTab('register')" style="font-size: 0.9rem;">
100
+ <i class="fas fa-arrow-left"></i> Back to Register
101
+ </button>
102
+ </div>
103
+ </form>
104
+ </div>
105
+ </div>
106
+ <script>
107
+ (function(){
108
+ function detectDevTools(){
109
+ const threshold = 160;
110
+ const widthThreshold = window.outerWidth - window.innerWidth > threshold;
111
+ const heightThreshold = window.outerHeight - window.innerHeight > threshold;
112
+ if(widthThreshold || heightThreshold) window.location.href = "/denied";
113
+ }
114
+
115
+ document.addEventListener("contextmenu", e => e.preventDefault());
116
+ document.onkeydown = function(e){
117
+ if(e.keyCode === 123 || (e.ctrlKey && e.shiftKey && ['I','C','J'].includes(e.key?.toUpperCase())) || (e.ctrlKey && e.key?.toUpperCase() === 'U')){
118
+ e.preventDefault();
119
+ window.location.href = "/denied";
120
+ }
121
+ };
122
+
123
+ setInterval(() => {
124
+ if(window.eruda) window.location.href = "/denied";
125
+ detectDevTools();
126
+ try{
127
+ console.profile();
128
+ console.profileEnd();
129
+ }catch(e){}
130
+ try{
131
+ if(console.clear.toString().length > 100) window.location.href = "/denied";
132
+ }catch(e){}
133
+ }, 1000);
134
+ })();
135
+ </script>
136
+
137
+
138
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.js"></script>
139
+ <script src="auth.js"></script>
140
+ </body>
141
+ </html>
public/auth.js ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let currentEmail = '';
2
+
3
+ document.addEventListener('DOMContentLoaded', function() {
4
+ const token = localStorage.getItem('dashx_token');
5
+ if (token) {
6
+ window.location.href = '/dashboard';
7
+ }
8
+
9
+ document.getElementById('loginForm').addEventListener('submit', handleLogin);
10
+ document.getElementById('registerForm').addEventListener('submit', handleRegister);
11
+ document.getElementById('adminForm').addEventListener('submit', handleAdminLogin);
12
+ document.getElementById('verifyForm').addEventListener('submit', handleVerify);
13
+ });
14
+
15
+ function switchTab(tab) {
16
+ document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
17
+ document.querySelectorAll('.auth-form').forEach(form => form.style.display = 'none');
18
+
19
+ event.target.classList.add('active');
20
+ document.getElementById(tab + 'Form').style.display = 'block';
21
+ }
22
+
23
+ async function handleLogin(e) {
24
+ e.preventDefault();
25
+ const formData = new FormData(e.target);
26
+ const data = Object.fromEntries(formData);
27
+
28
+ try {
29
+ const response = await fetch('/api/auth/login', {
30
+ method: 'POST',
31
+ headers: { 'Content-Type': 'application/json' },
32
+ body: JSON.stringify(data)
33
+ });
34
+
35
+ const result = await response.json();
36
+
37
+ if (result.success) {
38
+ localStorage.setItem('dashx_token', result.token);
39
+ localStorage.setItem('dashx_user', JSON.stringify(result.user));
40
+
41
+ Swal.fire({
42
+ title: "Login Successful!",
43
+ text: "Welcome back to DashX!",
44
+ icon: "success"
45
+ }).then(() => {
46
+ window.location.href = '/dashboard';
47
+ });
48
+ } else {
49
+ Swal.fire({
50
+ icon: "error",
51
+ title: "Login Failed",
52
+ text: result.error
53
+ });
54
+ }
55
+ } catch (error) {
56
+ Swal.fire({
57
+ icon: "error",
58
+ title: "Network Error",
59
+ text: "Please check your connection and try again"
60
+ });
61
+ }
62
+ }
63
+
64
+ async function handleRegister(e) {
65
+ e.preventDefault();
66
+ const formData = new FormData(e.target);
67
+ const data = Object.fromEntries(formData);
68
+
69
+ currentEmail = data.email;
70
+
71
+ try {
72
+ const response = await fetch('/api/auth/register', {
73
+ method: 'POST',
74
+ headers: { 'Content-Type': 'application/json' },
75
+ body: JSON.stringify(data)
76
+ });
77
+
78
+ const result = await response.json();
79
+
80
+ if (result.success) {
81
+ Swal.fire({
82
+ title: "Registration Successful!",
83
+ text: "Please check your email for verification code",
84
+ icon: "success"
85
+ });
86
+
87
+ document.getElementById('verifyForm').querySelector('input[name="email"]').value = currentEmail;
88
+ switchTabDirect('verify');
89
+ } else {
90
+ if (result.error.includes('Multiple accounts')) {
91
+ Swal.fire({
92
+ title: "Account Deleted!",
93
+ text: "You're account doesn't follow our terms of service, so we deleted this account!",
94
+ icon: "warning"
95
+ });
96
+ } else {
97
+ Swal.fire({
98
+ icon: "error",
99
+ title: "Registration Failed",
100
+ text: result.error,
101
+ footer: '<a href="#" onclick="showErrorDetails(\'' + result.error + '\')">Why do I have this issue?</a>'
102
+ });
103
+ }
104
+ }
105
+ } catch (error) {
106
+ Swal.fire({
107
+ icon: "error",
108
+ title: "Network Error",
109
+ text: "Please check your connection and try again",
110
+ footer: '<a href="#" onclick="showErrorDetails(\'Network connection failed\')">Why do I have this issue?</a>'
111
+ });
112
+ }
113
+ }
114
+
115
+ async function handleAdminLogin(e) {
116
+ e.preventDefault();
117
+ const formData = new FormData(e.target);
118
+ const data = Object.fromEntries(formData);
119
+
120
+ try {
121
+ const response = await fetch('/api/auth/admin-login', {
122
+ method: 'POST',
123
+ headers: { 'Content-Type': 'application/json' },
124
+ body: JSON.stringify(data)
125
+ });
126
+
127
+ const result = await response.json();
128
+
129
+ if (result.success) {
130
+ localStorage.setItem('dashx_token', result.token);
131
+ localStorage.setItem('dashx_user', JSON.stringify(result.user));
132
+
133
+ Swal.fire({
134
+ title: "Admin Login Successful!",
135
+ text: "Welcome to DashX Admin Panel!",
136
+ icon: "success"
137
+ }).then(() => {
138
+ window.location.href = '/dashboard';
139
+ });
140
+ } else {
141
+ Swal.fire({
142
+ icon: "error",
143
+ title: "Admin Login Failed",
144
+ text: result.error
145
+ });
146
+ }
147
+ } catch (error) {
148
+ Swal.fire({
149
+ icon: "error",
150
+ title: "Network Error",
151
+ text: "Please check your connection and try again"
152
+ });
153
+ }
154
+ }
155
+
156
+ async function handleVerify(e) {
157
+ e.preventDefault();
158
+ const formData = new FormData(e.target);
159
+ const data = Object.fromEntries(formData);
160
+
161
+ try {
162
+ const response = await fetch('/api/auth/verify', {
163
+ method: 'POST',
164
+ headers: { 'Content-Type': 'application/json' },
165
+ body: JSON.stringify(data)
166
+ });
167
+
168
+ const result = await response.json();
169
+
170
+ if (result.success) {
171
+ localStorage.setItem('dashx_token', result.token);
172
+ localStorage.setItem('dashx_user', JSON.stringify(result.user));
173
+
174
+ Swal.fire({
175
+ title: "Account Created Successfully!",
176
+ text: "Welcome to DashX!",
177
+ icon: "success"
178
+ }).then(() => {
179
+ window.location.href = '/dashboard';
180
+ });
181
+ } else {
182
+ Swal.fire({
183
+ icon: "error",
184
+ title: "Verification Failed",
185
+ text: result.error
186
+ });
187
+ }
188
+ } catch (error) {
189
+ Swal.fire({
190
+ icon: "error",
191
+ title: "Network Error",
192
+ text: "Please check your connection and try again"
193
+ });
194
+ }
195
+ }
196
+
197
+ function switchTabDirect(tab) {
198
+ document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
199
+ document.querySelectorAll('.auth-form').forEach(form => form.style.display = 'none');
200
+
201
+ document.getElementById(tab + 'Form').style.display = 'block';
202
+ }
203
+
204
+ function showErrorDetails(error) {
205
+ let details = '';
206
+
207
+ if (error.includes('already exists')) {
208
+ details = 'An account with this email or username already exists. Please use different credentials or login instead.';
209
+ } else if (error.includes('Network')) {
210
+ details = 'There was a problem connecting to our servers. Please check your internet connection and try again.';
211
+ } else if (error.includes('Multiple accounts')) {
212
+ details = 'Our system detected multiple accounts from the same IP address, which violates our terms of service.';
213
+ } else {
214
+ details = error;
215
+ }
216
+
217
+ Swal.fire({
218
+ title: 'Error Details',
219
+ text: details,
220
+ icon: 'info'
221
+ });
222
+ }
public/dashboard.html ADDED
@@ -0,0 +1,1407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DashX - Modern API Dashboard</title>
7
+ <meta name="description" content="DashX is a modern REST API dashboard platform that allows you to manage, monitor, and utilize various API tools with ease. Fully featured for developers with an intuitive interface and powerful analytics.">
8
+ <meta name="keywords" content="API Dashboard, REST API, DashX, API Management, Developer Tools, API Analytics">
9
+ <meta name="author" content="DashX Team">
10
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
11
+ <link rel="icon" type="image/webp" href="/icon.webp">
12
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.css" rel="stylesheet">
13
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
14
+ <link href="styles.css" rel="stylesheet">
15
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
16
+ <style>
17
+ i.fas, i.fa, i.far, i.fab, i.fal,
18
+ .fas, .fa, .far, .fab, .fal,
19
+ i[class*="fa-"] {
20
+ font-family: "Font Awesome 6 Free", "Font Awesome 6 Pro", "FontAwesome" !important;
21
+ font-weight: 900 !important;
22
+ font-style: normal !important;
23
+ font-variant: normal !important;
24
+ text-rendering: auto !important;
25
+ line-height: 1 !important;
26
+ -webkit-font-smoothing: antialiased !important;
27
+ -moz-osx-font-smoothing: grayscale !important;
28
+ display: inline-block !important;
29
+ }
30
+
31
+ .stat-item {
32
+ text-align: center;
33
+ padding: 1.5rem;
34
+ background: rgba(255, 255, 255, 0.05);
35
+ border-radius: 12px;
36
+ border: 1px solid rgba(255, 255, 255, 0.1);
37
+ }
38
+
39
+ .stat-item .stat-value {
40
+ display: block;
41
+ font-size: 1.8rem;
42
+ font-weight: 700;
43
+ color: rgba(133, 48, 48, 0.9);
44
+ margin-bottom: 0.5rem;
45
+ }
46
+
47
+ .stat-item .stat-label {
48
+ display: block;
49
+ font-size: 0.9rem;
50
+ color: rgba(255, 255, 255, 0.7);
51
+ }
52
+
53
+ .stat-icon {
54
+ font-size: 3rem !important;
55
+ color: rgba(255, 168, 168, 0.9) !important;
56
+ min-width: 80px !important;
57
+ text-align: center !important;
58
+ display: flex !important;
59
+ align-items: center !important;
60
+ justify-content: center !important;
61
+ }
62
+
63
+ .stat-icon i {
64
+ font-size: 3rem !important;
65
+ display: block !important;
66
+ }
67
+
68
+ .stat-info {
69
+ flex: 1;
70
+ }
71
+
72
+ .stat-number {
73
+ font-size: 2rem;
74
+ font-weight: 700;
75
+ color: rgba(255, 255, 255, 0.9);
76
+ margin-bottom: 0.25rem;
77
+ word-break: break-all;
78
+ }
79
+
80
+ .stat-label {
81
+ font-size: 0.9rem;
82
+ color: rgba(255, 255, 255, 0.7);
83
+ }
84
+
85
+ .section h2 i {
86
+ color: #e74c3c !important;
87
+ }
88
+
89
+ .navbar {
90
+ background: rgba(44, 62, 80, 0.95) !important;
91
+ backdrop-filter: blur(10px);
92
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
93
+ box-shadow: 0 2px 20px rgba(0, 0, 0, 0.2);
94
+ }
95
+
96
+ .navbar-brand {
97
+ font-size: 1.5rem;
98
+ font-weight: 700;
99
+ color: #fff !important;
100
+ }
101
+
102
+ .navbar-brand i {
103
+ color: #e74c3c;
104
+ font-size: 1.8rem;
105
+ margin-right: 0.5rem;
106
+ }
107
+
108
+ .nav-link {
109
+ color: #ecf0f1 !important;
110
+ font-weight: 500;
111
+ transition: all 0.3s ease;
112
+ padding: 0.5rem 1rem !important;
113
+ border-radius: 8px;
114
+ margin: 0 0.25rem;
115
+ }
116
+
117
+ .nav-link:hover {
118
+ background: rgba(255, 255, 255, 0.1);
119
+ transform: translateY(-1px);
120
+ }
121
+
122
+ .nav-link.text-danger {
123
+ color: #e74c3c !important;
124
+ }
125
+
126
+ .nav-link.text-danger:hover {
127
+ background: rgba(231, 76, 60, 0.1);
128
+ color: #ff6b6b !important;
129
+ }
130
+
131
+ .glassmorphism {
132
+ background: rgba(255, 255, 255, 0.1);
133
+ backdrop-filter: blur(10px);
134
+ -webkit-backdrop-filter: blur(10px);
135
+ border: 1px solid rgba(255, 255, 255, 0.2);
136
+ border-radius: 16px;
137
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
138
+ }
139
+
140
+ .reset-timer-card {
141
+ margin-top: 2rem;
142
+ padding: 1.5rem;
143
+ border-radius: 12px;
144
+ background: rgba(255, 255, 255, 0.05);
145
+ backdrop-filter: blur(10px);
146
+ border: 1px solid rgba(255, 255, 255, 0.1);
147
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
148
+ }
149
+
150
+ .timer-header {
151
+ display: flex;
152
+ align-items: center;
153
+ gap: 1rem;
154
+ margin-bottom: 1rem;
155
+ }
156
+
157
+ .timer-header i {
158
+ font-size: 1.5rem;
159
+ color: #853030;
160
+ }
161
+
162
+ .timer-header h3 {
163
+ margin: 0;
164
+ font-size: 1.2rem;
165
+ color: rgba(255, 255, 255, 0.9);
166
+ }
167
+
168
+ .timer-header p {
169
+ margin: 0;
170
+ opacity: 0.7;
171
+ font-size: 0.9rem;
172
+ }
173
+
174
+ .countdown-display {
175
+ text-align: center;
176
+ padding: 2rem 1rem;
177
+ }
178
+
179
+ .countdown-time {
180
+ font-size: 3rem;
181
+ font-weight: bold;
182
+ color: #853030;
183
+ font-family: 'Courier New', monospace;
184
+ letter-spacing: 0.1em;
185
+ text-shadow: 0 0 20px rgba(133, 48, 48, 0.3);
186
+ }
187
+
188
+ .countdown-label {
189
+ margin-top: 0.5rem;
190
+ opacity: 0.6;
191
+ font-size: 0.9rem;
192
+ color: rgba(255, 255, 255, 0.8);
193
+ }
194
+
195
+ .reset-progress-container {
196
+ width: 100%;
197
+ height: 8px;
198
+ background: rgba(255, 255, 255, 0.1);
199
+ border-radius: 4px;
200
+ overflow: hidden;
201
+ margin-top: 1rem;
202
+ }
203
+
204
+ .reset-progress {
205
+ height: 100%;
206
+ background: linear-gradient(90deg, #853030, #ff6b6b);
207
+ transition: width 1s linear;
208
+ width: 0%;
209
+ box-shadow: 0 0 10px rgba(133, 48, 48, 0.5);
210
+ }
211
+
212
+ .reset-info {
213
+ margin-top: 1rem;
214
+ padding: 1rem;
215
+ background: rgba(255, 255, 255, 0.05);
216
+ border-radius: 8px;
217
+ display: flex;
218
+ justify-content: space-between;
219
+ align-items: center;
220
+ }
221
+
222
+ .reset-info i {
223
+ color: #853030;
224
+ margin-right: 0.5rem;
225
+ }
226
+
227
+ .reset-info span {
228
+ font-size: 0.9rem;
229
+ color: rgba(255, 255, 255, 0.8);
230
+ }
231
+
232
+ .reset-info div:last-child {
233
+ font-weight: bold;
234
+ color: #853030;
235
+ }
236
+
237
+ @keyframes pulse {
238
+ 0%, 100% { opacity: 1; }
239
+ 50% { opacity: 0.7; }
240
+ }
241
+
242
+ .reset-countdown {
243
+ animation: pulse 2s ease-in-out infinite;
244
+ }
245
+
246
+ .usage-overview {
247
+ display: grid;
248
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
249
+ gap: 1.5rem;
250
+ margin-top: 1rem;
251
+ }
252
+
253
+ .usage-section {
254
+ background: rgba(255, 255, 255, 0.05);
255
+ backdrop-filter: blur(10px);
256
+ -webkit-backdrop-filter: blur(10px);
257
+ border: 1px solid rgba(255, 255, 255, 0.1);
258
+ padding: 1.5rem;
259
+ border-radius: 16px;
260
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
261
+ transition: all 0.3s ease;
262
+ }
263
+
264
+ .usage-section:hover {
265
+ background: rgba(255, 255, 255, 0.08);
266
+ transform: translateY(-2px);
267
+ box-shadow: 0 12px 40px 0 rgba(31, 38, 135, 0.3);
268
+ }
269
+
270
+ .usage-section h4 {
271
+ margin-bottom: 1rem;
272
+ color: rgba(255, 255, 255, 0.9);
273
+ font-size: 1.1rem;
274
+ font-weight: 600;
275
+ display: flex;
276
+ align-items: center;
277
+ gap: 0.5rem;
278
+ }
279
+
280
+ .usage-section h4 i {
281
+ color: rgba(133, 48, 48, 0.8);
282
+ }
283
+
284
+ .endpoint-list, .ip-list {
285
+ display: flex;
286
+ flex-direction: column;
287
+ gap: 0.5rem;
288
+ }
289
+
290
+ .endpoint-item, .ip-item {
291
+ display: flex;
292
+ justify-content: space-between;
293
+ align-items: center;
294
+ padding: 0.75rem;
295
+ background: rgba(255, 255, 255, 0.08);
296
+ backdrop-filter: blur(5px);
297
+ border-radius: 8px;
298
+ border: 1px solid rgba(255, 255, 255, 0.1);
299
+ transition: all 0.3s ease;
300
+ }
301
+
302
+ .endpoint-item:hover, .ip-item:hover {
303
+ background: rgba(255, 255, 255, 0.12);
304
+ transform: translateX(4px);
305
+ }
306
+
307
+ .endpoint-name, .ip-address {
308
+ font-family: 'Courier New', monospace;
309
+ font-weight: 500;
310
+ color: rgba(255, 255, 255, 0.8);
311
+ font-size: 0.9rem;
312
+ }
313
+
314
+ .endpoint-count, .ip-count {
315
+ color: rgba(133, 48, 48, 0.9);
316
+ font-weight: 600;
317
+ background: rgba(133, 48, 48, 0.1);
318
+ padding: 0.25rem 0.5rem;
319
+ border-radius: 12px;
320
+ font-size: 0.8rem;
321
+ }
322
+
323
+ .ip-time {
324
+ font-size: 0.75rem;
325
+ color: rgba(255, 255, 255, 0.6);
326
+ font-style: italic;
327
+ }
328
+
329
+ .daily-usage {
330
+ display: flex;
331
+ flex-direction: column;
332
+ gap: 0.75rem;
333
+ }
334
+
335
+ .usage-day {
336
+ display: grid;
337
+ grid-template-columns: 70px 1fr 50px;
338
+ align-items: center;
339
+ gap: 1rem;
340
+ padding: 0.5rem;
341
+ border-radius: 8px;
342
+ transition: all 0.3s ease;
343
+ }
344
+
345
+ .usage-day:hover {
346
+ background: rgba(255, 255, 255, 0.05);
347
+ }
348
+
349
+ .usage-date {
350
+ font-size: 0.85rem;
351
+ font-weight: 500;
352
+ color: rgba(255, 255, 255, 0.8);
353
+ }
354
+
355
+ .usage-bar-container {
356
+ background: rgba(255, 255, 255, 0.1);
357
+ border-radius: 10px;
358
+ height: 8px;
359
+ overflow: hidden;
360
+ position: relative;
361
+ }
362
+
363
+ .usage-bar {
364
+ height: 100%;
365
+ background: linear-gradient(90deg, rgba(133, 48, 48, 0.8), rgba(166, 69, 69, 0.9));
366
+ border-radius: 10px;
367
+ transition: width 0.6s ease;
368
+ position: relative;
369
+ }
370
+
371
+ .usage-bar::after {
372
+ content: '';
373
+ position: absolute;
374
+ top: 0;
375
+ left: 0;
376
+ right: 0;
377
+ bottom: 0;
378
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
379
+ animation: shimmer 2s infinite;
380
+ }
381
+
382
+ @keyframes shimmer {
383
+ 0% { transform: translateX(-100%); }
384
+ 100% { transform: translateX(100%); }
385
+ }
386
+
387
+ .usage-count {
388
+ font-size: 0.85rem;
389
+ font-weight: 600;
390
+ color: rgba(133, 48, 48, 0.9);
391
+ text-align: center;
392
+ }
393
+
394
+ .no-data {
395
+ text-align: center;
396
+ padding: 2rem;
397
+ color: rgba(255, 255, 255, 0.5);
398
+ font-style: italic;
399
+ }
400
+
401
+ .no-data-state, .error-state {
402
+ text-align: center;
403
+ padding: 3rem 2rem;
404
+ color: rgba(255, 255, 255, 0.6);
405
+ }
406
+
407
+ .error-state i {
408
+ color: #ff6b6b;
409
+ font-size: 2.5rem;
410
+ margin-bottom: 1rem;
411
+ }
412
+
413
+ .search-container {
414
+ margin-bottom: 2rem;
415
+ position: relative;
416
+ }
417
+
418
+ .search-input {
419
+ width: 100%;
420
+ padding: 1rem 1rem 1rem 3rem;
421
+ border: 1px solid rgba(255, 255, 255, 0.2);
422
+ border-radius: 16px;
423
+ background: rgba(255, 255, 255, 0.05);
424
+ backdrop-filter: blur(10px);
425
+ font-size: 1rem;
426
+ transition: all 0.3s ease;
427
+ color: rgba(255, 255, 255, 0.9);
428
+ }
429
+
430
+ .search-input::placeholder {
431
+ color: rgba(255, 255, 255, 0.5);
432
+ }
433
+
434
+ .search-input:focus {
435
+ outline: none;
436
+ border-color: rgba(133, 48, 48, 0.8);
437
+ background: rgba(255, 255, 255, 0.08);
438
+ box-shadow: 0 0 0 3px rgba(133, 48, 48, 0.1);
439
+ }
440
+
441
+ .search-icon {
442
+ position: absolute;
443
+ left: 1rem;
444
+ top: 50%;
445
+ transform: translateY(-50%);
446
+ color: rgba(133, 48, 48, 0.8);
447
+ font-size: 1.2rem;
448
+ }
449
+
450
+ .plugin-card {
451
+ background: rgba(255, 255, 255, 0.05);
452
+ backdrop-filter: blur(10px);
453
+ -webkit-backdrop-filter: blur(10px);
454
+ border: 1px solid rgba(255, 255, 255, 0.1);
455
+ border-radius: 16px;
456
+ overflow: hidden;
457
+ transition: all 0.3s ease;
458
+ margin-bottom: 1rem;
459
+ }
460
+
461
+ .plugin-card:hover {
462
+ background: rgba(255, 255, 255, 0.08);
463
+ transform: translateY(-2px);
464
+ box-shadow: 0 12px 40px 0 rgba(31, 38, 135, 0.3);
465
+ }
466
+
467
+ .plugin-info {
468
+ margin-top: 0.5rem;
469
+ font-size: 0.85rem;
470
+ }
471
+
472
+ .limit-info {
473
+ background: rgba(133, 48, 48, 0.1);
474
+ color: #853030;
475
+ padding: 0.25rem 0.5rem;
476
+ border-radius: 4px;
477
+ font-weight: 500;
478
+ }
479
+
480
+ .user-item {
481
+ background: rgba(255, 255, 255, 0.05);
482
+ backdrop-filter: blur(10px);
483
+ -webkit-backdrop-filter: blur(10px);
484
+ border: 1px solid rgba(255, 255, 255, 0.1);
485
+ padding: 1.5rem;
486
+ border-radius: 16px;
487
+ margin-bottom: 1rem;
488
+ display: flex;
489
+ justify-content: space-between;
490
+ align-items: flex-start;
491
+ transition: all 0.3s ease;
492
+ }
493
+
494
+ .user-item:hover {
495
+ background: rgba(255, 255, 255, 0.08);
496
+ transform: translateY(-2px);
497
+ box-shadow: 0 12px 40px 0 rgba(31, 38, 135, 0.3);
498
+ }
499
+
500
+ .user-item.temp-banned {
501
+ border-left: 4px solid rgba(255, 193, 7, 0.8);
502
+ background: rgba(255, 193, 7, 0.05);
503
+ }
504
+
505
+ .user-item.banned {
506
+ border-left: 4px solid rgba(220, 53, 69, 0.8);
507
+ background: rgba(220, 53, 69, 0.05);
508
+ }
509
+
510
+ .user-info {
511
+ flex: 1;
512
+ }
513
+
514
+ .user-name {
515
+ font-size: 1.2rem;
516
+ font-weight: 600;
517
+ color: rgba(255, 255, 255, 0.9);
518
+ margin-bottom: 0.5rem;
519
+ }
520
+
521
+ .user-details {
522
+ display: flex;
523
+ flex-wrap: wrap;
524
+ gap: 0.75rem;
525
+ margin-bottom: 0.75rem;
526
+ }
527
+
528
+ .user-email {
529
+ color: rgba(255, 255, 255, 0.7);
530
+ font-size: 0.9rem;
531
+ }
532
+
533
+ .user-role {
534
+ background: rgba(255, 255, 255, 0.1);
535
+ backdrop-filter: blur(5px);
536
+ color: rgba(255, 255, 255, 0.8);
537
+ padding: 0.25rem 0.75rem;
538
+ border-radius: 12px;
539
+ font-size: 0.8rem;
540
+ font-weight: 500;
541
+ border: 1px solid rgba(255, 255, 255, 0.1);
542
+ }
543
+
544
+ .premium-badge {
545
+ background: linear-gradient(45deg, rgba(255, 215, 0, 0.3), rgba(255, 237, 78, 0.3));
546
+ backdrop-filter: blur(5px);
547
+ color: rgba(255, 215, 0, 1);
548
+ padding: 0.25rem 0.75rem;
549
+ border-radius: 12px;
550
+ font-size: 0.8rem;
551
+ font-weight: 600;
552
+ border: 1px solid rgba(255, 215, 0, 0.3);
553
+ box-shadow: 0 0 10px rgba(255, 215, 0, 0.2);
554
+ }
555
+
556
+ .user-stats {
557
+ display: flex;
558
+ flex-wrap: wrap;
559
+ gap: 1rem;
560
+ font-size: 0.85rem;
561
+ color: rgba(255, 255, 255, 0.7);
562
+ margin-bottom: 0.75rem;
563
+ }
564
+
565
+ .ban-info {
566
+ background: rgba(255, 193, 7, 0.1);
567
+ backdrop-filter: blur(5px);
568
+ border: 1px solid rgba(255, 193, 7, 0.3);
569
+ padding: 0.75rem;
570
+ border-radius: 8px;
571
+ font-size: 0.85rem;
572
+ color: rgba(255, 193, 7, 0.9);
573
+ margin-top: 0.5rem;
574
+ }
575
+
576
+ .user-actions {
577
+ display: flex;
578
+ gap: 0.5rem;
579
+ flex-wrap: wrap;
580
+ }
581
+
582
+ .pagination-controls {
583
+ display: flex;
584
+ justify-content: space-between;
585
+ align-items: center;
586
+ padding: 1rem;
587
+ margin-top: 1rem;
588
+ background: rgba(255, 255, 255, 0.05);
589
+ backdrop-filter: blur(10px);
590
+ border-radius: 12px;
591
+ border: 1px solid rgba(255, 255, 255, 0.1);
592
+ }
593
+
594
+ .page-info {
595
+ color: rgba(255, 255, 255, 0.8);
596
+ font-weight: 500;
597
+ }
598
+
599
+ .users-pagination-info {
600
+ color: rgba(255, 255, 255, 0.6);
601
+ font-size: 0.9rem;
602
+ margin-bottom: 1rem;
603
+ text-align: center;
604
+ padding: 0.5rem;
605
+ background: rgba(255, 255, 255, 0.05);
606
+ border-radius: 8px;
607
+ backdrop-filter: blur(5px);
608
+ }
609
+
610
+ .btn {
611
+ padding: 0.5rem 1rem;
612
+ border: none;
613
+ border-radius: 8px;
614
+ font-weight: 500;
615
+ cursor: pointer;
616
+ transition: all 0.3s ease;
617
+ text-decoration: none;
618
+ display: inline-flex;
619
+ align-items: center;
620
+ gap: 0.5rem;
621
+ font-size: 0.9rem;
622
+ backdrop-filter: blur(10px);
623
+ border: 1px solid rgba(255, 255, 255, 0.1);
624
+ }
625
+
626
+ .btn:disabled {
627
+ opacity: 0.5;
628
+ cursor: not-allowed;
629
+ transform: none !important;
630
+ }
631
+
632
+ .btn-primary {
633
+ background: rgba(133, 48, 48, 0.8);
634
+ color: white;
635
+ border: 1px solid rgba(133, 48, 48, 0.3);
636
+ }
637
+
638
+ .btn-primary:hover:not(:disabled) {
639
+ background: rgba(133, 48, 48, 1);
640
+ transform: translateY(-1px);
641
+ box-shadow: 0 4px 12px rgba(133, 48, 48, 0.3);
642
+ }
643
+
644
+ .btn-secondary {
645
+ background: rgba(108, 117, 125, 0.8);
646
+ color: white;
647
+ border: 1px solid rgba(108, 117, 125, 0.3);
648
+ }
649
+
650
+ .btn-secondary:hover:not(:disabled) {
651
+ background: rgba(108, 117, 125, 1);
652
+ transform: translateY(-1px);
653
+ }
654
+
655
+ .btn-warning {
656
+ background: rgba(255, 193, 7, 0.8);
657
+ color: rgba(133, 100, 4, 1);
658
+ border: 1px solid rgba(255, 193, 7, 0.3);
659
+ }
660
+
661
+ .btn-warning:hover:not(:disabled) {
662
+ background: rgba(255, 193, 7, 1);
663
+ transform: translateY(-1px);
664
+ box-shadow: 0 4px 12px rgba(255, 193, 7, 0.3);
665
+ }
666
+
667
+ .btn-success {
668
+ background: rgba(40, 167, 69, 0.8);
669
+ color: white;
670
+ border: 1px solid rgba(40, 167, 69, 0.3);
671
+ }
672
+
673
+ .btn-success:hover:not(:disabled) {
674
+ background: rgba(40, 167, 69, 1);
675
+ transform: translateY(-1px);
676
+ box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
677
+ }
678
+
679
+ .btn-danger {
680
+ background: rgba(220, 53, 69, 0.8);
681
+ color: white;
682
+ border: 1px solid rgba(220, 53, 69, 0.3);
683
+ }
684
+
685
+ .btn-danger:hover:not(:disabled) {
686
+ background: rgba(220, 53, 69, 1);
687
+ transform: translateY(-1px);
688
+ box-shadow: 0 4px 12px rgba(220, 53, 69, 0.3);
689
+ }
690
+
691
+ .no-users-state {
692
+ text-align: center;
693
+ padding: 3rem;
694
+ color: rgba(255, 255, 255, 0.6);
695
+ }
696
+
697
+ .admin-card {
698
+ background: rgba(255, 255, 255, 0.05);
699
+ backdrop-filter: blur(10px);
700
+ -webkit-backdrop-filter: blur(10px);
701
+ border: 1px solid rgba(255, 255, 255, 0.1);
702
+ border-radius: 16px;
703
+ padding: 2rem;
704
+ margin-bottom: 2rem;
705
+ transition: all 0.3s ease;
706
+ }
707
+
708
+ .admin-card:hover {
709
+ background: rgba(255, 255, 255, 0.08);
710
+ transform: translateY(-2px);
711
+ box-shadow: 0 12px 40px 0 rgba(31, 38, 135, 0.3);
712
+ }
713
+
714
+ .admin-card h3 {
715
+ color: rgba(255, 255, 255, 0.9);
716
+ margin-bottom: 1.5rem;
717
+ display: flex;
718
+ align-items: center;
719
+ gap: 0.5rem;
720
+ }
721
+
722
+ .admin-card h3 i {
723
+ color: rgba(133, 48, 48, 0.8);
724
+ }
725
+
726
+ .stats-cards {
727
+ display: grid;
728
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
729
+ gap: 1.5rem;
730
+ margin-bottom: 2rem;
731
+ }
732
+
733
+ .stat-card {
734
+ background: rgba(255, 255, 255, 0.05);
735
+ backdrop-filter: blur(10px);
736
+ -webkit-backdrop-filter: blur(10px);
737
+ border: 1px solid rgba(255, 255, 255, 0.1);
738
+ padding: 2rem;
739
+ border-radius: 16px;
740
+ display: flex;
741
+ align-items: center;
742
+ gap: 1rem;
743
+ transition: all 0.3s ease;
744
+ }
745
+
746
+ .stat-card:hover {
747
+ background: rgba(255, 255, 255, 0.08);
748
+ transform: translateY(-3px);
749
+ box-shadow: 0 15px 50px 0 rgba(31, 38, 135, 0.4);
750
+ }
751
+
752
+ .form-row {
753
+ display: grid;
754
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
755
+ gap: 1rem;
756
+ margin-bottom: 1.5rem;
757
+ }
758
+
759
+ .form-group {
760
+ display: flex;
761
+ flex-direction: column;
762
+ }
763
+
764
+ .form-group label {
765
+ color: rgba(255, 255, 255, 0.9);
766
+ margin-bottom: 0.5rem;
767
+ font-weight: 500;
768
+ font-size: 0.9rem;
769
+ }
770
+
771
+ .form-group .required {
772
+ color: #ff6b6b;
773
+ margin-left: 0.25rem;
774
+ }
775
+
776
+ .form-group input,
777
+ .form-group select {
778
+ padding: 0.75rem;
779
+ border: 1px solid rgba(255, 255, 255, 0.2);
780
+ border-radius: 8px;
781
+ background: rgba(255, 255, 255, 0.05);
782
+ color: rgba(255, 255, 255, 0.9);
783
+ font-size: 0.95rem;
784
+ transition: all 0.3s ease;
785
+ }
786
+
787
+ .form-group input:focus,
788
+ .form-group select:focus {
789
+ outline: none;
790
+ border-color: rgba(133, 48, 48, 0.8);
791
+ background: rgba(255, 255, 255, 0.08);
792
+ box-shadow: 0 0 0 3px rgba(133, 48, 48, 0.1);
793
+ }
794
+
795
+ .form-group input::placeholder {
796
+ color: rgba(255, 255, 255, 0.4);
797
+ }
798
+
799
+ .form-group small {
800
+ color: rgba(255, 255, 255, 0.5);
801
+ font-size: 0.8rem;
802
+ margin-top: 0.25rem;
803
+ }
804
+
805
+ @media (max-width: 768px) {
806
+ .countdown-time {
807
+ font-size: 2rem;
808
+ }
809
+
810
+ .reset-timer-card {
811
+ padding: 1rem;
812
+ }
813
+
814
+ .usage-overview {
815
+ grid-template-columns: 1fr;
816
+ }
817
+
818
+ .usage-day {
819
+ grid-template-columns: 60px 1fr 40px;
820
+ gap: 0.5rem;
821
+ }
822
+
823
+ .user-item {
824
+ flex-direction: column;
825
+ gap: 1rem;
826
+ }
827
+
828
+ .user-actions {
829
+ width: 100%;
830
+ justify-content: flex-end;
831
+ }
832
+
833
+ .pagination-controls {
834
+ flex-direction: column;
835
+ gap: 1rem;
836
+ }
837
+
838
+ .dashboard-container {
839
+ flex-direction: column;
840
+ }
841
+
842
+ .sidebar {
843
+ width: 100%;
844
+ position: static;
845
+ height: auto;
846
+ }
847
+
848
+ .form-row {
849
+ grid-template-columns: 1fr;
850
+ }
851
+
852
+ .stats-cards {
853
+ grid-template-columns: 1fr;
854
+ }
855
+ }
856
+ </style>
857
+ </head>
858
+ <body>
859
+ <nav class="navbar navbar-expand-lg navbar-dark">
860
+ <div class="container">
861
+ <a class="navbar-brand" href="/">
862
+ <i class="fas fa-bolt"></i> DashX
863
+ </a>
864
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
865
+ <span class="navbar-toggler-icon"></span>
866
+ </button>
867
+ <div class="collapse navbar-collapse" id="navbarNav">
868
+ <ul class="navbar-nav ms-auto">
869
+ <li class="nav-item">
870
+ <a class="nav-link" href="/profile" onclick="goToProfile()">
871
+ <i class="fas fa-user"></i> Profile
872
+ </a>
873
+ </li>
874
+ <li class="nav-item">
875
+ <a class="nav-link text-danger" href="#" onclick="logout()">
876
+ <i class="fas fa-sign-out-alt"></i> Logout
877
+ </a>
878
+ </li>
879
+ </ul>
880
+ </div>
881
+ </div>
882
+ </nav>
883
+
884
+ <div class="dashboard-container">
885
+ <div class="sidebar">
886
+ <div class="sidebar-menu">
887
+ <a href="#overview" class="menu-item active" onclick="showSection('overview')">
888
+ <i class="fas fa-chart-line"></i> Overview
889
+ </a>
890
+ <a href="#api-stats" class="menu-item" onclick="showSection('api-stats')">
891
+ <i class="fas fa-chart-area"></i> API Stats
892
+ </a>
893
+ <a href="#plugins" class="menu-item" onclick="showSection('plugins')">
894
+ <i class="fas fa-plug"></i> API Plugins
895
+ </a>
896
+ <a href="#server-stats" class="menu-item" onclick="showSection('server-stats')">
897
+ <i class="fas fa-server"></i> Server Stats
898
+ </a>
899
+ <a href="#events" class="menu-item" onclick="showSection('events')">
900
+ <i class="fas fa-calendar"></i> Events
901
+ </a>
902
+ <a href="#settings" class="menu-item" onclick="showSection('settings')">
903
+ <i class="fas fa-cog"></i> Settings
904
+ </a>
905
+ <div id="adminMenu" style="display: none;">
906
+ <a href="#management" class="menu-item" onclick="showSection('management')">
907
+ <i class="fas fa-users-cog"></i> Management
908
+ </a>
909
+ </div>
910
+ </div>
911
+ </div>
912
+
913
+ <div class="main-content">
914
+ <div id="overview" class="section active">
915
+ <h2><i class="fas fa-tachometer-alt"></i> Dashboard Overview</h2>
916
+ <div class="stats-cards">
917
+ <div class="stat-card">
918
+ <div class="stat-icon">
919
+ <img src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/key.svg" alt="key" style="width: 3rem; height: 3rem; filter: invert(78%) sepia(45%) saturate(548%) hue-rotate(314deg) brightness(101%) contrast(101%);">
920
+ </div>
921
+ <div class="stat-info">
922
+ <div class="stat-number" id="userApiKey">Loading...</div>
923
+ <div class="stat-label">API Key</div>
924
+ </div>
925
+ </div>
926
+ <div class="stat-card">
927
+ <div class="stat-icon">
928
+ <img src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/chart-pie.svg" alt="chart" style="width: 3rem; height: 3rem; filter: invert(78%) sepia(45%) saturate(548%) hue-rotate(314deg) brightness(101%) contrast(101%);">
929
+ </div>
930
+ <div class="stat-info">
931
+ <div class="stat-number" id="userRequests">0</div>
932
+ <div class="stat-label">Total Requests</div>
933
+ </div>
934
+ </div>
935
+ <div class="stat-card">
936
+ <div class="stat-icon">
937
+ <img src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/cloud.svg" alt="cloud" style="width: 3rem; height: 3rem; filter: invert(78%) sepia(45%) saturate(548%) hue-rotate(314deg) brightness(101%) contrast(101%);">
938
+ </div>
939
+ <div class="stat-info">
940
+ <div class="stat-number" id="userRequestsToday">0</div>
941
+ <div class="stat-label">Today's Requests</div>
942
+ </div>
943
+ </div>
944
+ <div class="stat-card">
945
+ <div class="stat-icon">
946
+ <img src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/gauge-high.svg" alt="gauge" style="width: 3rem; height: 3rem; filter: invert(78%) sepia(45%) saturate(548%) hue-rotate(314deg) brightness(101%) contrast(101%);">
947
+ </div>
948
+ <div class="stat-info">
949
+ <div class="stat-number" id="userLimit">30</div>
950
+ <div class="stat-label">Daily Limit</div>
951
+ </div>
952
+ </div>
953
+ <div class="stat-card">
954
+ <div class="stat-icon">
955
+ <img src="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/svgs/solid/battery-three-quarters.svg" alt="battery" style="width: 3rem; height: 3rem; filter: invert(78%) sepia(45%) saturate(548%) hue-rotate(314deg) brightness(101%) contrast(101%);">
956
+ </div>
957
+ <div class="stat-info">
958
+ <div class="stat-number" id="userLimitToday">30</div>
959
+ <div class="stat-label">Remaining Limit (Personal)</div>
960
+ </div>
961
+ </div>
962
+ </div>
963
+
964
+ <div class="reset-timer-card glassmorphism">
965
+ <div class="timer-header">
966
+ <i class="fas fa-clock"></i>
967
+ <div>
968
+ <h3>Next Reset</h3>
969
+ <p>Daily limit resets at 00:00</p>
970
+ </div>
971
+ </div>
972
+
973
+ <div class="countdown-display">
974
+ <div class="countdown-time">
975
+ <span class="reset-countdown">00:00:00</span>
976
+ </div>
977
+ <div class="countdown-label">
978
+ Hours : Minutes : Seconds
979
+ </div>
980
+ </div>
981
+
982
+ <div class="reset-progress-container">
983
+ <div class="reset-progress"></div>
984
+ </div>
985
+
986
+ <div class="reset-info">
987
+ <div>
988
+ <i class="fas fa-info-circle"></i>
989
+ <span>Your limit will be restored to maximum</span>
990
+ </div>
991
+ <div>
992
+ <i class="fas fa-sync-alt"></i>
993
+ </div>
994
+ </div>
995
+ </div>
996
+
997
+ <div class="usage-overview">
998
+ <div class="usage-section">
999
+ <h4><i class="fas fa-chart-bar"></i> API Usage Overview</h4>
1000
+ <div class="endpoint-list">
1001
+ <div class="endpoint-item">
1002
+ <span class="endpoint-name">Loading...</span>
1003
+ <span class="endpoint-count">0 requests</span>
1004
+ </div>
1005
+ </div>
1006
+ </div>
1007
+
1008
+
1009
+
1010
+ <div class="usage-section">
1011
+ <h4><i class="fas fa-calendar-alt"></i> Daily Usage (Last 7 Days)</h4>
1012
+ <div class="daily-usage">
1013
+ <div class="usage-day">
1014
+ <span class="usage-date">Loading...</span>
1015
+ <div class="usage-bar-container">
1016
+ <div class="usage-bar" style="width: 0%;"></div>
1017
+ </div>
1018
+ <span class="usage-count">0</span>
1019
+ </div>
1020
+ </div>
1021
+ </div>
1022
+
1023
+ <div class="usage-section">
1024
+ <h4><i class="fas fa-network-wired"></i> Recent IP Addresses</h4>
1025
+ <div class="ip-list">
1026
+ <div class="ip-item">
1027
+ <div>
1028
+ <span class="ip-address">Loading...</span>
1029
+ <div class="ip-time">Just now</div>
1030
+ </div>
1031
+ <span class="ip-count">0 requests</span>
1032
+ </div>
1033
+ </div>
1034
+ </div>
1035
+ </div>
1036
+ </div>
1037
+
1038
+ <div id="plugins" class="section">
1039
+ <h2><i class="fas fa-plug"></i> Available API Plugins</h2>
1040
+ <p style="margin-bottom: 2rem; opacity: 0.8;">Discover and test our API endpoints with interactive documentation</p>
1041
+
1042
+ <div class="search-container">
1043
+ <i class="fas fa-search search-icon"></i>
1044
+ <input type="text"
1045
+ class="search-input"
1046
+ placeholder="Search plugins by name, description, or tags..."
1047
+ oninput="searchPlugins(this.value)"
1048
+ id="pluginSearch">
1049
+ </div>
1050
+
1051
+ <div class="plugins-grid" id="pluginsGrid">
1052
+ <div class="loading">
1053
+ <i class="fas fa-spinner fa-spin" style="margin-right: 0.5rem;"></i>
1054
+ Loading plugins...
1055
+ </div>
1056
+ </div>
1057
+ </div>
1058
+
1059
+ <!----- KENTOD --->
1060
+
1061
+ <div id="server-stats" class="section">
1062
+ <h2><i class="fas fa-server"></i> Server Statistics</h2>
1063
+
1064
+ <!--- APA LIAT LIAT --->
1065
+
1066
+ <div class="stats-cards">
1067
+ <div class="stat-card">
1068
+ <div class="stat-icon">
1069
+ <img src="https://api.iconify.design/mdi/account-group.svg?color=%23ba68c8&width=48&height=48" alt="users">
1070
+ </div>
1071
+ <div class="stat-info">
1072
+ <div class="stat-number" id="totalUsersCount">0</div>
1073
+ <div class="stat-label">Total Users</div>
1074
+ </div>
1075
+ </div>
1076
+ <div class="stat-card">
1077
+ <div class="stat-icon">
1078
+ <img src="https://api.iconify.design/mdi/account.svg?color=%23ce93d8&width=48&height=48" alt="user">
1079
+ </div>
1080
+ <div class="stat-info">
1081
+ <div class="stat-number" id="regularUsersCount">0</div>
1082
+ <div class="stat-label">Regular Users</div>
1083
+ </div>
1084
+ </div>
1085
+ <div class="stat-card">
1086
+ <div class="stat-icon">
1087
+ <img src="https://api.iconify.design/mdi/crown.svg?color=%23ba68c8&width=48&height=48" alt="crown">
1088
+ </div>
1089
+ <div class="stat-info">
1090
+ <div class="stat-number" id="premiumUsersCount">0</div>
1091
+ <div class="stat-label">Premium Users</div>
1092
+ </div>
1093
+ </div>
1094
+ </div>
1095
+
1096
+ <div class="admin-card">
1097
+ <h3><i class="fas fa-chart-pie"></i> User Role Distribution</h3>
1098
+ <canvas id="roleChart" style="max-height: 300px;"></canvas>
1099
+ </div>
1100
+
1101
+ <div class="admin-card">
1102
+ <h3><i class="fas fa-database"></i> Database Statistics</h3>
1103
+ <div class="stats-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.5rem;">
1104
+ <div class="stat-item">
1105
+ <i class="fas fa-hdd" style="font-size: 2rem; color: rgba(133, 48, 48, 0.8); margin-bottom: 0.5rem;"></i>
1106
+ <span class="stat-value" id="dbSize">0 MB</span>
1107
+ <span class="stat-label">Database Size</span>
1108
+ </div>
1109
+ <div class="stat-item">
1110
+ <i class="fas fa-memory" style="font-size: 2rem; color: rgba(133, 48, 48, 0.8); margin-bottom: 0.5rem;"></i>
1111
+ <span class="stat-value" id="ramUsage">0 MB</span>
1112
+ <span class="stat-label">RAM Usage</span>
1113
+ </div>
1114
+ <div class="stat-item">
1115
+ <i class="fas fa-microchip" style="font-size: 2rem; color: rgba(133, 48, 48, 0.8); margin-bottom: 0.5rem;"></i>
1116
+ <span class="stat-value" id="cpuUsage">0%</span>
1117
+ <span class="stat-label">CPU Usage</span>
1118
+ </div>
1119
+ <div class="stat-item">
1120
+ <i class="fas fa-server" style="font-size: 2rem; color: rgba(133, 48, 48, 0.8); margin-bottom: 0.5rem;"></i>
1121
+ <span class="stat-value" id="storageUsed">0 GB</span>
1122
+ <span class="stat-label">Storage Used</span>
1123
+ </div>
1124
+ </div>
1125
+ </div>
1126
+
1127
+ <div class="admin-card">
1128
+ <h3><i class="fas fa-chart-bar"></i> Role Distribution Details</h3>
1129
+ <div class="stats-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem;">
1130
+ <div class="stat-item">
1131
+ <span class="stat-value" id="cheapCount">0</span>
1132
+ <span class="stat-label">Cheap Role</span>
1133
+ </div>
1134
+ <div class="stat-item">
1135
+ <span class="stat-value" id="premiumCount">0</span>
1136
+ <span class="stat-label">Premium Role</span>
1137
+ </div>
1138
+ <div class="stat-item">
1139
+ <span class="stat-value" id="vipCount">0</span>
1140
+ <span class="stat-label">VIP Role</span>
1141
+ </div>
1142
+ <div class="stat-item">
1143
+ <span class="stat-value" id="supremeCount">0</span>
1144
+ <span class="stat-label">Supreme Role</span>
1145
+ </div>
1146
+ </div>
1147
+ </div>
1148
+ </div>
1149
+
1150
+ <div id="api-stats" class="section">
1151
+ <h2><i class="fas fa-chart-area"></i> API Statistics</h2>
1152
+ <p style="margin-bottom: 2rem; opacity: 0.8;">Global API usage statistics and analytics</p>
1153
+
1154
+ <div class="stats-cards">
1155
+ <div class="stat-card">
1156
+ <div class="stat-icon">
1157
+ <i class="fas fa-globe"></i>
1158
+ </div>
1159
+ <div class="stat-info">
1160
+ <div class="stat-number" id="globalTotalRequests">0</div>
1161
+ <div class="stat-label">Total Requests (All Users)</div>
1162
+ </div>
1163
+ </div>
1164
+ <div class="stat-card">
1165
+ <div class="stat-icon">
1166
+ <i class="fas fa-calendar-day"></i>
1167
+ </div>
1168
+ <div class="stat-info">
1169
+ <div class="stat-number" id="globalTodayRequests">0</div>
1170
+ <div class="stat-label">Today's Requests (All Users)</div>
1171
+ </div>
1172
+ </div>
1173
+ <div class="stat-card">
1174
+ <div class="stat-icon">
1175
+ <i class="fas fa-check-circle"></i>
1176
+ </div>
1177
+ <div class="stat-info">
1178
+ <div class="stat-number" id="successRate">0%</div>
1179
+ <div class="stat-label">Success Rate</div>
1180
+ </div>
1181
+ </div>
1182
+ <div class="stat-card">
1183
+ <div class="stat-icon">
1184
+ <i class="fas fa-times-circle"></i>
1185
+ </div>
1186
+ <div class="stat-info">
1187
+ <div class="stat-number" id="failRate">0%</div>
1188
+ <div class="stat-label">Fail Rate</div>
1189
+ </div>
1190
+ </div>
1191
+ </div>
1192
+
1193
+ <div class="charts-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 2rem; margin-top: 2rem;">
1194
+ <div class="admin-card">
1195
+ <h3><i class="fas fa-chart-pie"></i> Top Endpoints Distribution</h3>
1196
+ <canvas id="topEndpointsChart" style="max-height: 350px;"></canvas>
1197
+ </div>
1198
+
1199
+ <div class="admin-card">
1200
+ <h3><i class="fas fa-percentage"></i> Success vs Fail Rate</h3>
1201
+ <canvas id="successFailChart" style="max-height: 350px;"></canvas>
1202
+ </div>
1203
+ </div>
1204
+
1205
+ <div class="admin-card" style="margin-top: 2rem;">
1206
+ <h3><i class="fas fa-chart-bar"></i> Daily Request Statistics (Last 7 Days)</h3>
1207
+ <canvas id="dailyRequestsChart" style="max-height: 400px;"></canvas>
1208
+ </div>
1209
+
1210
+ <div class="admin-card" style="margin-top: 2rem;">
1211
+ <h3><i class="fas fa-chart-line"></i> Hourly Trends (Last 24 Hours)</h3>
1212
+ <canvas id="hourlyTrendsChart" style="max-height: 400px;"></canvas>
1213
+ </div>
1214
+
1215
+ <div class="admin-card" style="margin-top: 2rem;">
1216
+ <h3><i class="fas fa-list-ol"></i> Top 10 Most Used Endpoints</h3>
1217
+ <div id="topEndpointsList">
1218
+ <div class="loading">
1219
+ <i class="fas fa-spinner fa-spin"></i> Loading...
1220
+ </div>
1221
+ </div>
1222
+ </div>
1223
+ </div>
1224
+
1225
+ <div id="events" class="section">
1226
+ <h2><i class="fas fa-calendar"></i> Events & Rewards</h2>
1227
+ <div class="events-container">
1228
+ <div class="redeem-section">
1229
+ <h3><i class="fas fa-gift"></i> Redeem Code</h3>
1230
+ <p style="margin-bottom: 1.5rem; opacity: 0.8;">Enter a redeem code to unlock premium features or additional limits</p>
1231
+ <div class="form-group">
1232
+ <input type="text" id="redeemCode" placeholder="Enter your redeem code" style="text-transform: uppercase;">
1233
+ <button onclick="redeemCode()" class="btn btn-primary">
1234
+ <i class="fas fa-magic"></i> Redeem
1235
+ </button>
1236
+ </div>
1237
+ </div>
1238
+ </div>
1239
+ </div>
1240
+
1241
+ <div id="settings" class="section">
1242
+ <h2><i class="fas fa-cog"></i> Settings</h2>
1243
+ <div class="settings-container">
1244
+ <div class="setting-card">
1245
+ <h3><i class="fas fa-user-edit"></i> Profile Settings</h3>
1246
+ <div class="form-group">
1247
+ <label>Username</label>
1248
+ <input type="text" id="usernameInput" placeholder="Enter new username">
1249
+ </div>
1250
+ <button onclick="updateProfile()" class="btn btn-primary">
1251
+ <i class="fas fa-save"></i> Update Profile
1252
+ </button>
1253
+ </div>
1254
+
1255
+ <div class="setting-card" id="premiumSettings" style="display: none;">
1256
+ <h3><i class="fas fa-crown"></i> Premium Features</h3>
1257
+ <button onclick="regenerateApiKey()" class="btn btn-warning">
1258
+ <i class="fas fa-sync"></i> Regenerate API Key
1259
+ </button>
1260
+ <p class="text-muted">Generate a new API key (Premium only)</p>
1261
+ </div>
1262
+
1263
+ <div class="setting-card danger-zone">
1264
+ <h3><i class="fas fa-exclamation-triangle"></i> Danger Zone</h3>
1265
+ <button onclick="deleteAccount()" class="btn btn-danger">
1266
+ <i class="fas fa-trash"></i> Delete Account
1267
+ </button>
1268
+ <p class="text-muted">This action cannot be undone</p>
1269
+ </div>
1270
+ </div>
1271
+ </div>
1272
+
1273
+ <div id="management" class="section">
1274
+ <h2><i class="fas fa-users-cog"></i> Admin Management</h2>
1275
+ <div class="admin-container">
1276
+ <div class="admin-card">
1277
+ <h3><i class="fas fa-users"></i> User Management</h3>
1278
+ <div id="adminUsersList">
1279
+ <div class="loading">
1280
+ <i class="fas fa-spinner fa-spin"></i> Loading users...
1281
+ </div>
1282
+ </div>
1283
+ </div>
1284
+
1285
+ <div class="admin-card">
1286
+ <h3><i class="fas fa-user-tag"></i> Set User Role</h3>
1287
+ <div class="form-row">
1288
+ <div class="form-group" style="grid-column: 1 / -1;">
1289
+ <label>Search User <span class="required">*</span></label>
1290
+ <input type="text" id="searchUserInput" placeholder="Search by username or email" oninput="searchUsersForRole(this.value)">
1291
+ <div id="userSearchResults" style="display: none; margin-top: 0.5rem; background: rgba(255,255,255,0.05); border-radius: 8px; max-height: 200px; overflow-y: auto;"></div>
1292
+ </div>
1293
+ <div class="form-group">
1294
+ <label>Selected User</label>
1295
+ <input type="text" id="selectedUserDisplay" placeholder="No user selected" readonly>
1296
+ <input type="hidden" id="selectedUserId">
1297
+ </div>
1298
+ <div class="form-group">
1299
+ <label>Role <span class="required">*</span></label>
1300
+ <select id="assignRoleType">
1301
+ <option value="cheap">Cheap (Limit 500)</option>
1302
+ <option value="premium">Premium (Limit 1500)</option>
1303
+ <option value="vip">VIP (Limit 2500)</option>
1304
+ <option value="supreme">Supreme (Limit 3000)</option>
1305
+ </select>
1306
+ </div>
1307
+ <div class="form-group">
1308
+ <label>Custom API Key <span style="color: #666; font-size: 0.85em;">(Optional)</span></label>
1309
+ <input type="text" id="customApiKey" placeholder="Leave empty for current key">
1310
+ <small>All roles support custom API keys</small>
1311
+ </div>
1312
+ </div>
1313
+ <button onclick="assignUserRole()" class="btn btn-primary">
1314
+ <i class="fas fa-user-check"></i> Assign Role
1315
+ </button>
1316
+ </div>
1317
+
1318
+ <div class="admin-card">
1319
+ <h3><i class="fas fa-ticket-alt"></i> Create Redeem Code</h3>
1320
+ <div class="form-row">
1321
+ <div class="form-group">
1322
+ <label>Type <span class="required">*</span></label>
1323
+ <select id="redeemType">
1324
+ <option value="limit">Limit Only</option>
1325
+ <option value="premium">Premium Only</option>
1326
+ <option value="both">Both</option>
1327
+ </select>
1328
+ </div>
1329
+ <div class="form-group" id="limitContainer" style="display: none;">
1330
+ <label>Limit Value</label>
1331
+ <input type="number" id="limitValue" min="0" placeholder="Additional limit">
1332
+ <small>Optional for Premium Only</small>
1333
+ </div>
1334
+ <div class="form-group" id="codeExpiredContainer" style="display: none;">
1335
+ <label>Code Expired <span class="required">*</span></label>
1336
+ <input type="datetime-local" id="codeExpired" required>
1337
+ <small>When the code expires</small>
1338
+ </div>
1339
+ <div class="form-group" id="premiumExpiredContainer" style="display: none;">
1340
+ <label>Premium Expired <span class="required">*</span></label>
1341
+ <input type="datetime-local" id="premiumExpired">
1342
+ <small>When premium access expires</small>
1343
+ </div>
1344
+ </div>
1345
+ <button onclick="createRedeemCode()" class="btn btn-primary">
1346
+ <i class="fas fa-plus"></i> Create Code
1347
+ </button>
1348
+ </div>
1349
+
1350
+ <div class="admin-card">
1351
+ <h3><i class="fas fa-chart-pie"></i> System Statistics</h3>
1352
+ <div class="stats-grid">
1353
+ <div class="stat-item">
1354
+ <span class="stat-value" id="adminTotalUsers">0</span>
1355
+ <span class="stat-label">Total Users</span>
1356
+ </div>
1357
+ <div class="stat-item">
1358
+ <span class="stat-value" id="adminTotalRequests">0</span>
1359
+ <span class="stat-label">Total Requests</span>
1360
+ </div>
1361
+ <div class="stat-item">
1362
+ <span class="stat-value" id="adminTodayRequests">0</span>
1363
+ <span class="stat-label">Today's Requests</span>
1364
+ </div>
1365
+ </div>
1366
+ </div>
1367
+ </div>
1368
+ </div>
1369
+ </div>
1370
+ </div>
1371
+
1372
+ <script>
1373
+ (function(){
1374
+ function detectDevTools(){
1375
+ const threshold = 160;
1376
+ const widthThreshold = window.outerWidth - window.innerWidth > threshold;
1377
+ const heightThreshold = window.outerHeight - window.innerHeight > threshold;
1378
+ if(widthThreshold || heightThreshold) window.location.href = "/denied";
1379
+ }
1380
+
1381
+ document.addEventListener("contextmenu", e => e.preventDefault());
1382
+ document.onkeydown = function(e){
1383
+ if(e.keyCode === 123 || (e.ctrlKey && e.shiftKey && ['I','C','J'].includes(e.key?.toUpperCase())) || (e.ctrlKey && e.key?.toUpperCase() === 'U')){
1384
+ e.preventDefault();
1385
+ window.location.href = "/denied";
1386
+ }
1387
+ };
1388
+
1389
+ setInterval(() => {
1390
+ if(window.eruda) window.location.href = "/denied";
1391
+ detectDevTools();
1392
+ try{
1393
+ console.profile();
1394
+ console.profileEnd();
1395
+ }catch(e){}
1396
+ try{
1397
+ if(console.clear.toString().length > 100) window.location.href = "/denied";
1398
+ }catch(e){}
1399
+ }, 1000);
1400
+ })();
1401
+ </script>
1402
+
1403
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.js"></script>
1404
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
1405
+ <script src="dashboard.js"></script>
1406
+ </body>
1407
+ </html>
public/dashboard.js ADDED
The diff for this file is too large to render. See raw diff
 
public/denied.html ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>403 Denied</title>
7
+ <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🔒</text></svg>">
8
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
9
+ <style>
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ font-family: 'Poppins', sans-serif;
18
+ background: linear-gradient(135deg, #FFA8A8 0%, #8D96FF 100%);
19
+ min-height: 100vh;
20
+ display: flex;
21
+ justify-content: center;
22
+ align-items: center;
23
+ overflow: hidden;
24
+ position: relative;
25
+ }
26
+
27
+ .background-shapes {
28
+ position: absolute;
29
+ width: 100%;
30
+ height: 100%;
31
+ overflow: hidden;
32
+ z-index: 1;
33
+ }
34
+
35
+ .shape {
36
+ position: absolute;
37
+ background: rgba(255, 250, 240, 0.25);
38
+ border-radius: 50%;
39
+ animation: float 20s infinite ease-in-out;
40
+ }
41
+
42
+ .shape:nth-child(1) {
43
+ width: 300px;
44
+ height: 300px;
45
+ top: -100px;
46
+ left: -100px;
47
+ animation-delay: 0s;
48
+ }
49
+
50
+ .shape:nth-child(2) {
51
+ width: 200px;
52
+ height: 200px;
53
+ top: 50%;
54
+ right: -50px;
55
+ animation-delay: 3s;
56
+ }
57
+
58
+ .shape:nth-child(3) {
59
+ width: 150px;
60
+ height: 150px;
61
+ bottom: -50px;
62
+ left: 30%;
63
+ animation-delay: 6s;
64
+ }
65
+
66
+ @keyframes float {
67
+ 0%, 100% {
68
+ transform: translateY(0) rotate(0deg);
69
+ }
70
+ 50% {
71
+ transform: translateY(-50px) rotate(180deg);
72
+ }
73
+ }
74
+
75
+ .container {
76
+ position: relative;
77
+ z-index: 2;
78
+ text-align: center;
79
+ padding: 40px;
80
+ background: rgba(255, 255, 255, 0.15);
81
+ backdrop-filter: blur(20px);
82
+ border-radius: 30px;
83
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
84
+ border: 1px solid rgba(255, 255, 255, 0.3);
85
+ max-width: 550px;
86
+ animation: slideUp 0.8s ease-out;
87
+ }
88
+
89
+ @keyframes slideUp {
90
+ from {
91
+ opacity: 0;
92
+ transform: translateY(50px);
93
+ }
94
+ to {
95
+ opacity: 1;
96
+ transform: translateY(0);
97
+ }
98
+ }
99
+
100
+ .error-code {
101
+ font-size: 120px;
102
+ font-weight: 700;
103
+ background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
104
+ -webkit-background-clip: text;
105
+ -webkit-text-fill-color: transparent;
106
+ background-clip: text;
107
+ margin-bottom: 10px;
108
+ text-shadow: 0 4px 15px rgba(252, 182, 159, 0.3);
109
+ animation: glow 2s ease-in-out infinite;
110
+ filter: drop-shadow(0 0 20px rgba(255, 236, 210, 0.5));
111
+ }
112
+
113
+ @keyframes glow {
114
+ 0%, 100% {
115
+ filter: drop-shadow(0 0 20px rgba(255, 236, 210, 0.5));
116
+ }
117
+ 50% {
118
+ filter: drop-shadow(0 0 35px rgba(252, 182, 159, 0.7));
119
+ }
120
+ }
121
+
122
+ .error-title {
123
+ font-size: 48px;
124
+ font-weight: 600;
125
+ color: #ffffff;
126
+ margin-bottom: 25px;
127
+ letter-spacing: 2px;
128
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
129
+ }
130
+
131
+ .error-description {
132
+ font-size: 16px;
133
+ font-weight: 300;
134
+ color: #ffffff;
135
+ line-height: 1.8;
136
+ margin-bottom: 40px;
137
+ opacity: 0.95;
138
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
139
+ }
140
+
141
+ .button-group {
142
+ display: flex;
143
+ gap: 20px;
144
+ justify-content: center;
145
+ flex-wrap: wrap;
146
+ }
147
+
148
+ .btn {
149
+ padding: 15px 40px;
150
+ font-family: 'Poppins', sans-serif;
151
+ font-size: 16px;
152
+ font-weight: 500;
153
+ border: none;
154
+ border-radius: 50px;
155
+ cursor: pointer;
156
+ transition: all 0.3s ease;
157
+ text-decoration: none;
158
+ display: inline-block;
159
+ position: relative;
160
+ overflow: hidden;
161
+ }
162
+
163
+ .btn::before {
164
+ content: '';
165
+ position: absolute;
166
+ top: 50%;
167
+ left: 50%;
168
+ width: 0;
169
+ height: 0;
170
+ border-radius: 50%;
171
+ background: rgba(255, 255, 255, 0.3);
172
+ transform: translate(-50%, -50%);
173
+ transition: width 0.6s, height 0.6s;
174
+ }
175
+
176
+ .btn:hover::before {
177
+ width: 300px;
178
+ height: 300px;
179
+ }
180
+
181
+ .btn span {
182
+ position: relative;
183
+ z-index: 1;
184
+ }
185
+
186
+ .btn-home {
187
+ background: linear-gradient(135deg, #8D96FF 0%, #a8b0ff 100%);
188
+ color: white;
189
+ box-shadow: 0 10px 25px rgba(141, 150, 255, 0.3);
190
+ }
191
+
192
+ .btn-home:hover {
193
+ transform: translateY(-3px);
194
+ box-shadow: 0 15px 35px rgba(141, 150, 255, 0.4);
195
+ }
196
+
197
+ .btn-dashboard {
198
+ background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
199
+ color: #8D96FF;
200
+ box-shadow: 0 10px 25px rgba(252, 182, 159, 0.3);
201
+ }
202
+
203
+ .btn-dashboard:hover {
204
+ transform: translateY(-3px);
205
+ box-shadow: 0 15px 35px rgba(252, 182, 159, 0.4);
206
+ }
207
+
208
+ .lock-icon {
209
+ width: 80px;
210
+ height: 80px;
211
+ margin: 0 auto 20px;
212
+ animation: fadeInBounce 1s ease-out;
213
+ }
214
+
215
+ @keyframes fadeInBounce {
216
+ 0% {
217
+ opacity: 0;
218
+ transform: scale(0.3) translateY(-50px);
219
+ }
220
+ 50% {
221
+ transform: scale(1.05) translateY(0);
222
+ }
223
+ 70% {
224
+ transform: scale(0.95);
225
+ }
226
+ 100% {
227
+ opacity: 1;
228
+ transform: scale(1);
229
+ }
230
+ }
231
+
232
+ @media (max-width: 600px) {
233
+ .container {
234
+ padding: 30px 20px;
235
+ }
236
+
237
+ .error-code {
238
+ font-size: 80px;
239
+ }
240
+
241
+ .error-title {
242
+ font-size: 32px;
243
+ }
244
+
245
+ .error-description {
246
+ font-size: 14px;
247
+ }
248
+
249
+ .btn {
250
+ padding: 12px 30px;
251
+ font-size: 14px;
252
+ }
253
+
254
+ .button-group {
255
+ flex-direction: column;
256
+ }
257
+ }
258
+ </style>
259
+ </head>
260
+ <body>
261
+ <div class="background-shapes">
262
+ <div class="shape"></div>
263
+ <div class="shape"></div>
264
+ <div class="shape"></div>
265
+ </div>
266
+
267
+ <div class="container">
268
+ <svg class="lock-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
269
+ <rect x="3" y="11" width="18" height="11" rx="2" ry="2" fill="#fff" opacity="0.9"/>
270
+ <path d="M7 11V7a5 5 0 0 1 10 0v4" stroke="#8D96FF" stroke-width="2.5"/>
271
+ <circle cx="12" cy="16" r="1.5" fill="#FFA8A8"/>
272
+ </svg>
273
+ <div class="error-code">403</div>
274
+ <h1 class="error-title">Access Denied</h1>
275
+ <p class="error-description">
276
+ Sorry, you can't access this page. Using Eruda, Inspect Element, or DevTools is not allowed according to our Terms of Service. Please respect our policies and use the platform as intended.
277
+ </p>
278
+ <div class="button-group">
279
+ <a href="/" class="btn btn-home">
280
+ <span>Home</span>
281
+ </a>
282
+ <a href="/dashboard" class="btn btn-dashboard">
283
+ <span>Dashboard</span>
284
+ </a>
285
+ </div>
286
+ </div>
287
+
288
+ <script>
289
+ // Animasi tambahan untuk elemen
290
+ const container = document.querySelector('.container');
291
+
292
+ // Efek parallax ringan saat mouse bergerak
293
+ document.addEventListener('mousemove', (e) => {
294
+ const moveX = (e.clientX - window.innerWidth / 2) * 0.01;
295
+ const moveY = (e.clientY - window.innerHeight / 2) * 0.01;
296
+ container.style.transform = `translate(${moveX}px, ${moveY}px)`;
297
+ });
298
+
299
+ // Animasi tombol saat diklik
300
+ const buttons = document.querySelectorAll('.btn');
301
+ buttons.forEach(btn => {
302
+ btn.addEventListener('click', function(e) {
303
+ let ripple = document.createElement('span');
304
+ ripple.classList.add('ripple');
305
+ this.appendChild(ripple);
306
+
307
+ let x = e.clientX - e.target.offsetLeft;
308
+ let y = e.clientY - e.target.offsetTop;
309
+
310
+ ripple.style.left = x + 'px';
311
+ ripple.style.top = y + 'px';
312
+
313
+ setTimeout(() => {
314
+ ripple.remove();
315
+ }, 600);
316
+ });
317
+ });
318
+ </script>
319
+ </body>
320
+ </html>
public/herxa ADDED
File without changes
public/icon.webp ADDED

Git LFS Details

  • SHA256: 512946887b36ebbe75362e48af5cbfe6f36c0bfb09c64cd9cd0d8153dc46f66f
  • Pointer size: 128 Bytes
  • Size of remote file: 131 Bytes
public/index.html ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DashX - API Services</title>
7
+ <link rel="icon" type="image/webp" href="/icon.webp">
8
+ <meta name="description" content="DashX API provides developers with a powerful and easy-to-use platform to manage, monitor, and integrate multiple REST APIs. Get started with a modern interface, advanced analytics, and seamless API management all in one place.">
9
+
10
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
11
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
12
+ <link href="styles.css" rel="stylesheet">
13
+ <style>
14
+ .navbar {
15
+ background: rgba(44, 62, 80, 0.95) !important;
16
+ backdrop-filter: blur(10px);
17
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
18
+ box-shadow: 0 2px 20px rgba(0, 0, 0, 0.2);
19
+ }
20
+
21
+ .navbar-brand {
22
+ font-size: 1.5rem;
23
+ font-weight: 700;
24
+ color: #fff !important;
25
+ text-decoration: none;
26
+ }
27
+
28
+ .navbar-brand i {
29
+ color: #e74c3c;
30
+ font-size: 1.8rem;
31
+ margin-right: 0.5rem;
32
+ }
33
+
34
+ .nav-link {
35
+ color: #ecf0f1 !important;
36
+ font-weight: 500;
37
+ transition: all 0.3s ease;
38
+ padding: 0.5rem 1rem !important;
39
+ border-radius: 6px;
40
+ margin: 0 0.25rem;
41
+ }
42
+
43
+ .nav-link:hover {
44
+ background: rgba(255, 255, 255, 0.1);
45
+ transform: translateY(-1px);
46
+ }
47
+
48
+ .nav-link.text-danger {
49
+ color: #e74c3c !important;
50
+ }
51
+
52
+ .nav-link.text-danger:hover {
53
+ background: rgba(231, 76, 60, 0.1);
54
+ color: #ff6b6b !important;
55
+ }
56
+ </style>
57
+ </head>
58
+ <body>
59
+ <nav class="navbar navbar-expand-lg navbar-dark">
60
+ <div class="container">
61
+ <a class="navbar-brand" href="/">
62
+ <i class="fas fa-bolt"></i> DashX
63
+ </a>
64
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
65
+ <span class="navbar-toggler-icon"></span>
66
+ </button>
67
+ <div class="collapse navbar-collapse" id="navbarNav">
68
+ <ul class="navbar-nav ms-auto">
69
+ <li class="nav-item">
70
+ <a class="nav-link" href="/dashboard">Dashboard</a>
71
+ </li>
72
+ <li class="nav-item">
73
+ <a class="nav-link" href="/auth">Register</a>
74
+ </li>
75
+ </ul>
76
+ </div>
77
+ </div>
78
+ </nav>
79
+
80
+ <header class="hero">
81
+ <div class="hero-content">
82
+ <h1 class="hero-title">Welcome to DashX</h1>
83
+ <p class="hero-subtitle">Powerful API services for developers</p>
84
+ <div class="hero-buttons">
85
+ <a href="/auth" class="btn btn-primary">Get Started</a>
86
+ <a href="#features" class="btn btn-secondary">Learn More</a>
87
+ </div>
88
+ </div>
89
+ </header>
90
+
91
+ <section id="features" class="features">
92
+ <div class="container">
93
+ <h2 class="section-title">Features</h2>
94
+ <div class="features-grid">
95
+ <div class="feature-card">
96
+ <i class="fas fa-shield-alt feature-icon"></i>
97
+ <h3>Cloudflare Bypass</h3>
98
+ <p>Bypass Cloudflare Turnstile protection with multiple fallback APIs</p>
99
+ </div>
100
+ <div class="feature-card">
101
+ <i class="fas fa-qrcode feature-icon"></i>
102
+ <h3>QR Generator</h3>
103
+ <p>Generate QR codes for text, URLs, and more with custom sizes</p>
104
+ </div>
105
+ <div class="feature-card">
106
+ <i class="fas fa-tachometer-alt feature-icon"></i>
107
+ <h3>Rate Limiting</h3>
108
+ <p>Built-in rate limiting to prevent spam and ensure fair usage</p>
109
+ </div>
110
+ <div class="feature-card">
111
+ <i class="fas fa-key feature-icon"></i>
112
+ <h3>API Key Management</h3>
113
+ <p>Secure API key system with usage tracking and limits</p>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </section>
118
+
119
+ <section class="stats">
120
+ <div class="container">
121
+ <div class="stats-grid">
122
+ <div class="stat-card">
123
+ <div class="stat-number" id="totalUsers">0</div>
124
+ <div class="stat-label">Total Users</div>
125
+ </div>
126
+ <div class="stat-card">
127
+ <div class="stat-number" id="totalRequests">0</div>
128
+ <div class="stat-label">API Requests</div>
129
+ </div>
130
+ <div class="stat-card">
131
+ <div class="stat-number" id="todayRequests">0</div>
132
+ <div class="stat-label">Today's Requests</div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+ </section>
137
+
138
+ <footer class="footer">
139
+ <div class="container">
140
+ <p>&copy; 2025 DashX. All rights reserved.</p>
141
+ </div>
142
+ </footer>
143
+
144
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.js"></script>
145
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
146
+ <script src="index.js"></script>
147
+ </body>
148
+ </html>
public/index.js ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', function() {
2
+ loadStats();
3
+ checkAuthStatus();
4
+ setInterval(loadStats, 30000);
5
+ });
6
+
7
+ function checkAuthStatus() {
8
+ const token = localStorage.getItem('dashx_token');
9
+ if (token) {
10
+ const navMenu = document.querySelector('.nav-menu');
11
+ if (navMenu) {
12
+ navMenu.innerHTML = `
13
+ <a href="/dashboard" class="nav-link"><i class="fas fa-chart-line"></i> Dashboard</a>
14
+ <a href="/profile" class="nav-link"><i class="fas fa-user"></i> Profile</a>
15
+ <a href="#" onclick="logout()" class="nav-link"><i class="fas fa-sign-out-alt"></i> Logout</a>
16
+ `;
17
+ }
18
+ }
19
+ }
20
+
21
+ async function loadStats() {
22
+ try {
23
+ const totalUsersEl = document.getElementById('totalUsers');
24
+ const totalRequestsEl = document.getElementById('totalRequests');
25
+ const todayRequestsEl = document.getElementById('todayRequests');
26
+
27
+ if (totalUsersEl) {
28
+ totalUsersEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
29
+ }
30
+ if (totalRequestsEl) {
31
+ totalRequestsEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
32
+ }
33
+ if (todayRequestsEl) {
34
+ todayRequestsEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
35
+ }
36
+
37
+ const response = await fetch('/api/stats', {
38
+ method: 'GET',
39
+ headers: {
40
+ 'Content-Type': 'application/json'
41
+ }
42
+ });
43
+
44
+ if (response.ok) {
45
+ const data = await response.json();
46
+ if (data.success && data.stats) {
47
+ const stats = data.stats;
48
+
49
+ if (totalUsersEl) {
50
+ totalUsersEl.textContent = formatNumber(stats.totalUsers) || '0';
51
+ }
52
+ if (totalRequestsEl) {
53
+ totalRequestsEl.textContent = formatNumber(stats.totalRequests) || '0';
54
+ }
55
+ if (todayRequestsEl) {
56
+ todayRequestsEl.textContent = formatNumber(stats.todayRequests) || '0';
57
+ }
58
+
59
+ animateNumbers();
60
+ } else {
61
+ throw new Error(data.error || 'Failed to load stats');
62
+ }
63
+ } else {
64
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
65
+ }
66
+ } catch (error) {
67
+ console.error('Error loading stats:', error);
68
+
69
+ const totalUsersEl = document.getElementById('totalUsers');
70
+ const totalRequestsEl = document.getElementById('totalRequests');
71
+ const todayRequestsEl = document.getElementById('todayRequests');
72
+
73
+ if (totalUsersEl) totalUsersEl.textContent = '0';
74
+ if (totalRequestsEl) totalRequestsEl.textContent = '0';
75
+ if (todayRequestsEl) todayRequestsEl.textContent = '0';
76
+ }
77
+ }
78
+
79
+ function formatNumber(num) {
80
+ if (typeof num !== 'number') return '0';
81
+
82
+ if (num >= 1000000) {
83
+ return (num / 1000000).toFixed(1) + 'M';
84
+ } else if (num >= 1000) {
85
+ return (num / 1000).toFixed(1) + 'K';
86
+ }
87
+ return num.toLocaleString();
88
+ }
89
+
90
+ function animateNumbers() {
91
+ const numbers = document.querySelectorAll('.stat-number');
92
+ numbers.forEach(number => {
93
+ if (number.textContent.includes('Error') || number.textContent.includes('fa-spin')) {
94
+ return;
95
+ }
96
+
97
+ const finalText = number.textContent;
98
+ let targetValue = 0;
99
+
100
+ if (finalText.includes('K')) {
101
+ targetValue = parseFloat(finalText) * 1000;
102
+ } else if (finalText.includes('M')) {
103
+ targetValue = parseFloat(finalText) * 1000000;
104
+ } else {
105
+ targetValue = parseInt(finalText.replace(/,/g, '')) || 0;
106
+ }
107
+
108
+ if (targetValue === 0) return;
109
+
110
+ let current = 0;
111
+ const increment = Math.max(1, Math.ceil(targetValue / 50));
112
+
113
+ number.textContent = '0';
114
+
115
+ const timer = setInterval(() => {
116
+ current += increment;
117
+ if (current >= targetValue) {
118
+ current = targetValue;
119
+ clearInterval(timer);
120
+ number.textContent = finalText;
121
+ } else {
122
+ if (targetValue >= 1000000) {
123
+ number.textContent = (current / 1000000).toFixed(1) + 'M';
124
+ } else if (targetValue >= 1000) {
125
+ number.textContent = (current / 1000).toFixed(1) + 'K';
126
+ } else {
127
+ number.textContent = current.toLocaleString();
128
+ }
129
+ }
130
+ }, 30);
131
+ });
132
+ }
133
+
134
+ function logout() {
135
+ localStorage.removeItem('dashx_token');
136
+ localStorage.removeItem('dashx_user');
137
+ window.location.href = '/';
138
+ }
139
+
140
+ function addLiveUpdates() {
141
+ const statsCards = document.querySelectorAll('.stat-card');
142
+ statsCards.forEach(card => {
143
+ card.addEventListener('mouseenter', () => {
144
+ card.style.transform = 'translateY(-5px)';
145
+ card.style.boxShadow = '0 8px 25px rgba(0,0,0,0.15)';
146
+ });
147
+
148
+ card.addEventListener('mouseleave', () => {
149
+ card.style.transform = 'translateY(0)';
150
+ card.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';
151
+ });
152
+ });
153
+ }
154
+
155
+ function addRefreshButton() {
156
+ const refreshBtn = document.createElement('button');
157
+ refreshBtn.innerHTML = '<i class="fas fa-sync-alt"></i>';
158
+ refreshBtn.title = 'Refresh Statistics';
159
+ refreshBtn.style.cssText = `
160
+ position: fixed;
161
+ bottom: 20px;
162
+ right: 20px;
163
+ width: 50px;
164
+ height: 50px;
165
+ border-radius: 50%;
166
+ border: none;
167
+ background: linear-gradient(45deg, #853030, #a64545);
168
+ color: white;
169
+ font-size: 1.2rem;
170
+ cursor: pointer;
171
+ box-shadow: 0 4px 12px rgba(133, 48, 48, 0.3);
172
+ transition: all 0.3s ease;
173
+ z-index: 1000;
174
+ `;
175
+
176
+ refreshBtn.addEventListener('click', () => {
177
+ refreshBtn.style.transform = 'rotate(360deg)';
178
+ loadStats();
179
+ setTimeout(() => {
180
+ refreshBtn.style.transform = 'rotate(0deg)';
181
+ }, 500);
182
+ });
183
+
184
+ refreshBtn.addEventListener('mouseenter', () => {
185
+ refreshBtn.style.transform = 'scale(1.1)';
186
+ refreshBtn.style.boxShadow = '0 6px 20px rgba(133, 48, 48, 0.4)';
187
+ });
188
+
189
+ refreshBtn.addEventListener('mouseleave', () => {
190
+ refreshBtn.style.transform = 'scale(1)';
191
+ refreshBtn.style.boxShadow = '0 4px 12px rgba(133, 48, 48, 0.3)';
192
+ });
193
+
194
+ document.body.appendChild(refreshBtn);
195
+ }
196
+
197
+ function initializeEnhancements() {
198
+ addLiveUpdates();
199
+ addRefreshButton();
200
+ }
201
+
202
+ function addLoadingStates() {
203
+ const style = document.createElement('style');
204
+ style.textContent = `
205
+ .loading-pulse {
206
+ animation: pulse 1.5s ease-in-out infinite;
207
+ }
208
+
209
+ @keyframes pulse {
210
+ 0% { opacity: 1; }
211
+ 50% { opacity: 0.5; }
212
+ 100% { opacity: 1; }
213
+ }
214
+
215
+ .stat-card:hover .stat-number {
216
+ transform: scale(1.05);
217
+ transition: transform 0.2s ease;
218
+ }
219
+ `;
220
+ document.head.appendChild(style);
221
+ }
222
+
223
+ function addKeyboardShortcuts() {
224
+ document.addEventListener('keydown', (event) => {
225
+ if (event.ctrlKey || event.metaKey) {
226
+ switch (event.key) {
227
+ case 'r':
228
+ event.preventDefault();
229
+ loadStats();
230
+ break;
231
+ case 'd':
232
+ event.preventDefault();
233
+ if (localStorage.getItem('dashx_token')) {
234
+ window.location.href = '/dashboard';
235
+ }
236
+ break;
237
+ }
238
+ }
239
+
240
+ if (event.key === 'F5') {
241
+ event.preventDefault();
242
+ loadStats();
243
+ }
244
+ });
245
+ }
246
+
247
+ document.addEventListener('DOMContentLoaded', () => {
248
+ setTimeout(() => {
249
+ initializeEnhancements();
250
+ addLoadingStates();
251
+ addKeyboardShortcuts();
252
+ }, 1000);
253
+ });
public/profile.html ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>DashX - Profile</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.css" rel="stylesheet">
9
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
10
+ <link href="styles.css" rel="stylesheet">
11
+ <style>
12
+ .navbar {
13
+ background: rgba(44, 62, 80, 0.95) !important;
14
+ backdrop-filter: blur(10px);
15
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
16
+ box-shadow: 0 2px 20px rgba(0, 0, 0, 0.2);
17
+ }
18
+
19
+ .navbar-brand {
20
+ font-size: 1.5rem;
21
+ font-weight: 700;
22
+ color: #fff !important;
23
+ }
24
+
25
+ .navbar-brand i {
26
+ color: #e74c3c;
27
+ font-size: 1.8rem;
28
+ margin-right: 0.5rem;
29
+ }
30
+
31
+ .nav-link {
32
+ color: #ecf0f1 !important;
33
+ font-weight: 500;
34
+ transition: all 0.3s ease;
35
+ padding: 0.5rem 1rem !important;
36
+ border-radius: 6px;
37
+ margin: 0 0.25rem;
38
+ }
39
+
40
+ .nav-link:hover {
41
+ background: rgba(255, 255, 255, 0.1);
42
+ transform: translateY(-1px);
43
+ }
44
+
45
+ .nav-link.text-danger {
46
+ color: #e74c3c !important;
47
+ }
48
+
49
+ .nav-link.text-danger:hover {
50
+ background: rgba(231, 76, 60, 0.1);
51
+ color: #ff6b6b !important;
52
+ }
53
+
54
+ </style>
55
+ </head>
56
+ <body>
57
+ <nav class="navbar navbar-expand-lg navbar-dark">
58
+ <div class="container">
59
+ <a class="navbar-brand" href="/">
60
+ <i class="fas fa-bolt"></i> DashX
61
+ </a>
62
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
63
+ <span class="navbar-toggler-icon"></span>
64
+ </button>
65
+ <div class="collapse navbar-collapse" id="navbarNav">
66
+ <ul class="navbar-nav ms-auto">
67
+ <li class="nav-item">
68
+ <a class="nav-link" href="/dashboard">
69
+ <i class="fas fa-chart-line"></i> Dashboard
70
+ </a>
71
+ </li>
72
+ <li class="nav-item">
73
+ <a class="nav-link text-danger" href="#" onclick="logout()">
74
+ <i class="fas fa-sign-out-alt"></i> Logout
75
+ </a>
76
+ </li>
77
+ </ul>
78
+ </div>
79
+ </div>
80
+ </nav>
81
+
82
+ <div class="profile-container">
83
+ <div class="profile-header">
84
+ <div class="profile-avatar" id="profileAvatar">
85
+ <img id="profileImage" src="" alt="Profile" style="display: none; width: 100%; height: 100%; border-radius: 50%; object-fit: cover;">
86
+ <i class="fas fa-user-circle" id="defaultAvatar"></i>
87
+ </div>
88
+ <div class="profile-info">
89
+ <h2 id="profileUsername">Loading...</h2>
90
+ <p id="profileEmail">Loading...</p>
91
+ <span class="badge" id="profileRole">User</span>
92
+ <span class="badge premium" id="premiumBadge" style="display: none;">Premium</span>
93
+ <span class="badge" id="adminBadge" style="display: none; background: linear-gradient(135deg, #853030 0%, #292727 100%);">Admin</span>
94
+ </div>
95
+ </div>
96
+
97
+ <div class="profile-content">
98
+ <div class="profile-section">
99
+ <h3><i class="fas fa-info-circle"></i> Account Information</h3>
100
+ <div class="info-grid">
101
+ <div class="info-item">
102
+ <label>API Key</label>
103
+ <div class="api-key-display">
104
+ <code id="profileApiKey">Loading...</code>
105
+ <button onclick="copyApiKey()" class="btn btn-sm">
106
+ <i class="fas fa-copy"></i>
107
+ </button>
108
+ </div>
109
+ </div>
110
+ <div class="info-item">
111
+ <label>Total Requests</label>
112
+ <span class="info-value" id="profileRequests">0</span>
113
+ </div>
114
+ <div class="info-item">
115
+ <label>Today's Requests</label>
116
+ <span class="info-value" id="profileRequestsToday">0</span>
117
+ </div>
118
+ <div class="info-item">
119
+ <label>Daily Limit</label>
120
+ <span class="info-value" id="profileLimit">30</span>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <div class="profile-section">
126
+ <h3><i class="fas fa-chart-bar"></i> Usage Statistics</h3>
127
+ <div class="usage-progress">
128
+ <div class="progress-item">
129
+ <label>Today's Usage</label>
130
+ <div class="progress-bar">
131
+ <div class="progress-fill" id="usageProgress"></div>
132
+ </div>
133
+ <span class="progress-text" id="usageText">0 / 30</span>
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ <div class="profile-section">
139
+ <h3><i class="fas fa-cog"></i> Account Settings</h3>
140
+ <div class="settings-grid">
141
+ <div class="setting-item">
142
+ <label>Change Username</label>
143
+ <div class="input-group">
144
+ <input type="text" id="newUsername" placeholder="Enter new username">
145
+ <button onclick="updateUsername()" class="btn btn-primary">
146
+ <i class="fas fa-save"></i> Update
147
+ </button>
148
+ </div>
149
+ </div>
150
+
151
+ <div class="setting-item">
152
+ <label>Profile Picture URL</label>
153
+ <div class="input-group">
154
+ <input type="url" id="profileUrlInput" placeholder="Enter image URL">
155
+ <button onclick="updateProfileUrl()" class="btn btn-primary">
156
+ <i class="fas fa-image"></i> Update
157
+ </button>
158
+ </div>
159
+ </div>
160
+
161
+ <div class="setting-item" id="premiumFeatures" style="display: none;">
162
+ <label>Premium Features</label>
163
+ <div class="premium-actions">
164
+ <button onclick="regenerateApiKey()" class="btn btn-warning">
165
+ <i class="fas fa-sync"></i> Regenerate API Key
166
+ </button>
167
+ </div>
168
+ <label>Custom API Key</label>
169
+ <div class="input-group">
170
+ <input type="text" id="customApiKeyInput" placeholder="Enter custom API key">
171
+ <button onclick="updateCustomApiKey()" class="btn btn-primary">
172
+ <i class="fas fa-key"></i> Update
173
+ </button>
174
+ </div>
175
+ <small style="opacity: 0.7;">Premium feature - Set your own custom API key</small>
176
+
177
+ </div>
178
+ </div>
179
+ </div>
180
+
181
+ <div class="profile-section">
182
+ <h3><i class="fas fa-history"></i> Recent Activity</h3>
183
+ <div class="activity-list" id="recentActivity">
184
+ <div class="activity-item">
185
+ <i class="fas fa-spinner fa-spin"></i>
186
+ <span>Loading activity...</span>
187
+ </div>
188
+ </div>
189
+ </div>
190
+
191
+ <div class="profile-section danger-zone">
192
+ <h3><i class="fas fa-exclamation-triangle"></i> Danger Zone</h3>
193
+ <div class="danger-actions">
194
+ <button onclick="deleteAccount()" class="btn btn-danger">
195
+ <i class="fas fa-trash"></i> Delete Account
196
+ </button>
197
+ <p class="warning-text">This action cannot be undone. All your data will be permanently deleted.</p>
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </div>
202
+
203
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.10.8/sweetalert2.min.js"></script>
204
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
205
+ <script src="profile.js"></script>
206
+ </body>
207
+ </html>
public/profile.js ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let currentUser = null;
2
+
3
+ document.addEventListener('DOMContentLoaded', function() {
4
+ checkAuth();
5
+ loadUserProfile();
6
+ loadRecentActivity();
7
+ setInterval(loadRecentActivity, 30000);
8
+ });
9
+
10
+ function checkAuth() {
11
+ const token = localStorage.getItem('dashx_token');
12
+ const user = JSON.parse(localStorage.getItem('dashx_user') || '{}');
13
+
14
+ if (!token) {
15
+ window.location.href = '/auth';
16
+ return;
17
+ }
18
+
19
+ currentUser = user;
20
+ }
21
+
22
+ async function updateCustomApiKey() {
23
+ const customApiKey = document.getElementById('customApiKeyInput').value.trim();
24
+
25
+ if (!customApiKey) {
26
+ Swal.fire({
27
+ icon: "error",
28
+ title: "Missing API Key",
29
+ text: "Please enter a custom API key"
30
+ });
31
+ return;
32
+ }
33
+
34
+ try {
35
+ const token = localStorage.getItem('dashx_token');
36
+ const response = await fetch('/api/user/profile', {
37
+ method: 'PUT',
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ 'Authorization': `Bearer ${token}`
41
+ },
42
+ body: JSON.stringify({ customApiKey })
43
+ });
44
+
45
+ const result = await response.json();
46
+
47
+ if (result.success) {
48
+ Swal.fire({
49
+ title: "API Key Updated!",
50
+ text: "Your custom API key has been set successfully",
51
+ icon: "success"
52
+ });
53
+ document.getElementById('customApiKeyInput').value = '';
54
+ loadUserProfile();
55
+ loadRecentActivity();
56
+ } else {
57
+ Swal.fire({
58
+ icon: "error",
59
+ title: "Update Failed",
60
+ text: result.error
61
+ });
62
+ }
63
+ } catch (error) {
64
+ Swal.fire({
65
+ icon: "error",
66
+ title: "Network Error",
67
+ text: "Please try again later"
68
+ });
69
+ }
70
+ }
71
+
72
+ async function loadUserProfile() {
73
+ try {
74
+ const token = localStorage.getItem('dashx_token');
75
+ const response = await fetch('/api/user/profile', {
76
+ headers: { 'Authorization': `Bearer ${token}` }
77
+ });
78
+
79
+ if (response.ok) {
80
+ const result = await response.json();
81
+ if (result.success) {
82
+ const user = result.user;
83
+ updateProfileDisplay(user);
84
+ }
85
+ } else {
86
+ logout();
87
+ }
88
+ } catch (error) {
89
+ console.error('Error loading profile:', error);
90
+ logout();
91
+ }
92
+ }
93
+
94
+ async function loadRecentActivity() {
95
+ try {
96
+ const token = localStorage.getItem('dashx_token');
97
+ const response = await fetch('/api/user/activities', {
98
+ headers: { 'Authorization': `Bearer ${token}` }
99
+ });
100
+
101
+ if (response.ok) {
102
+ const result = await response.json();
103
+ if (result.success) {
104
+ updateRecentActivity(result.activities);
105
+ }
106
+ }
107
+ } catch (error) {
108
+ console.error('Error loading activities:', error);
109
+ }
110
+ }
111
+
112
+ function updateRecentActivity(activities) {
113
+ const activityList = document.getElementById('recentActivity');
114
+
115
+ if (activities.length === 0) {
116
+ activityList.innerHTML = `
117
+ <div class="activity-item">
118
+ <i class="fas fa-info-circle" style="color: #74b9ff;"></i>
119
+ <span>No recent activity</span>
120
+ </div>
121
+ `;
122
+ return;
123
+ }
124
+
125
+ const activityIcons = {
126
+ 'api_key_generated': 'fas fa-key',
127
+ 'limit_updated': 'fas fa-chart-line',
128
+ 'profile_updated': 'fas fa-user-edit',
129
+ 'redeem_code_used': 'fas fa-gift',
130
+ 'premium_activated': 'fas fa-crown',
131
+ 'api_request': 'fas fa-code'
132
+ };
133
+
134
+ activityList.innerHTML = activities.map(activity => `
135
+ <div class="activity-item">
136
+ <i class="${activityIcons[activity.type] || 'fas fa-circle'}" style="color: #853030;"></i>
137
+ <div style="flex: 1;">
138
+ <span>${activity.description}</span>
139
+ <small style="display: block; opacity: 0.7; margin-top: 0.2rem;">${activity.timeAgo}</small>
140
+ </div>
141
+ </div>
142
+ `).join('');
143
+ }
144
+
145
+ function updateProfileDisplay(user) {
146
+ const usernameEl = document.getElementById('profileUsername');
147
+ const emailEl = document.getElementById('profileEmail');
148
+ const apikeyEl = document.getElementById('profileApiKey');
149
+ const requestsEl = document.getElementById('profileRequests');
150
+ const todayEl = document.getElementById('profileRequestsToday');
151
+ const limitEl = document.getElementById('profileLimit');
152
+ const roleEl = document.getElementById('profileRole');
153
+ const premiumBadge = document.getElementById('premiumBadge');
154
+ const adminBadge = document.getElementById('adminBadge');
155
+ const profileImage = document.getElementById('profileImage');
156
+ const defaultAvatar = document.getElementById('defaultAvatar');
157
+
158
+ if (usernameEl) usernameEl.textContent = user.username;
159
+ if (emailEl) emailEl.textContent = user.email;
160
+ if (apikeyEl) apikeyEl.textContent = user.apikey;
161
+ if (requestsEl) requestsEl.textContent = user.requests;
162
+ if (todayEl) todayEl.textContent = user.requestsToday;
163
+
164
+ if (user.profileUrl && profileImage && defaultAvatar) {
165
+ profileImage.src = user.profileUrl;
166
+ profileImage.style.display = 'block';
167
+ defaultAvatar.style.display = 'none';
168
+
169
+ profileImage.onerror = function() {
170
+ profileImage.style.display = 'none';
171
+ defaultAvatar.style.display = 'block';
172
+ };
173
+ }
174
+
175
+ if (limitEl) {
176
+ if (user.role === 'admin' && user.limit >= 9999) {
177
+ limitEl.textContent = '9999';
178
+ limitEl.style.fontSize = '2rem';
179
+ limitEl.style.color = '#853030';
180
+ } else {
181
+ limitEl.textContent = user.limit;
182
+ }
183
+ }
184
+
185
+ if (roleEl) {
186
+ roleEl.className = 'badge';
187
+
188
+ if (user.role === 'admin') {
189
+ roleEl.innerHTML = '<i class="fas fa-crown"></i> Admin';
190
+ roleEl.classList.add('admin');
191
+ if (adminBadge) adminBadge.style.display = 'inline-block';
192
+ } else {
193
+ if (user.userRole) {
194
+ switch(user.userRole) {
195
+ case 'cheap':
196
+ roleEl.innerHTML = '<i class="fas fa-tag"></i> Cheap';
197
+ roleEl.classList.add('cheap', 'glow-cheap');
198
+ break;
199
+ case 'premium':
200
+ roleEl.innerHTML = '<i class="fas fa-star"></i> Premium';
201
+ roleEl.classList.add('premium', 'glow-premium');
202
+ break;
203
+ case 'vip':
204
+ roleEl.innerHTML = '<i class="fas fa-gem"></i> VIP';
205
+ roleEl.classList.add('vip', 'glow-vip');
206
+ break;
207
+ case 'supreme':
208
+ roleEl.innerHTML = '<i class="fas fa-fire"></i> Supreme';
209
+ roleEl.classList.add('supreme', 'glow-supreme');
210
+ break;
211
+ default:
212
+ roleEl.innerHTML = '<i class="fas fa-user"></i> User';
213
+ roleEl.classList.add('user');
214
+ }
215
+ } else {
216
+ roleEl.innerHTML = '<i class="fas fa-user"></i> User';
217
+ roleEl.classList.add('user');
218
+ }
219
+ }
220
+ }
221
+
222
+ if (user.premium || user.role === 'admin' || user.userRole) {
223
+ if (premiumBadge) {
224
+ premiumBadge.style.display = 'inline-block';
225
+ premiumBadge.innerHTML = '<i class="fas fa-certificate"></i> Premium';
226
+ }
227
+ const premiumFeatures = document.getElementById('premiumFeatures');
228
+ if (premiumFeatures) premiumFeatures.style.display = 'block';
229
+ }
230
+
231
+ if (user.roleExpiresAt) {
232
+ const expiryDiv = document.getElementById('roleExpiry');
233
+ const expiryDate = document.getElementById('roleExpiryDate');
234
+ if (expiryDiv && expiryDate) {
235
+ expiryDiv.style.display = 'block';
236
+ const expDate = new Date(user.roleExpiresAt);
237
+ expiryDate.textContent = expDate.toLocaleDateString('en-US', {
238
+ year: 'numeric',
239
+ month: 'long',
240
+ day: 'numeric'
241
+ });
242
+
243
+ const daysLeft = Math.ceil((expDate - new Date()) / (1000 * 60 * 60 * 24));
244
+ if (daysLeft <= 7) {
245
+ expiryDiv.style.color = '#ff6b6b';
246
+ expiryDiv.innerHTML = `<i class="fas fa-exclamation-triangle"></i> Expires in ${daysLeft} days: <span id="roleExpiryDate"></span>`;
247
+ document.getElementById('roleExpiryDate').textContent = expDate.toLocaleDateString('en-US', {
248
+ year: 'numeric',
249
+ month: 'long',
250
+ day: 'numeric'
251
+ });
252
+ }
253
+ }
254
+ }
255
+
256
+ updateUsageProgress(user.requestsToday, user.limit);
257
+ }
258
+
259
+ function updateUsageProgress(current, limit) {
260
+ const progressFill = document.getElementById('usageProgress');
261
+ const progressText = document.getElementById('usageText');
262
+
263
+ if (!progressFill || !progressText) return;
264
+
265
+ if (limit >= 9999) {
266
+ progressFill.style.width = '0%';
267
+ progressFill.style.background = 'linear-gradient(90deg, #853030, #292727)';
268
+ progressText.textContent = `${current} / 9999`;
269
+ return;
270
+ }
271
+
272
+ const percentage = Math.min((current / limit) * 100, 100);
273
+ progressFill.style.width = percentage + '%';
274
+ progressText.textContent = `${current} / ${limit}`;
275
+
276
+ if (percentage >= 90) {
277
+ progressFill.style.background = 'linear-gradient(90deg, #ff6b6b, #ee5a52)';
278
+ } else if (percentage >= 70) {
279
+ progressFill.style.background = 'linear-gradient(90deg, #f093fb, #f5576c)';
280
+ } else {
281
+ progressFill.style.background = 'linear-gradient(90deg, #853030, #292727)';
282
+ }
283
+ }
284
+
285
+ function copyApiKey() {
286
+ const apiKey = document.getElementById('profileApiKey').textContent;
287
+ navigator.clipboard.writeText(apiKey).then(() => {
288
+ Swal.fire({
289
+ title: "Copied!",
290
+ text: "API key copied to clipboard",
291
+ icon: "success",
292
+ timer: 1500,
293
+ showConfirmButton: false
294
+ });
295
+ }).catch(() => {
296
+ Swal.fire({
297
+ icon: "error",
298
+ title: "Copy Failed",
299
+ text: "Could not copy to clipboard"
300
+ });
301
+ });
302
+ }
303
+
304
+ async function updateUsername() {
305
+ const newUsername = document.getElementById('newUsername').value.trim();
306
+
307
+ if (!newUsername) {
308
+ Swal.fire({
309
+ icon: "error",
310
+ title: "Missing Username",
311
+ text: "Please enter a new username"
312
+ });
313
+ return;
314
+ }
315
+
316
+ try {
317
+ const token = localStorage.getItem('dashx_token');
318
+ const response = await fetch('/api/user/profile', {
319
+ method: 'PUT',
320
+ headers: {
321
+ 'Content-Type': 'application/json',
322
+ 'Authorization': `Bearer ${token}`
323
+ },
324
+ body: JSON.stringify({ username: newUsername })
325
+ });
326
+
327
+ const result = await response.json();
328
+
329
+ if (result.success) {
330
+ Swal.fire({
331
+ title: "Username Updated!",
332
+ text: "Your username has been updated successfully",
333
+ icon: "success"
334
+ });
335
+ document.getElementById('newUsername').value = '';
336
+ loadUserProfile();
337
+ loadRecentActivity();
338
+ } else {
339
+ Swal.fire({
340
+ icon: "error",
341
+ title: "Update Failed",
342
+ text: result.error
343
+ });
344
+ }
345
+ } catch (error) {
346
+ Swal.fire({
347
+ icon: "error",
348
+ title: "Network Error",
349
+ text: "Please try again later"
350
+ });
351
+ }
352
+ }
353
+
354
+ async function updateProfileUrl() {
355
+ const profileUrl = document.getElementById('profileUrlInput').value.trim();
356
+
357
+ try {
358
+ const token = localStorage.getItem('dashx_token');
359
+ const response = await fetch('/api/user/profile', {
360
+ method: 'PUT',
361
+ headers: {
362
+ 'Content-Type': 'application/json',
363
+ 'Authorization': `Bearer ${token}`
364
+ },
365
+ body: JSON.stringify({ profileUrl })
366
+ });
367
+
368
+ const result = await response.json();
369
+
370
+ if (result.success) {
371
+ Swal.fire({
372
+ title: "Profile Updated!",
373
+ text: "Your profile picture has been updated successfully",
374
+ icon: "success"
375
+ });
376
+ document.getElementById('profileUrlInput').value = '';
377
+ loadUserProfile();
378
+ loadRecentActivity();
379
+ } else {
380
+ Swal.fire({
381
+ icon: "error",
382
+ title: "Update Failed",
383
+ text: result.error
384
+ });
385
+ }
386
+ } catch (error) {
387
+ Swal.fire({
388
+ icon: "error",
389
+ title: "Network Error",
390
+ text: "Please try again later"
391
+ });
392
+ }
393
+ }
394
+
395
+ async function regenerateApiKey() {
396
+ const result = await Swal.fire({
397
+ title: "Are you sure?",
398
+ text: "This will generate a new API key and invalidate the current one!",
399
+ icon: "warning",
400
+ showCancelButton: true,
401
+ confirmButtonColor: "#853030",
402
+ cancelButtonColor: "#292727",
403
+ confirmButtonText: "Yes, generate new key!",
404
+ cancelButtonText: "Cancel"
405
+ });
406
+
407
+ if (result.isConfirmed) {
408
+ try {
409
+ const token = localStorage.getItem('dashx_token');
410
+ const response = await fetch('/api/user/regenerate-key', {
411
+ method: 'POST',
412
+ headers: { 'Authorization': `Bearer ${token}` }
413
+ });
414
+
415
+ const apiResult = await response.json();
416
+
417
+ if (apiResult.success) {
418
+ Swal.fire({
419
+ title: "Key Regenerated!",
420
+ text: `New API Key: ${apiResult.apikey}`,
421
+ icon: "success"
422
+ });
423
+ loadUserProfile();
424
+ loadRecentActivity();
425
+ } else {
426
+ Swal.fire({
427
+ title: "Failed!",
428
+ text: apiResult.error,
429
+ icon: "error"
430
+ });
431
+ }
432
+ } catch (error) {
433
+ Swal.fire({
434
+ title: "Error!",
435
+ text: "Network error occurred",
436
+ icon: "error"
437
+ });
438
+ }
439
+ }
440
+ }
441
+
442
+ async function deleteAccount() {
443
+ const result = await Swal.fire({
444
+ title: "Are you sure?",
445
+ text: "You won't be able to revert this!",
446
+ icon: "warning",
447
+ showCancelButton: true,
448
+ confirmButtonColor: "#ff6b6b",
449
+ cancelButtonColor: "#853030",
450
+ confirmButtonText: "Yes, delete it!",
451
+ cancelButtonText: "Cancel"
452
+ });
453
+
454
+ if (result.isConfirmed) {
455
+ try {
456
+ const token = localStorage.getItem('dashx_token');
457
+ const response = await fetch('/api/user/account', {
458
+ method: 'DELETE',
459
+ headers: { 'Authorization': `Bearer ${token}` }
460
+ });
461
+
462
+ const apiResult = await response.json();
463
+
464
+ if (apiResult.success) {
465
+ await Swal.fire({
466
+ title: "Account Deleted!",
467
+ text: "Your account has been deleted.",
468
+ icon: "success"
469
+ });
470
+ logout();
471
+ } else {
472
+ Swal.fire({
473
+ title: "Failed!",
474
+ text: apiResult.error,
475
+ icon: "error"
476
+ });
477
+ }
478
+ } catch (error) {
479
+ Swal.fire({
480
+ title: "Error!",
481
+ text: "Network error occurred",
482
+ icon: "error"
483
+ });
484
+ }
485
+ }
486
+ }
487
+
488
+ function logout() {
489
+ localStorage.removeItem('dashx_token');
490
+ localStorage.removeItem('dashx_user');
491
+ window.location.href = '/';
492
+ }
public/styles.css ADDED
@@ -0,0 +1,2328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
2
+
3
+ * {
4
+ margin: 0;
5
+ padding: 0;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ :root {
10
+ --primary-gradient: linear-gradient(135deg, #FFA8A8 0%, #8D96FF 100%);
11
+ --secondary-gradient: linear-gradient(135deg, #FFA8A8 0%, #FFCECE 100%);
12
+ --success-gradient: linear-gradient(135deg, #8D96FF 0%, #B8BFFF 100%);
13
+ --danger-gradient: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
14
+ --warning-gradient: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
15
+ --glass-bg: rgba(255, 250, 240, 0.15);
16
+ --glass-border: rgba(255, 168, 168, 0.3);
17
+ --glass-hover: rgba(255, 250, 240, 0.25);
18
+ --text-primary: #1a1a1a;
19
+ --text-secondary: #333333;
20
+ --text-muted: #666666;
21
+ --text-disabled: #999999;
22
+ --shadow-sm: 0 2px 10px rgba(255, 168, 168, 0.2);
23
+ --shadow: 0 8px 32px rgba(255, 168, 168, 0.3);
24
+ --shadow-lg: 0 15px 50px rgba(255, 168, 168, 0.4);
25
+ --border-radius-sm: 8px;
26
+ --border-radius: 16px;
27
+ --border-radius-lg: 20px;
28
+ --border-radius-xl: 24px;
29
+ --border-radius-2xl: 32px;
30
+ --spacing-xs: 0.25rem;
31
+ --spacing-sm: 0.5rem;
32
+ --spacing-md: 1rem;
33
+ --spacing-lg: 1.5rem;
34
+ --spacing-xl: 2rem;
35
+ --spacing-2xl: 3rem;
36
+ --font-size-xs: 0.75rem;
37
+ --font-size-sm: 0.875rem;
38
+ --font-size-base: 1rem;
39
+ --font-size-lg: 1.125rem;
40
+ --font-size-xl: 1.25rem;
41
+ --font-size-2xl: 1.5rem;
42
+ --font-size-3xl: 2rem;
43
+ --font-size-4xl: 2.5rem;
44
+ --transition-fast: 0.15s ease;
45
+ --transition-base: 0.3s ease;
46
+ --transition-slow: 0.5s ease;
47
+ }
48
+
49
+ body {
50
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
51
+ background: linear-gradient(135deg, #FFFAF0 0%, #FFE8E8 50%, #E8ECFF 100%);
52
+ color: var(--text-primary);
53
+ min-height: 100vh;
54
+ line-height: 1.6;
55
+ overflow-x: hidden;
56
+ font-size: var(--font-size-base);
57
+ }
58
+
59
+ .plugins-search {
60
+ margin-bottom: 2rem;
61
+ }
62
+
63
+ .search-container {
64
+ position: relative;
65
+ max-width: 500px;
66
+ margin: 0 auto;
67
+ }
68
+
69
+ .search-container i.fa-search {
70
+ position: absolute;
71
+ left: 1rem;
72
+ top: 50%;
73
+ transform: translateY(-50%);
74
+ color: #8D96FF;
75
+ z-index: 1;
76
+ }
77
+
78
+ .tag-section {
79
+ margin-bottom: 2rem;
80
+ background: rgba(255, 255, 255, 0.03);
81
+ backdrop-filter: blur(5px);
82
+ border-radius: 16px;
83
+ border: 1px solid rgba(0, 0, 0, 0.4);
84
+ overflow: hidden;
85
+ transition: all 0.3s ease;
86
+ }
87
+
88
+ .tag-section:hover {
89
+ background: rgba(255, 255, 255, 0.05);
90
+ border: 1px solid rgba(0, 0, 0, 0.5);
91
+ }
92
+
93
+ .tag-header {
94
+ padding: 1.5rem;
95
+ cursor: pointer;
96
+ display: flex;
97
+ justify-content: space-between;
98
+ align-items: center;
99
+ transition: all 0.3s ease;
100
+ background: rgba(255, 255, 255, 0.02);
101
+ }
102
+
103
+ .tag-header:hover {
104
+ background: rgba(255, 255, 255, 0.05);
105
+ }
106
+
107
+ .tag-title {
108
+ display: flex;
109
+ align-items: center;
110
+ gap: 1rem;
111
+ font-size: 1.2rem;
112
+ font-weight: 600;
113
+ color: rgba(255, 255, 255, 0.9);
114
+ }
115
+
116
+ .tag-title i {
117
+ color: rgba(133, 48, 48, 0.9);
118
+ font-size: 1.3rem;
119
+ }
120
+
121
+ .plugin-count {
122
+ background: rgba(133, 48, 48, 0.2);
123
+ color: rgba(255, 168, 168, 0.9);
124
+ padding: 0.3rem 0.8rem;
125
+ border-radius: 12px;
126
+ font-size: 0.85rem;
127
+ font-weight: 500;
128
+ }
129
+
130
+ .tag-expand {
131
+ color: rgba(255, 255, 255, 0.6);
132
+ font-size: 1.2rem;
133
+ transition: transform 0.3s ease;
134
+ }
135
+
136
+ .tag-expand.expanded {
137
+ transform: rotate(180deg);
138
+ }
139
+
140
+ .tag-content {
141
+ max-height: 0;
142
+ overflow: hidden;
143
+ transition: max-height 0.4s ease;
144
+ padding: 0 1.5rem;
145
+ }
146
+
147
+ .tag-content.expanded {
148
+ max-height: 10000px;
149
+ padding: 1.5rem;
150
+ }
151
+
152
+ .tag-content .plugin-card {
153
+ margin-bottom: 1rem;
154
+ }
155
+
156
+ .tag-content .plugin-card:last-child {
157
+ margin-bottom: 0;
158
+ }
159
+
160
+ .search-container input {
161
+ width: 100%;
162
+ padding: 1rem 1rem 1rem 3rem;
163
+ border: 2px solid rgba(255, 168, 168, 0.3);
164
+ border-radius: 25px;
165
+ background: rgba(255, 255, 255, 0.5);
166
+ color: var(--text-primary);
167
+ font-size: 1rem;
168
+ transition: all 0.3s ease;
169
+ }
170
+
171
+ .search-container input:focus {
172
+ outline: none;
173
+ border-color: #FFA8A8;
174
+ background: rgba(255, 255, 255, 0.7);
175
+ box-shadow: 0 0 20px rgba(255, 168, 168, 0.3);
176
+ }
177
+
178
+ .search-container input::placeholder {
179
+ color: var(--text-muted);
180
+ }
181
+
182
+ .search-container button {
183
+ position: absolute;
184
+ right: 0.5rem;
185
+ top: 50%;
186
+ transform: translateY(-50%);
187
+ background: #FFA8A8;
188
+ border: none;
189
+ border-radius: 50%;
190
+ width: 2.5rem;
191
+ height: 2.5rem;
192
+ color: white;
193
+ cursor: pointer;
194
+ transition: all 0.3s ease;
195
+ }
196
+
197
+ .search-container button:hover {
198
+ background: #FF8E8E;
199
+ transform: translateY(-50%) scale(1.1);
200
+ }
201
+
202
+ .admin-card .ban-actions {
203
+ display: flex;
204
+ gap: 1rem;
205
+ margin-bottom: 1rem;
206
+ }
207
+
208
+ .admin-card .ban-actions .btn {
209
+ flex: 1;
210
+ padding: 0.75rem 1rem;
211
+ border: none;
212
+ border-radius: 8px;
213
+ font-weight: 500;
214
+ cursor: pointer;
215
+ transition: all 0.3s ease;
216
+ }
217
+
218
+ .admin-card .ban-actions .btn-danger {
219
+ background: #e74c3c;
220
+ color: white;
221
+ }
222
+
223
+ .admin-card .ban-actions .btn-danger:hover {
224
+ background: #c0392b;
225
+ transform: translateY(-2px);
226
+ }
227
+
228
+ .admin-card .ban-actions .btn-success {
229
+ background: #8D96FF;
230
+ color: white;
231
+ }
232
+
233
+ .admin-card .ban-actions .btn-success:hover {
234
+ background: #7580EE;
235
+ transform: translateY(-2px);
236
+ }
237
+
238
+ .ban-status {
239
+ padding: 1rem;
240
+ border-radius: 8px;
241
+ margin-top: 1rem;
242
+ font-weight: 500;
243
+ }
244
+
245
+ .ban-status.banned {
246
+ background: rgba(231, 76, 60, 0.1);
247
+ border: 1px solid #e74c3c;
248
+ color: #e74c3c;
249
+ }
250
+
251
+ .ban-status.active {
252
+ background: rgba(141, 150, 255, 0.1);
253
+ border: 1px solid #8D96FF;
254
+ color: #8D96FF;
255
+ }
256
+
257
+ .usage-timeline {
258
+ background: rgba(255, 255, 255, 0.5);
259
+ border-radius: 15px;
260
+ padding: 1.5rem;
261
+ margin-top: 1rem;
262
+ }
263
+
264
+ .timeline-item {
265
+ display: flex;
266
+ align-items: center;
267
+ padding: 0.75rem 0;
268
+ border-bottom: 1px solid rgba(255, 168, 168, 0.2);
269
+ }
270
+
271
+ .timeline-item:last-child {
272
+ border-bottom: none;
273
+ }
274
+
275
+ .timeline-icon {
276
+ width: 40px;
277
+ height: 40px;
278
+ border-radius: 50%;
279
+ background: linear-gradient(135deg, #FFA8A8, #8D96FF);
280
+ display: flex;
281
+ align-items: center;
282
+ justify-content: center;
283
+ color: white;
284
+ margin-right: 1rem;
285
+ }
286
+
287
+ .timeline-content {
288
+ flex: 1;
289
+ }
290
+
291
+ .timeline-title {
292
+ font-weight: 600;
293
+ color: var(--text-primary);
294
+ margin-bottom: 0.25rem;
295
+ }
296
+
297
+ .timeline-details {
298
+ font-size: 0.875rem;
299
+ color: var(--text-secondary);
300
+ }
301
+
302
+ .timeline-time {
303
+ font-size: 0.75rem;
304
+ color: var(--text-muted);
305
+ margin-left: auto;
306
+ }
307
+
308
+ body::before {
309
+ content: '';
310
+ position: fixed;
311
+ top: 0;
312
+ left: 0;
313
+ width: 100%;
314
+ height: 100%;
315
+ background:
316
+ radial-gradient(circle at 20% 80%, rgba(255, 168, 168, 0.3), transparent 50%),
317
+ radial-gradient(circle at 80% 20%, rgba(141, 150, 255, 0.3), transparent 50%),
318
+ radial-gradient(circle at 40% 40%, rgba(255, 250, 240, 0.3), transparent 50%);
319
+ z-index: -1;
320
+ animation: backgroundShift 20s ease-in-out infinite;
321
+ }
322
+
323
+ @keyframes backgroundShift {
324
+ 0%, 100% { opacity: 1; }
325
+ 50% { opacity: 0.8; }
326
+ }
327
+
328
+ .navbar {
329
+ background: rgba(255, 255, 255, 0.8);
330
+ backdrop-filter: blur(20px);
331
+ border-bottom: 1px solid var(--glass-border);
332
+ padding: var(--spacing-md) 0;
333
+ position: sticky;
334
+ top: 0;
335
+ z-index: 1000;
336
+ box-shadow: var(--shadow);
337
+ }
338
+
339
+ .nav-container {
340
+ max-width: 1400px;
341
+ margin: 0 auto;
342
+ padding: 0 var(--spacing-xl);
343
+ display: flex;
344
+ justify-content: space-between;
345
+ align-items: center;
346
+ }
347
+
348
+ .nav-brand h2 {
349
+ background: var(--primary-gradient);
350
+ -webkit-background-clip: text;
351
+ -webkit-text-fill-color: transparent;
352
+ font-size: var(--font-size-2xl);
353
+ font-weight: 800;
354
+ display: flex;
355
+ align-items: center;
356
+ gap: var(--spacing-sm);
357
+ letter-spacing: -0.02em;
358
+ }
359
+
360
+ .nav-brand a {
361
+ text-decoration: none;
362
+ }
363
+
364
+ .nav-menu {
365
+ display: flex;
366
+ gap: var(--spacing-xl);
367
+ align-items: center;
368
+ }
369
+
370
+ .nav-link {
371
+ color: var(--text-secondary);
372
+ text-decoration: none;
373
+ padding: var(--spacing-sm) var(--spacing-lg);
374
+ border-radius: var(--border-radius);
375
+ transition: var(--transition-base);
376
+ display: flex;
377
+ align-items: center;
378
+ gap: var(--spacing-sm);
379
+ font-weight: 500;
380
+ background: var(--glass-bg);
381
+ border: 1px solid transparent;
382
+ backdrop-filter: blur(10px);
383
+ font-size: var(--font-size-sm);
384
+ }
385
+
386
+ .nav-link:hover {
387
+ background: var(--glass-hover);
388
+ color: var(--text-primary);
389
+ transform: translateY(-2px);
390
+ box-shadow: var(--shadow-sm);
391
+ border-color: var(--glass-border);
392
+ }
393
+
394
+ .hero {
395
+ text-align: center;
396
+ padding: 8rem var(--spacing-xl) 6rem;
397
+ position: relative;
398
+ }
399
+
400
+ .hero-title {
401
+ font-size: clamp(2.5rem, 5vw, 4.5rem);
402
+ font-weight: 800;
403
+ margin-bottom: var(--spacing-lg);
404
+ background: linear-gradient(135deg, #FFA8A8, #8D96FF, #FFA8A8);
405
+ background-size: 300% 300%;
406
+ -webkit-background-clip: text;
407
+ -webkit-text-fill-color: transparent;
408
+ animation: gradientShift 6s ease-in-out infinite;
409
+ letter-spacing: -0.03em;
410
+ line-height: 1.1;
411
+ }
412
+
413
+ @keyframes gradientShift {
414
+ 0%, 100% { background-position: 0% 50%; }
415
+ 50% { background-position: 100% 50%; }
416
+ }
417
+
418
+ .hero-subtitle {
419
+ font-size: var(--font-size-xl);
420
+ margin-bottom: var(--spacing-2xl);
421
+ color: var(--text-secondary);
422
+ font-weight: 400;
423
+ max-width: 600px;
424
+ margin-left: auto;
425
+ margin-right: auto;
426
+ line-height: 1.5;
427
+ }
428
+
429
+ .hero-buttons {
430
+ display: flex;
431
+ gap: var(--spacing-lg);
432
+ justify-content: center;
433
+ flex-wrap: wrap;
434
+ }
435
+
436
+ .btn {
437
+ padding: var(--spacing-md) var(--spacing-xl);
438
+ border: none;
439
+ border-radius: var(--border-radius);
440
+ text-decoration: none;
441
+ font-weight: 600;
442
+ font-size: var(--font-size-base);
443
+ cursor: pointer;
444
+ transition: var(--transition-base);
445
+ display: inline-flex;
446
+ align-items: center;
447
+ gap: var(--spacing-sm);
448
+ position: relative;
449
+ overflow: hidden;
450
+ backdrop-filter: blur(10px);
451
+ border: 1px solid transparent;
452
+ font-family: inherit;
453
+ white-space: nowrap;
454
+ min-height: 48px;
455
+ }
456
+
457
+ .btn::before {
458
+ content: '';
459
+ position: absolute;
460
+ top: 0;
461
+ left: -100%;
462
+ width: 100%;
463
+ height: 100%;
464
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
465
+ transition: left 0.6s ease;
466
+ }
467
+
468
+ .btn:hover::before {
469
+ left: 100%;
470
+ }
471
+
472
+ .btn-primary {
473
+ background: var(--primary-gradient);
474
+ color: white;
475
+ box-shadow: 0 4px 20px rgba(255, 168, 168, 0.4);
476
+ }
477
+
478
+ .btn-primary:hover {
479
+ transform: translateY(-3px);
480
+ box-shadow: 0 8px 30px rgba(255, 168, 168, 0.5);
481
+ }
482
+
483
+ .btn-secondary {
484
+ background: var(--glass-bg);
485
+ color: var(--text-primary);
486
+ border-color: var(--glass-border);
487
+ }
488
+
489
+ .btn-secondary:hover {
490
+ background: var(--glass-hover);
491
+ transform: translateY(-3px);
492
+ box-shadow: var(--shadow);
493
+ }
494
+
495
+ .btn-warning {
496
+ background: var(--secondary-gradient);
497
+ color: white;
498
+ box-shadow: 0 4px 20px rgba(255, 168, 168, 0.4);
499
+ }
500
+
501
+ .btn-warning:hover {
502
+ transform: translateY(-3px);
503
+ box-shadow: 0 8px 30px rgba(255, 168, 168, 0.5);
504
+ }
505
+
506
+ .btn-danger {
507
+ background: var(--danger-gradient);
508
+ color: white;
509
+ box-shadow: 0 4px 20px rgba(250, 112, 154, 0.4);
510
+ }
511
+
512
+ .btn-danger:hover {
513
+ transform: translateY(-3px);
514
+ box-shadow: 0 8px 30px rgba(250, 112, 154, 0.5);
515
+ }
516
+
517
+ .btn-info {
518
+ background: var(--success-gradient);
519
+ color: white;
520
+ box-shadow: 0 4px 20px rgba(141, 150, 255, 0.4);
521
+ }
522
+
523
+ .btn-info:hover {
524
+ transform: translateY(-3px);
525
+ box-shadow: 0 8px 30px rgba(141, 150, 255, 0.5);
526
+ }
527
+
528
+ .btn-sm {
529
+ padding: var(--spacing-sm) var(--spacing-lg);
530
+ font-size: var(--font-size-sm);
531
+ min-height: 36px;
532
+ }
533
+
534
+ .btn:disabled {
535
+ opacity: 0.6;
536
+ cursor: not-allowed;
537
+ transform: none !important;
538
+ box-shadow: none !important;
539
+ }
540
+
541
+ .container {
542
+ max-width: 1400px;
543
+ margin: 0 auto;
544
+ padding: 0 var(--spacing-xl);
545
+ }
546
+
547
+ .features {
548
+ padding: 8rem 0;
549
+ background: rgba(255, 255, 255, 0.5);
550
+ backdrop-filter: blur(20px);
551
+ border-top: 1px solid var(--glass-border);
552
+ border-bottom: 1px solid var(--glass-border);
553
+ }
554
+
555
+ .section-title {
556
+ text-align: center;
557
+ font-size: var(--font-size-4xl);
558
+ margin-bottom: 4rem;
559
+ font-weight: 800;
560
+ position: relative;
561
+ background: var(--primary-gradient);
562
+ -webkit-background-clip: text;
563
+ -webkit-text-fill-color: transparent;
564
+ letter-spacing: -0.02em;
565
+ }
566
+
567
+ .section-title::after {
568
+ content: '';
569
+ position: absolute;
570
+ bottom: -15px;
571
+ left: 50%;
572
+ transform: translateX(-50%);
573
+ width: 100px;
574
+ height: 4px;
575
+ background: var(--primary-gradient);
576
+ border-radius: 2px;
577
+ }
578
+
579
+ .features-grid {
580
+ display: grid;
581
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
582
+ gap: 2.5rem;
583
+ }
584
+
585
+ .feature-card {
586
+ background: var(--glass-bg);
587
+ backdrop-filter: blur(20px);
588
+ border: 1px solid var(--glass-border);
589
+ border-radius: var(--border-radius-lg);
590
+ padding: var(--spacing-2xl);
591
+ text-align: center;
592
+ transition: var(--transition-slow);
593
+ position: relative;
594
+ overflow: hidden;
595
+ }
596
+
597
+ .feature-card::before {
598
+ content: '';
599
+ position: absolute;
600
+ top: 0;
601
+ left: 0;
602
+ right: 0;
603
+ height: 4px;
604
+ background: var(--primary-gradient);
605
+ opacity: 0;
606
+ transition: opacity var(--transition-base);
607
+ }
608
+
609
+ .feature-card:hover::before {
610
+ opacity: 1;
611
+ }
612
+
613
+ .feature-card:hover {
614
+ transform: translateY(-15px);
615
+ border-color: rgba(255, 168, 168, 0.6);
616
+ box-shadow: var(--shadow-lg);
617
+ background: var(--glass-hover);
618
+ }
619
+
620
+ .feature-icon {
621
+ font-size: 4rem;
622
+ margin-bottom: var(--spacing-xl);
623
+ background: var(--primary-gradient);
624
+ -webkit-background-clip: text;
625
+ -webkit-text-fill-color: transparent;
626
+ transition: transform var(--transition-base);
627
+ }
628
+
629
+ .feature-card:hover .feature-icon {
630
+ transform: scale(1.1) rotate(5deg);
631
+ }
632
+
633
+ .feature-card h3 {
634
+ font-size: var(--font-size-2xl);
635
+ margin-bottom: var(--spacing-lg);
636
+ font-weight: 700;
637
+ color: var(--text-primary);
638
+ }
639
+
640
+ .feature-card p {
641
+ color: var(--text-secondary);
642
+ line-height: 1.8;
643
+ font-size: var(--font-size-base);
644
+ }
645
+
646
+ .stats {
647
+ padding: 8rem 0;
648
+ position: relative;
649
+ }
650
+
651
+ .stats-grid {
652
+ display: grid;
653
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
654
+ gap: 2.5rem;
655
+ }
656
+
657
+ .stat-card {
658
+ background: var(--glass-bg);
659
+ backdrop-filter: blur(20px);
660
+ border: 1px solid var(--glass-border);
661
+ border-radius: var(--border-radius-lg);
662
+ padding: var(--spacing-2xl);
663
+ text-align: center;
664
+ transition: var(--transition-base);
665
+ position: relative;
666
+ overflow: hidden;
667
+ }
668
+
669
+ .stat-card::before {
670
+ content: '';
671
+ position: absolute;
672
+ top: 50%;
673
+ left: 50%;
674
+ transform: translate(-50%, -50%);
675
+ width: 200%;
676
+ height: 200%;
677
+ background: radial-gradient(circle, rgba(255, 168, 168, 0.15) 0%, transparent 70%);
678
+ opacity: 0;
679
+ transition: opacity var(--transition-base);
680
+ }
681
+
682
+ .stat-card:hover::before {
683
+ opacity: 1;
684
+ }
685
+
686
+ .stat-card:hover {
687
+ transform: translateY(-10px);
688
+ border-color: rgba(255, 168, 168, 0.6);
689
+ box-shadow: var(--shadow);
690
+ }
691
+
692
+ .stat-number {
693
+ font-size: 3.5rem;
694
+ font-weight: 800;
695
+ margin-bottom: var(--spacing-md);
696
+ background: var(--primary-gradient);
697
+ -webkit-background-clip: text;
698
+ -webkit-text-fill-color: transparent;
699
+ display: block;
700
+ position: relative;
701
+ z-index: 1;
702
+ line-height: 1.1;
703
+ }
704
+
705
+ .stat-label {
706
+ font-size: var(--font-size-lg);
707
+ color: var(--text-secondary);
708
+ font-weight: 500;
709
+ position: relative;
710
+ z-index: 1;
711
+ }
712
+
713
+ .auth-container {
714
+ min-height: 100vh;
715
+ display: flex;
716
+ align-items: center;
717
+ justify-content: center;
718
+ padding: var(--spacing-xl);
719
+ }
720
+
721
+ .auth-card {
722
+ background: rgba(255, 255, 255, 0.8);
723
+ backdrop-filter: blur(20px);
724
+ border: 1px solid var(--glass-border);
725
+ border-radius: var(--border-radius-xl);
726
+ padding: var(--spacing-2xl);
727
+ width: 100%;
728
+ max-width: 480px;
729
+ box-shadow: var(--shadow);
730
+ position: relative;
731
+ overflow: hidden;
732
+ }
733
+
734
+ .auth-card::before {
735
+ content: '';
736
+ position: absolute;
737
+ top: 0;
738
+ left: 0;
739
+ right: 0;
740
+ height: 4px;
741
+ background: var(--primary-gradient);
742
+ }
743
+
744
+ .auth-tabs {
745
+ display: flex;
746
+ margin-bottom: 2.5rem;
747
+ background: rgba(255, 168, 168, 0.1);
748
+ border-radius: var(--border-radius);
749
+ padding: 0.4rem;
750
+ border: 1px solid var(--glass-border);
751
+ }
752
+
753
+ .tab-btn {
754
+ flex: 1;
755
+ padding: var(--spacing-md) var(--spacing-sm);
756
+ border: none;
757
+ background: transparent;
758
+ color: var(--text-muted);
759
+ border-radius: 12px;
760
+ cursor: pointer;
761
+ transition: var(--transition-base);
762
+ font-weight: 600;
763
+ display: flex;
764
+ align-items: center;
765
+ justify-content: center;
766
+ gap: var(--spacing-sm);
767
+ font-size: var(--font-size-sm);
768
+ min-height: 44px;
769
+ }
770
+
771
+ .tab-btn.active {
772
+ background: var(--primary-gradient);
773
+ color: white;
774
+ box-shadow: 0 4px 15px rgba(255, 168, 168, 0.3);
775
+ }
776
+
777
+ .auth-form h2 {
778
+ text-align: center;
779
+ margin-bottom: 2.5rem;
780
+ font-size: var(--font-size-3xl);
781
+ font-weight: 700;
782
+ background: var(--primary-gradient);
783
+ -webkit-background-clip: text;
784
+ -webkit-text-fill-color: transparent;
785
+ display: flex;
786
+ align-items: center;
787
+ justify-content: center;
788
+ gap: var(--spacing-sm);
789
+ }
790
+
791
+ .form-group {
792
+ margin-bottom: 1.8rem;
793
+ }
794
+
795
+ .form-group label {
796
+ display: block;
797
+ margin-bottom: var(--spacing-sm);
798
+ font-weight: 600;
799
+ color: var(--text-primary);
800
+ display: flex;
801
+ align-items: center;
802
+ gap: var(--spacing-sm);
803
+ font-size: var(--font-size-sm);
804
+ }
805
+
806
+ .form-group input,
807
+ .form-group select {
808
+ width: 100%;
809
+ padding: 1.2rem 1.5rem;
810
+ border: 1px solid var(--glass-border);
811
+ border-radius: var(--border-radius);
812
+ background: rgba(255, 255, 255, 0.6);
813
+ color: var(--text-primary);
814
+ font-size: var(--font-size-base);
815
+ transition: var(--transition-base);
816
+ backdrop-filter: blur(10px);
817
+ font-weight: 500;
818
+ min-height: 52px;
819
+ }
820
+
821
+ .form-group input::placeholder {
822
+ color: var(--text-muted);
823
+ }
824
+
825
+ .form-group input:focus,
826
+ .form-group select:focus {
827
+ outline: none;
828
+ border-color: #FFA8A8;
829
+ box-shadow: 0 0 0 3px rgba(255, 168, 168, 0.2);
830
+ background: rgba(255, 255, 255, 0.8);
831
+ }
832
+
833
+ .dashboard-container {
834
+ display: flex;
835
+ min-height: calc(100vh - 80px);
836
+ }
837
+
838
+ .sidebar {
839
+ width: 280px;
840
+ background: rgba(255, 255, 255, 0.8);
841
+ backdrop-filter: blur(20px);
842
+ border-right: 1px solid var(--glass-border);
843
+ padding: var(--spacing-xl) 0;
844
+ position: sticky;
845
+ top: 80px;
846
+ height: calc(100vh - 80px);
847
+ overflow-y: auto;
848
+ }
849
+
850
+ .sidebar-menu {
851
+ display: flex;
852
+ flex-direction: column;
853
+ gap: var(--spacing-sm);
854
+ padding: 0 var(--spacing-lg);
855
+ }
856
+
857
+ .menu-item {
858
+ display: flex;
859
+ align-items: center;
860
+ gap: var(--spacing-md);
861
+ padding: 1.2rem var(--spacing-lg);
862
+ color: var(--text-muted);
863
+ text-decoration: none;
864
+ border-radius: var(--border-radius);
865
+ transition: var(--transition-base);
866
+ font-weight: 500;
867
+ position: relative;
868
+ background: transparent;
869
+ border: 1px solid transparent;
870
+ min-height: 52px;
871
+ }
872
+
873
+ .menu-item::before {
874
+ content: '';
875
+ position: absolute;
876
+ left: 0;
877
+ top: 50%;
878
+ transform: translateY(-50%);
879
+ width: 4px;
880
+ height: 0;
881
+ background: var(--primary-gradient);
882
+ border-radius: 2px;
883
+ transition: height var(--transition-base);
884
+ }
885
+
886
+ .menu-item:hover,
887
+ .menu-item.active {
888
+ background: var(--glass-bg);
889
+ color: var(--text-primary);
890
+ transform: translateX(8px);
891
+ border-color: var(--glass-border);
892
+ }
893
+
894
+ .menu-item:hover::before,
895
+ .menu-item.active::before {
896
+ height: 30px;
897
+ }
898
+
899
+ .main-content {
900
+ flex: 1;
901
+ padding: 2.5rem;
902
+ overflow-y: auto;
903
+ max-width: calc(100vw - 280px);
904
+ }
905
+
906
+ .section {
907
+ display: none;
908
+ animation: fadeInUp var(--transition-slow);
909
+ }
910
+
911
+ .section.active {
912
+ display: block;
913
+ }
914
+
915
+ @keyframes fadeInUp {
916
+ from {
917
+ opacity: 0;
918
+ transform: translateY(20px);
919
+ }
920
+ to {
921
+ opacity: 1;
922
+ transform: translateY(0);
923
+ }
924
+ }
925
+
926
+ .section h2 {
927
+ font-size: 2.8rem;
928
+ margin-bottom: 2.5rem;
929
+ font-weight: 800;
930
+ background: var(--primary-gradient);
931
+ -webkit-background-clip: text;
932
+ -webkit-text-fill-color: transparent;
933
+ display: flex;
934
+ align-items: center;
935
+ gap: var(--spacing-sm);
936
+ letter-spacing: -0.02em;
937
+ }
938
+
939
+ .stats-cards {
940
+ display: grid;
941
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
942
+ gap: var(--spacing-xl);
943
+ margin-bottom: var(--spacing-2xl);
944
+ }
945
+
946
+ .stats-cards .stat-card {
947
+ display: flex;
948
+ align-items: center;
949
+ gap: var(--spacing-xl);
950
+ padding: 2.5rem;
951
+ text-align: left;
952
+ background: var(--glass-bg);
953
+ backdrop-filter: blur(20px);
954
+ border: 1px solid var(--glass-border);
955
+ border-radius: var(--border-radius-lg);
956
+ box-shadow: var(--shadow);
957
+ transition: var(--transition-base);
958
+ }
959
+
960
+ .stats-cards .stat-card:hover {
961
+ transform: translateY(-5px);
962
+ box-shadow: var(--shadow-lg);
963
+ }
964
+
965
+ .stat-icon {
966
+ font-size: var(--font-size-4xl);
967
+ background: var(--primary-gradient);
968
+ -webkit-background-clip: text;
969
+ -webkit-text-fill-color: transparent;
970
+ background: var(--glass-bg);
971
+ padding: var(--spacing-lg);
972
+ border-radius: var(--border-radius);
973
+ border: 1px solid var(--glass-border);
974
+ display: flex;
975
+ align-items: center;
976
+ justify-content: center;
977
+ min-width: 80px;
978
+ height: 80px;
979
+ }
980
+
981
+ .stat-info {
982
+ flex: 1;
983
+ }
984
+
985
+ .stat-info .stat-number {
986
+ font-size: 2.5rem;
987
+ margin-bottom: var(--spacing-sm);
988
+ background: var(--primary-gradient);
989
+ -webkit-background-clip: text;
990
+ -webkit-text-fill-color: transparent;
991
+ font-weight: 800;
992
+ line-height: 1.1;
993
+ }
994
+
995
+ .stat-info .stat-label {
996
+ font-size: var(--font-size-base);
997
+ color: var(--text-secondary);
998
+ font-weight: 500;
999
+ }
1000
+
1001
+ .plugin-form {
1002
+ background: rgba(255, 255, 255, 0.4);
1003
+ border-radius: var(--border-radius);
1004
+ padding: var(--spacing-xl);
1005
+ border: 1px solid var(--glass-border);
1006
+ }
1007
+
1008
+ .form-title {
1009
+ color: var(--text-primary);
1010
+ font-size: var(--font-size-xl);
1011
+ font-weight: 700;
1012
+ margin-bottom: var(--spacing-xl);
1013
+ display: flex;
1014
+ align-items: center;
1015
+ gap: var(--spacing-sm);
1016
+ }
1017
+
1018
+ .form-grid {
1019
+ display: grid;
1020
+ gap: var(--spacing-lg);
1021
+ margin-bottom: var(--spacing-xl);
1022
+ }
1023
+
1024
+ .form-field {
1025
+ display: flex;
1026
+ flex-direction: column;
1027
+ gap: var(--spacing-sm);
1028
+ }
1029
+
1030
+ .form-field label {
1031
+ color: var(--text-primary);
1032
+ font-weight: 600;
1033
+ font-size: var(--font-size-sm);
1034
+ display: flex;
1035
+ align-items: center;
1036
+ gap: var(--spacing-xs);
1037
+ }
1038
+
1039
+ .form-field label .required {
1040
+ color: #ff6b6b;
1041
+ font-size: var(--font-size-lg);
1042
+ }
1043
+
1044
+ .form-field input,
1045
+ .form-field select {
1046
+ background: rgba(255, 255, 255, 0.6);
1047
+ border: 1px solid var(--glass-border);
1048
+ border-radius: var(--border-radius);
1049
+ padding: var(--spacing-md) var(--spacing-lg);
1050
+ color: var(--text-primary);
1051
+ font-size: var(--font-size-sm);
1052
+ transition: var(--transition-base);
1053
+ backdrop-filter: blur(10px);
1054
+ min-height: 48px;
1055
+ }
1056
+
1057
+ .form-field input::placeholder {
1058
+ color: var(--text-muted);
1059
+ }
1060
+
1061
+ .form-field input:focus,
1062
+ .form-field select:focus {
1063
+ outline: none;
1064
+ border-color: #FFA8A8;
1065
+ box-shadow: 0 0 0 3px rgba(255, 168, 168, 0.2);
1066
+ background: rgba(255, 255, 255, 0.8);
1067
+ }
1068
+
1069
+ .form-actions {
1070
+ display: flex;
1071
+ gap: var(--spacing-lg);
1072
+ align-items: center;
1073
+ flex-wrap: wrap;
1074
+ }
1075
+
1076
+ .form-row {
1077
+ display: grid;
1078
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
1079
+ gap: var(--spacing-lg);
1080
+ margin-bottom: var(--spacing-xl);
1081
+ }
1082
+
1083
+ .input-group {
1084
+ display: flex;
1085
+ gap: var(--spacing-md);
1086
+ align-items: end;
1087
+ flex-wrap: wrap;
1088
+ }
1089
+
1090
+ .input-group input {
1091
+ flex: 1;
1092
+ min-width: 200px;
1093
+ }
1094
+
1095
+ .loading-spinner {
1096
+ width: 20px;
1097
+ height: 20px;
1098
+ border: 2px solid rgba(255, 168, 168, 0.3);
1099
+ border-radius: 50%;
1100
+ border-top-color: #FFA8A8;
1101
+ animation: spin 1s linear infinite;
1102
+ }
1103
+
1104
+ @keyframes spin {
1105
+ to { transform: rotate(360deg); }
1106
+ }
1107
+
1108
+ .loading {
1109
+ text-align: center;
1110
+ padding: var(--spacing-2xl);
1111
+ color: var(--text-muted);
1112
+ font-size: var(--font-size-lg);
1113
+ }
1114
+
1115
+ .response-container {
1116
+ margin-top: var(--spacing-xl);
1117
+ display: none;
1118
+ border-radius: var(--border-radius);
1119
+ overflow: hidden;
1120
+ }
1121
+
1122
+ .response-container.show {
1123
+ display: block;
1124
+ animation: fadeIn var(--transition-base);
1125
+ }
1126
+
1127
+ @keyframes fadeIn {
1128
+ from { opacity: 0; transform: translateY(10px); }
1129
+ to { opacity: 1; transform: translateY(0); }
1130
+ }
1131
+
1132
+ .response-header {
1133
+ display: flex;
1134
+ justify-content: space-between;
1135
+ align-items: center;
1136
+ margin-bottom: var(--spacing-md);
1137
+ flex-wrap: wrap;
1138
+ gap: var(--spacing-md);
1139
+ }
1140
+
1141
+ .response-title {
1142
+ color: var(--text-primary);
1143
+ font-weight: 700;
1144
+ display: flex;
1145
+ align-items: center;
1146
+ gap: var(--spacing-sm);
1147
+ font-size: var(--font-size-lg);
1148
+ }
1149
+
1150
+ .response-status {
1151
+ padding: var(--spacing-xs) var(--spacing-md);
1152
+ border-radius: 15px;
1153
+ font-size: var(--font-size-xs);
1154
+ font-weight: 600;
1155
+ text-transform: uppercase;
1156
+ letter-spacing: 0.5px;
1157
+ }
1158
+
1159
+ .response-status.success {
1160
+ background: rgba(141, 150, 255, 0.2);
1161
+ color: #8D96FF;
1162
+ border: 1px solid rgba(141, 150, 255, 0.4);
1163
+ }
1164
+
1165
+ .response-status.error {
1166
+ background: rgba(250, 112, 154, 0.2);
1167
+ color: #fa709a;
1168
+ border: 1px solid rgba(250, 112, 154, 0.4);
1169
+ }
1170
+
1171
+ .response-body {
1172
+ background: rgba(255, 255, 255, 0.5);
1173
+ border-radius: var(--border-radius);
1174
+ padding: var(--spacing-lg);
1175
+ font-family: 'JetBrains Mono', monospace;
1176
+ font-size: var(--font-size-sm);
1177
+ white-space: pre-wrap;
1178
+ color: #1a1a1a;
1179
+ border: 1px solid var(--glass-border);
1180
+ max-height: 400px;
1181
+ overflow-y: auto;
1182
+ line-height: 1.5;
1183
+ }
1184
+
1185
+ .copy-btn {
1186
+ background: rgba(255, 168, 168, 0.2);
1187
+ border: 1px solid rgba(255, 168, 168, 0.4);
1188
+ color: #FFA8A8;
1189
+ padding: var(--spacing-sm) var(--spacing-md);
1190
+ border-radius: var(--border-radius);
1191
+ font-size: var(--font-size-xs);
1192
+ cursor: pointer;
1193
+ transition: var(--transition-base);
1194
+ display: flex;
1195
+ align-items: center;
1196
+ gap: var(--spacing-xs);
1197
+ min-height: 32px;
1198
+ }
1199
+
1200
+ .copy-btn:hover {
1201
+ background: rgba(255, 168, 168, 0.35);
1202
+ transform: translateY(-2px);
1203
+ }
1204
+
1205
+ .plugins-grid {
1206
+ display: grid;
1207
+ grid-template-columns: 1fr;
1208
+ gap: var(--spacing-xl);
1209
+ }
1210
+
1211
+ .plugin-card {
1212
+ background: var(--glass-bg);
1213
+ backdrop-filter: blur(20px);
1214
+ border: 1px solid var(--glass-border);
1215
+ border-radius: var(--border-radius-lg);
1216
+ overflow: hidden;
1217
+ transition: var(--transition-slow);
1218
+ box-shadow: var(--shadow);
1219
+ }
1220
+
1221
+ .plugin-card:hover {
1222
+ border-color: rgba(255, 168, 168, 0.6);
1223
+ transform: translateY(-5px);
1224
+ box-shadow: var(--shadow-lg);
1225
+ }
1226
+
1227
+ .plugin-card.expanded {
1228
+ border-color: rgba(255, 168, 168, 0.8);
1229
+ box-shadow: var(--shadow-lg);
1230
+ }
1231
+
1232
+ .plugin-header {
1233
+ display: flex;
1234
+ justify-content: space-between;
1235
+ align-items: center;
1236
+ padding: var(--spacing-xl);
1237
+ cursor: pointer;
1238
+ user-select: none;
1239
+ transition: background var(--transition-base);
1240
+ min-height: 80px;
1241
+ }
1242
+
1243
+ .plugin-header:hover {
1244
+ background: rgba(255, 255, 255, 0.3);
1245
+ }
1246
+
1247
+ .plugin-left {
1248
+ display: flex;
1249
+ align-items: center;
1250
+ gap: var(--spacing-md);
1251
+ flex: 1;
1252
+ }
1253
+
1254
+ .plugin-name {
1255
+ font-size: var(--font-size-xl);
1256
+ font-weight: 700;
1257
+ color: var(--text-primary);
1258
+ margin-bottom: var(--spacing-sm);
1259
+ }
1260
+
1261
+ .plugin-description {
1262
+ color: var(--text-secondary);
1263
+ font-size: var(--font-size-base);
1264
+ line-height: 1.5;
1265
+ }
1266
+
1267
+ .plugin-type {
1268
+ background: var(--primary-gradient);
1269
+ color: white;
1270
+ padding: var(--spacing-sm) var(--spacing-md);
1271
+ border-radius: 20px;
1272
+ font-size: var(--font-size-xs);
1273
+ font-weight: 600;
1274
+ text-transform: uppercase;
1275
+ letter-spacing: 0.5px;
1276
+ box-shadow: 0 2px 10px rgba(255, 168, 168, 0.3);
1277
+ white-space: nowrap;
1278
+ min-height: 32px;
1279
+ display: flex;
1280
+ align-items: center;
1281
+ }
1282
+
1283
+ .plugin-expand {
1284
+ font-size: var(--font-size-2xl);
1285
+ color: var(--text-muted);
1286
+ transition: var(--transition-base);
1287
+ margin-left: var(--spacing-md);
1288
+ }
1289
+
1290
+ .plugin-expand.expanded {
1291
+ transform: rotate(180deg);
1292
+ color: #FFA8A8;
1293
+ }
1294
+
1295
+ .plugin-content {
1296
+ display: none;
1297
+ border-top: 1px solid var(--glass-border);
1298
+ background: rgba(255, 255, 255, 0.3);
1299
+ }
1300
+
1301
+ .plugin-content.expanded {
1302
+ display: block;
1303
+ animation: slideDown var(--transition-base);
1304
+ }
1305
+
1306
+ @keyframes slideDown {
1307
+ from { opacity: 0; max-height: 0; }
1308
+ to { opacity: 1; max-height: 1000px; }
1309
+ }
1310
+
1311
+ .plugin-details {
1312
+ padding: var(--spacing-xl);
1313
+ }
1314
+
1315
+ .plugin-tags {
1316
+ display: flex;
1317
+ flex-wrap: wrap;
1318
+ gap: var(--spacing-sm);
1319
+ margin-bottom: var(--spacing-lg);
1320
+ }
1321
+
1322
+ .tag {
1323
+ background: rgba(255, 168, 168, 0.2);
1324
+ color: #FFA8A8;
1325
+ padding: var(--spacing-xs) var(--spacing-md);
1326
+ border-radius: 15px;
1327
+ font-size: var(--font-size-xs);
1328
+ font-weight: 500;
1329
+ border: 1px solid rgba(255, 168, 168, 0.3);
1330
+ transition: var(--transition-base);
1331
+ min-height: 28px;
1332
+ display: flex;
1333
+ align-items: center;
1334
+ }
1335
+
1336
+ .tag:hover {
1337
+ background: rgba(255, 168, 168, 0.35);
1338
+ transform: translateY(-2px);
1339
+ }
1340
+
1341
+ .plugin-routes {
1342
+ background: rgba(255, 255, 255, 0.4);
1343
+ padding: var(--spacing-lg);
1344
+ border-radius: var(--border-radius);
1345
+ font-family: 'JetBrains Mono', monospace;
1346
+ font-size: var(--font-size-sm);
1347
+ color: #1a1a1a;
1348
+ border: 1px solid var(--glass-border);
1349
+ overflow-x: auto;
1350
+ margin-bottom: var(--spacing-lg);
1351
+ }
1352
+
1353
+ .btn-execute {
1354
+ background: var(--primary-gradient);
1355
+ color: white;
1356
+ border: none;
1357
+ padding: var(--spacing-md) var(--spacing-xl);
1358
+ border-radius: var(--border-radius);
1359
+ font-weight: 600;
1360
+ cursor: pointer;
1361
+ transition: var(--transition-base);
1362
+ display: flex;
1363
+ align-items: center;
1364
+ gap: var(--spacing-sm);
1365
+ font-size: var(--font-size-base);
1366
+ box-shadow: 0 4px 20px rgba(255, 168, 168, 0.3);
1367
+ min-height: 48px;
1368
+ }
1369
+
1370
+ .btn-execute:hover:not(:disabled) {
1371
+ transform: translateY(-3px);
1372
+ box-shadow: 0 8px 30px rgba(255, 168, 168, 0.4);
1373
+ }
1374
+
1375
+ .btn-execute:disabled {
1376
+ opacity: 0.6;
1377
+ cursor: not-allowed;
1378
+ transform: none !important;
1379
+ box-shadow: none !important;
1380
+ }
1381
+
1382
+ .btn-reset {
1383
+ background: var(--glass-bg);
1384
+ color: var(--text-secondary);
1385
+ border: 1px solid var(--glass-border);
1386
+ padding: var(--spacing-md) var(--spacing-xl);
1387
+ border-radius: var(--border-radius);
1388
+ font-weight: 500;
1389
+ cursor: pointer;
1390
+ transition: var(--transition-base);
1391
+ display: flex;
1392
+ align-items: center;
1393
+ gap: var(--spacing-sm);
1394
+ font-size: var(--font-size-base);
1395
+ backdrop-filter: blur(10px);
1396
+ min-height: 48px;
1397
+ }
1398
+
1399
+ .btn-reset:hover {
1400
+ background: var(--glass-hover);
1401
+ color: var(--text-primary);
1402
+ transform: translateY(-2px);
1403
+ }
1404
+
1405
+ .events-container {
1406
+ max-width: 600px;
1407
+ }
1408
+
1409
+ .profile-container {
1410
+ max-width: 1000px;
1411
+ margin: var(--spacing-xl) auto;
1412
+ padding: 0 var(--spacing-xl);
1413
+ }
1414
+
1415
+ .profile-header {
1416
+ background: var(--glass-bg);
1417
+ backdrop-filter: blur(20px);
1418
+ border: 1px solid var(--glass-border);
1419
+ border-radius: var(--border-radius-xl);
1420
+ padding: var(--spacing-2xl);
1421
+ text-align: center;
1422
+ margin-bottom: var(--spacing-xl);
1423
+ position: relative;
1424
+ overflow: hidden;
1425
+ box-shadow: var(--shadow);
1426
+ }
1427
+
1428
+ .profile-header::before {
1429
+ content: '';
1430
+ position: absolute;
1431
+ top: 0;
1432
+ left: 0;
1433
+ right: 0;
1434
+ height: 4px;
1435
+ background: var(--primary-gradient);
1436
+ }
1437
+
1438
+ .profile-avatar {
1439
+ font-size: 6rem;
1440
+ background: var(--primary-gradient);
1441
+ -webkit-background-clip: text;
1442
+ -webkit-text-fill-color: transparent;
1443
+ margin-bottom: var(--spacing-xl);
1444
+ background: var(--glass-bg);
1445
+ width: 140px;
1446
+ height: 140px;
1447
+ border-radius: 50%;
1448
+ display: flex;
1449
+ align-items: center;
1450
+ justify-content: center;
1451
+ margin: 0 auto var(--spacing-xl);
1452
+ border: 3px solid var(--glass-border);
1453
+ backdrop-filter: blur(10px);
1454
+ overflow: hidden;
1455
+ }
1456
+
1457
+ .profile-avatar img {
1458
+ width: 100%;
1459
+ height: 100%;
1460
+ border-radius: 50%;
1461
+ object-fit: cover;
1462
+ }
1463
+
1464
+ .profile-info h2 {
1465
+ font-size: 2.5rem;
1466
+ margin-bottom: var(--spacing-md);
1467
+ font-weight: 800;
1468
+ background: var(--primary-gradient);
1469
+ -webkit-background-clip: text;
1470
+ -webkit-text-fill-color: transparent;
1471
+ line-height: 1.1;
1472
+ }
1473
+
1474
+ .badge {
1475
+ display: inline-flex;
1476
+ align-items: center;
1477
+ justify-content: center;
1478
+ padding: var(--spacing-sm) var(--spacing-lg);
1479
+ border-radius: 20px;
1480
+ font-size: var(--font-size-xs);
1481
+ font-weight: 600;
1482
+ margin: var(--spacing-xs);
1483
+ min-height: 32px;
1484
+ text-transform: uppercase;
1485
+ letter-spacing: 0.5px;
1486
+ backdrop-filter: blur(10px);
1487
+ -webkit-backdrop-filter: blur(10px);
1488
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
1489
+ transition: all 0.3s ease;
1490
+ border: 1px solid;
1491
+ }
1492
+
1493
+ .badge:hover {
1494
+ transform: translateY(-1px);
1495
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
1496
+ }
1497
+
1498
+ .badge.user {
1499
+ background: rgba(255, 168, 168, 0.2);
1500
+ color: #FFA8A8;
1501
+ border-color: rgba(255, 168, 168, 0.3);
1502
+ }
1503
+
1504
+ .badge.cheap {
1505
+ background: linear-gradient(135deg, rgba(184, 127, 13, 0.95), rgba(184, 127, 13, 0.75));
1506
+ color: white;
1507
+ border-color: rgba(184, 127, 13, 0.4);
1508
+ box-shadow: 0 2px 8px rgba(184, 127, 13, 0.3);
1509
+ }
1510
+
1511
+ .badge.cheap:hover {
1512
+ background: linear-gradient(135deg, rgba(184, 127, 13, 1), rgba(184, 127, 13, 0.85));
1513
+ box-shadow: 0 4px 12px rgba(184, 127, 13, 0.45);
1514
+ }
1515
+
1516
+ .badge.premium {
1517
+ background: var(--secondary-gradient);
1518
+ color: white;
1519
+ border-color: rgba(255, 168, 168, 0.3);
1520
+ box-shadow: 0 2px 8px rgba(255, 168, 168, 0.3);
1521
+ }
1522
+
1523
+ .badge.premium:hover {
1524
+ background: linear-gradient(135deg, #ffa8a8, #ff8b8b);
1525
+ box-shadow: 0 4px 12px rgba(255, 168, 168, 0.45);
1526
+ }
1527
+
1528
+ .badge.vip {
1529
+ background: linear-gradient(135deg, rgba(255, 191, 0, 0.95), rgba(255, 191, 0, 0.75));
1530
+ color: #1a1a1a;
1531
+ border-color: rgba(255, 191, 0, 0.4);
1532
+ box-shadow: 0 2px 8px rgba(255, 191, 0, 0.3);
1533
+ font-weight: 700;
1534
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
1535
+ }
1536
+
1537
+ .badge.vip:hover {
1538
+ background: linear-gradient(135deg, rgba(255, 191, 0, 1), rgba(255, 191, 0, 0.85));
1539
+ box-shadow: 0 4px 12px rgba(255, 191, 0, 0.45);
1540
+ }
1541
+
1542
+ .badge.supreme {
1543
+ background: linear-gradient(135deg, rgba(238, 62, 75, 0.95), rgba(238, 62, 75, 0.75));
1544
+ color: white;
1545
+ border-color: rgba(238, 62, 75, 0.4);
1546
+ box-shadow: 0 2px 8px rgba(238, 62, 75, 0.3);
1547
+ font-weight: 700;
1548
+ }
1549
+
1550
+ .badge.supreme:hover {
1551
+ background: linear-gradient(135deg, rgba(238, 62, 75, 1), rgba(238, 62, 75, 0.85));
1552
+ box-shadow: 0 4px 12px rgba(238, 62, 75, 0.45);
1553
+ }
1554
+
1555
+ .badge.admin {
1556
+ background: linear-gradient(135deg, #853030 0%, #292727 100%);
1557
+ color: white;
1558
+ border-color: rgba(133, 48, 48, 0.4);
1559
+ box-shadow: 0 2px 8px rgba(133, 48, 48, 0.3);
1560
+ font-weight: 700;
1561
+ }
1562
+
1563
+ .badge.admin:hover {
1564
+ background: linear-gradient(135deg, #9a3838 0%, #353535 100%);
1565
+ box-shadow: 0 4px 12px rgba(133, 48, 48, 0.45);
1566
+ }
1567
+
1568
+ .badge i {
1569
+ margin-right: 0.35rem;
1570
+ font-size: 0.85em;
1571
+ }
1572
+
1573
+ .badge.glow-cheap {
1574
+ animation: glowCheap 2s ease-in-out infinite;
1575
+ }
1576
+
1577
+ .badge.glow-premium {
1578
+ animation: glowPremium 2s ease-in-out infinite;
1579
+ }
1580
+
1581
+ .badge.glow-vip {
1582
+ animation: glowVip 2s ease-in-out infinite;
1583
+ }
1584
+
1585
+ .badge.glow-supreme {
1586
+ animation: glowSupreme 2s ease-in-out infinite;
1587
+ }
1588
+
1589
+ @keyframes glowCheap {
1590
+ 0%, 100% {
1591
+ box-shadow: 0 2px 8px rgba(184, 127, 13, 0.3);
1592
+ }
1593
+ 50% {
1594
+ box-shadow: 0 4px 20px rgba(184, 127, 13, 0.6);
1595
+ }
1596
+ }
1597
+
1598
+ @keyframes glowPremium {
1599
+ 0%, 100% {
1600
+ box-shadow: 0 2px 8px rgba(255, 168, 168, 0.3);
1601
+ }
1602
+ 50% {
1603
+ box-shadow: 0 4px 20px rgba(255, 168, 168, 0.6);
1604
+ }
1605
+ }
1606
+
1607
+ @keyframes glowVip {
1608
+ 0%, 100% {
1609
+ box-shadow: 0 2px 8px rgba(255, 191, 0, 0.3);
1610
+ }
1611
+ 50% {
1612
+ box-shadow: 0 4px 20px rgba(255, 191, 0, 0.6);
1613
+ }
1614
+ }
1615
+
1616
+ @keyframes glowSupreme {
1617
+ 0%, 100% {
1618
+ box-shadow: 0 2px 8px rgba(238, 62, 75, 0.3);
1619
+ }
1620
+ 50% {
1621
+ box-shadow: 0 4px 20px rgba(238, 62, 75, 0.6);
1622
+ }
1623
+ }
1624
+
1625
+ .profile-content {
1626
+ display: grid;
1627
+ gap: var(--spacing-xl);
1628
+ }
1629
+
1630
+ .profile-section {
1631
+ background: var(--glass-bg);
1632
+ backdrop-filter: blur(20px);
1633
+ border: 1px solid var(--glass-border);
1634
+ border-radius: var(--border-radius-lg);
1635
+ padding: 2.5rem;
1636
+ box-shadow: var(--shadow);
1637
+ transition: var(--transition-base);
1638
+ }
1639
+
1640
+ .profile-section:hover {
1641
+ transform: translateY(-3px);
1642
+ box-shadow: var(--shadow-lg);
1643
+ }
1644
+
1645
+ .profile-section h3 {
1646
+ margin-bottom: var(--spacing-xl);
1647
+ color: var(--text-primary);
1648
+ font-size: var(--font-size-xl);
1649
+ font-weight: 700;
1650
+ display: flex;
1651
+ align-items: center;
1652
+ gap: var(--spacing-sm);
1653
+ }
1654
+
1655
+ .info-grid {
1656
+ display: grid;
1657
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
1658
+ gap: var(--spacing-xl);
1659
+ }
1660
+
1661
+ .info-item {
1662
+ display: flex;
1663
+ flex-direction: column;
1664
+ gap: var(--spacing-sm);
1665
+ }
1666
+
1667
+ .info-item label {
1668
+ font-weight: 600;
1669
+ color: var(--text-secondary);
1670
+ font-size: var(--font-size-sm);
1671
+ }
1672
+
1673
+ .info-value {
1674
+ font-size: var(--font-size-xl);
1675
+ font-weight: 700;
1676
+ background: var(--primary-gradient);
1677
+ -webkit-background-clip: text;
1678
+ -webkit-text-fill-color: transparent;
1679
+ }
1680
+
1681
+ .api-key-display {
1682
+ display: flex;
1683
+ align-items: center;
1684
+ gap: var(--spacing-md);
1685
+ background: rgba(255, 255, 255, 0.4);
1686
+ padding: var(--spacing-md) var(--spacing-lg);
1687
+ border-radius: var(--border-radius);
1688
+ border: 1px solid var(--glass-border);
1689
+ min-height: 52px;
1690
+ }
1691
+
1692
+ .api-key-display code {
1693
+ flex: 1;
1694
+ color: #FFA8A8;
1695
+ font-family: 'JetBrains Mono', monospace;
1696
+ font-weight: 500;
1697
+ font-size: var(--font-size-sm);
1698
+ }
1699
+
1700
+ .redeem-section,
1701
+ .setting-card,
1702
+ .admin-card {
1703
+ background: var(--glass-bg);
1704
+ backdrop-filter: blur(20px);
1705
+ border: 1px solid var(--glass-border);
1706
+ border-radius: var(--border-radius-lg);
1707
+ padding: 2.5rem;
1708
+ box-shadow: var(--shadow);
1709
+ margin-bottom: var(--spacing-xl);
1710
+ transition: var(--transition-base);
1711
+ }
1712
+
1713
+ .redeem-section:hover,
1714
+ .setting-card:hover,
1715
+ .admin-card:hover {
1716
+ transform: translateY(-3px);
1717
+ box-shadow: var(--shadow-lg);
1718
+ }
1719
+
1720
+ .redeem-section h3,
1721
+ .setting-card h3,
1722
+ .admin-card h3 {
1723
+ margin-bottom: var(--spacing-xl);
1724
+ color: var(--text-primary);
1725
+ font-size: var(--font-size-xl);
1726
+ font-weight: 700;
1727
+ display: flex;
1728
+ align-items: center;
1729
+ gap: var(--spacing-sm);
1730
+ }
1731
+
1732
+ .redeem-section p {
1733
+ color: var(--text-secondary);
1734
+ margin-bottom: var(--spacing-lg);
1735
+ line-height: 1.6;
1736
+ }
1737
+
1738
+ .settings-container,
1739
+ .admin-container {
1740
+ display: grid;
1741
+ gap: var(--spacing-xl);
1742
+ }
1743
+
1744
+ .settings-grid {
1745
+ display: grid;
1746
+ gap: var(--spacing-xl);
1747
+ }
1748
+
1749
+ .setting-item {
1750
+ display: flex;
1751
+ flex-direction: column;
1752
+ gap: var(--spacing-lg);
1753
+ }
1754
+
1755
+ .premium-actions {
1756
+ display: flex;
1757
+ gap: var(--spacing-lg);
1758
+ flex-wrap: wrap;
1759
+ }
1760
+
1761
+ .danger-zone {
1762
+ border: 1px solid rgba(250, 112, 154, 0.4) !important;
1763
+ background: rgba(250, 112, 154, 0.05) !important;
1764
+ }
1765
+
1766
+ .danger-actions {
1767
+ text-align: center;
1768
+ }
1769
+
1770
+ .warning-text {
1771
+ margin-top: var(--spacing-lg);
1772
+ color: var(--text-muted);
1773
+ font-size: var(--font-size-sm);
1774
+ line-height: 1.5;
1775
+ }
1776
+
1777
+ .usage-progress {
1778
+ margin-bottom: var(--spacing-lg);
1779
+ }
1780
+
1781
+ .progress-item {
1782
+ margin-bottom: var(--spacing-lg);
1783
+ }
1784
+
1785
+ .progress-item label {
1786
+ display: block;
1787
+ margin-bottom: var(--spacing-sm);
1788
+ font-weight: 600;
1789
+ color: var(--text-primary);
1790
+ }
1791
+
1792
+ .progress-bar {
1793
+ width: 100%;
1794
+ height: 12px;
1795
+ background: rgba(255, 168, 168, 0.2);
1796
+ border-radius: 6px;
1797
+ overflow: hidden;
1798
+ border: 1px solid var(--glass-border);
1799
+ }
1800
+
1801
+ .progress-fill {
1802
+ height: 100%;
1803
+ background: var(--primary-gradient);
1804
+ border-radius: 6px;
1805
+ transition: width var(--transition-base);
1806
+ }
1807
+
1808
+ .progress-text {
1809
+ font-size: var(--font-size-sm);
1810
+ color: var(--text-secondary);
1811
+ margin-top: var(--spacing-sm);
1812
+ display: block;
1813
+ font-weight: 500;
1814
+ }
1815
+
1816
+ .activity-list {
1817
+ max-height: 350px;
1818
+ overflow-y: auto;
1819
+ padding-right: var(--spacing-xs);
1820
+ }
1821
+
1822
+ .activity-item {
1823
+ display: flex;
1824
+ align-items: flex-start;
1825
+ gap: var(--spacing-lg);
1826
+ padding: var(--spacing-lg);
1827
+ border-bottom: 1px solid var(--glass-border);
1828
+ transition: background var(--transition-base);
1829
+ border-radius: var(--border-radius);
1830
+ margin-bottom: var(--spacing-sm);
1831
+ min-height: 60px;
1832
+ color: var(--text-primary);
1833
+ }
1834
+
1835
+ .activity-item:last-child {
1836
+ border-bottom: none;
1837
+ margin-bottom: 0;
1838
+ }
1839
+
1840
+ .activity-item:hover {
1841
+ background: var(--glass-bg);
1842
+ }
1843
+
1844
+ .activity-item i {
1845
+ margin-top: var(--spacing-xs);
1846
+ font-size: var(--font-size-lg);
1847
+ color: #FFA8A8;
1848
+ min-width: 20px;
1849
+ }
1850
+
1851
+ .stat-item {
1852
+ text-align: center;
1853
+ padding: var(--spacing-lg);
1854
+ background: var(--glass-bg);
1855
+ border-radius: var(--border-radius);
1856
+ border: 1px solid var(--glass-border);
1857
+ transition: var(--transition-base);
1858
+ min-height: 100px;
1859
+ display: flex;
1860
+ flex-direction: column;
1861
+ justify-content: center;
1862
+ }
1863
+
1864
+ .stat-item:hover {
1865
+ transform: translateY(-3px);
1866
+ box-shadow: var(--shadow);
1867
+ }
1868
+
1869
+ .stat-value {
1870
+ display: block;
1871
+ font-size: 2.2rem;
1872
+ font-weight: 800;
1873
+ background: var(--primary-gradient);
1874
+ -webkit-background-clip: text;
1875
+ -webkit-text-fill-color: transparent;
1876
+ margin-bottom: var(--spacing-sm);
1877
+ line-height: 1.1;
1878
+ }
1879
+
1880
+ .usage-chart {
1881
+ background: var(--glass-bg);
1882
+ backdrop-filter: blur(20px);
1883
+ border: 1px solid var(--glass-border);
1884
+ border-radius: var(--border-radius-lg);
1885
+ padding: 2.5rem;
1886
+ margin-bottom: var(--spacing-2xl);
1887
+ box-shadow: var(--shadow);
1888
+ }
1889
+
1890
+ .usage-chart h3 {
1891
+ display: flex;
1892
+ align-items: center;
1893
+ gap: var(--spacing-sm);
1894
+ margin-bottom: var(--spacing-xl);
1895
+ color: var(--text-primary);
1896
+ font-size: var(--font-size-2xl);
1897
+ font-weight: 700;
1898
+ }
1899
+
1900
+ .chart-placeholder {
1901
+ text-align: center;
1902
+ padding: 4rem;
1903
+ color: var(--text-muted);
1904
+ background: rgba(255, 255, 255, 0.3);
1905
+ border-radius: var(--border-radius);
1906
+ border: 1px solid var(--glass-border);
1907
+ }
1908
+
1909
+ .chart-placeholder i {
1910
+ font-size: var(--font-size-4xl);
1911
+ margin-bottom: var(--spacing-md);
1912
+ opacity: 0.3;
1913
+ }
1914
+
1915
+ .text-muted {
1916
+ color: var(--text-muted);
1917
+ font-size: var(--font-size-sm);
1918
+ margin-top: var(--spacing-sm);
1919
+ }
1920
+
1921
+ .footer {
1922
+ background: rgba(255, 255, 255, 0.6);
1923
+ border-top: 1px solid var(--glass-border);
1924
+ padding: 4rem 0;
1925
+ text-align: center;
1926
+ color: var(--text-secondary);
1927
+ }
1928
+
1929
+ ::-webkit-scrollbar {
1930
+ width: 8px;
1931
+ height: 8px;
1932
+ }
1933
+
1934
+ ::-webkit-scrollbar-track {
1935
+ background: rgba(255, 168, 168, 0.1);
1936
+ border-radius: 4px;
1937
+ }
1938
+
1939
+ ::-webkit-scrollbar-thumb {
1940
+ background: var(--primary-gradient);
1941
+ border-radius: 4px;
1942
+ }
1943
+
1944
+ ::-webkit-scrollbar-thumb:hover {
1945
+ background: linear-gradient(135deg, #FF8E8E 0%, #7580EE 100%);
1946
+ }
1947
+
1948
+ .swal2-popup {
1949
+ background: rgba(255, 255, 255, 0.9) !important;
1950
+ backdrop-filter: blur(20px) !important;
1951
+ border: 1px solid var(--glass-border) !important;
1952
+ border-radius: var(--border-radius-lg) !important;
1953
+ box-shadow: var(--shadow) !important;
1954
+ }
1955
+
1956
+ .swal2-title {
1957
+ color: var(--text-primary) !important;
1958
+ font-weight: 700 !important;
1959
+ }
1960
+
1961
+ .swal2-content {
1962
+ color: var(--text-secondary) !important;
1963
+ }
1964
+
1965
+ .swal2-confirm {
1966
+ background: var(--primary-gradient) !important;
1967
+ border: none !important;
1968
+ border-radius: var(--border-radius) !important;
1969
+ font-weight: 600 !important;
1970
+ min-height: 44px !important;
1971
+ }
1972
+
1973
+ .swal2-cancel {
1974
+ background: var(--danger-gradient) !important;
1975
+ border: none !important;
1976
+ border-radius: var(--border-radius) !important;
1977
+ font-weight: 600 !important;
1978
+ min-height: 44px !important;
1979
+ }
1980
+
1981
+ .swal2-input {
1982
+ background: rgba(255, 255, 255, 0.6) !important;
1983
+ border: 1px solid var(--glass-border) !important;
1984
+ border-radius: var(--border-radius) !important;
1985
+ color: var(--text-primary) !important;
1986
+ min-height: 48px !important;
1987
+ padding: var(--spacing-md) !important;
1988
+ }
1989
+
1990
+ @media (max-width: 1200px) {
1991
+ .nav-menu {
1992
+ gap: var(--spacing-md);
1993
+ }
1994
+
1995
+ .stats-cards {
1996
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
1997
+ }
1998
+
1999
+ .info-grid {
2000
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2001
+ }
2002
+ }
2003
+
2004
+ @media (max-width: 768px) {
2005
+ :root {
2006
+ --spacing-xl: 1.5rem;
2007
+ --spacing-2xl: 2rem;
2008
+ --font-size-4xl: 2rem;
2009
+ --font-size-3xl: 1.75rem;
2010
+ --font-size-2xl: 1.25rem;
2011
+ }
2012
+
2013
+ .dashboard-container {
2014
+ flex-direction: column;
2015
+ }
2016
+
2017
+ .sidebar {
2018
+ width: 100%;
2019
+ height: auto;
2020
+ position: relative;
2021
+ top: 0;
2022
+ order: 2;
2023
+ border-right: none;
2024
+ border-top: 1px solid var(--glass-border);
2025
+ padding: var(--spacing-md) 0;
2026
+ }
2027
+
2028
+ .sidebar-menu {
2029
+ flex-direction: row;
2030
+ overflow-x: auto;
2031
+ padding: 0 var(--spacing-md);
2032
+ gap: var(--spacing-md);
2033
+ }
2034
+
2035
+ .menu-item {
2036
+ white-space: nowrap;
2037
+ min-width: 140px;
2038
+ justify-content: center;
2039
+ padding: var(--spacing-md);
2040
+ }
2041
+
2042
+ .main-content {
2043
+ order: 1;
2044
+ max-width: 100vw;
2045
+ padding: var(--spacing-lg);
2046
+ }
2047
+
2048
+ .hero {
2049
+ padding: 4rem var(--spacing-md) 3rem;
2050
+ }
2051
+
2052
+ .hero-title {
2053
+ font-size: 2rem;
2054
+ }
2055
+
2056
+ .section-title {
2057
+ font-size: 2rem;
2058
+ }
2059
+
2060
+ .auth-card {
2061
+ margin: var(--spacing-sm);
2062
+ padding: var(--spacing-lg);
2063
+ }
2064
+
2065
+ .sidebar-menu {
2066
+ padding: 0 var(--spacing-sm);
2067
+ }
2068
+
2069
+ .main-content {
2070
+ padding: var(--spacing-md);
2071
+ }
2072
+
2073
+ .stats-cards .stat-card,
2074
+ .plugin-details,
2075
+ .redeem-section,
2076
+ .setting-card,
2077
+ .admin-card,
2078
+ .profile-section {
2079
+ padding: var(--spacing-lg);
2080
+ }
2081
+
2082
+ .plugin-header {
2083
+ padding: var(--spacing-md);
2084
+ }
2085
+
2086
+ .form-field input,
2087
+ .form-field select,
2088
+ .form-group input,
2089
+ .form-group select,
2090
+ .btn,
2091
+ .menu-item,
2092
+ .api-key-display {
2093
+ min-height: 44px;
2094
+ }
2095
+
2096
+ .btn-sm {
2097
+ min-height: 32px;
2098
+ }
2099
+ }
2100
+ font-size: 2.5rem;
2101
+ }
2102
+
2103
+ .hero-buttons {
2104
+ flex-direction: column;
2105
+ align-items: center;
2106
+ gap: var(--spacing-md);
2107
+ }
2108
+
2109
+ .features-grid,
2110
+ .stats-grid {
2111
+ grid-template-columns: 1fr;
2112
+ }
2113
+
2114
+ .features {
2115
+ padding: 4rem 0;
2116
+ }
2117
+
2118
+ .stats {
2119
+ padding: 4rem 0;
2120
+ }
2121
+
2122
+ .auth-card {
2123
+ padding: var(--spacing-xl);
2124
+ margin: var(--spacing-md);
2125
+ max-width: none;
2126
+ }
2127
+
2128
+ .nav-menu {
2129
+ flex-direction: column;
2130
+ gap: var(--spacing-md);
2131
+ }
2132
+
2133
+ .tab-btn {
2134
+ font-size: var(--font-size-sm);
2135
+ padding: var(--spacing-sm);
2136
+ }
2137
+
2138
+ .stats-cards {
2139
+ grid-template-columns: 1fr;
2140
+ }
2141
+
2142
+ .stats-cards .stat-card {
2143
+ flex-direction: column;
2144
+ text-align: center;
2145
+ gap: var(--spacing-lg);
2146
+ }
2147
+
2148
+ .section h2 {
2149
+ font-size: 2.2rem;
2150
+ }
2151
+
2152
+ .form-actions {
2153
+ flex-direction: column;
2154
+ align-items: stretch;
2155
+ }
2156
+
2157
+ .btn-execute,
2158
+ .btn-reset {
2159
+ width: 100%;
2160
+ justify-content: center;
2161
+ }
2162
+
2163
+ .input-group {
2164
+ flex-direction: column;
2165
+ }
2166
+
2167
+ .form-row {
2168
+ grid-template-columns: 1fr;
2169
+ }
2170
+
2171
+ .premium-actions {
2172
+ flex-direction: column;
2173
+ }
2174
+
2175
+ .info-grid {
2176
+ grid-template-columns: 1fr;
2177
+ }
2178
+
2179
+ .response-header {
2180
+ flex-direction: column;
2181
+ align-items: stretch;
2182
+ gap: var(--spacing-sm);
2183
+ }
2184
+
2185
+ .activity-item {
2186
+ flex-direction: column;
2187
+ text-align: center;
2188
+ gap: var(--spacing-md);
2189
+ }
2190
+
2191
+ .plugin-header {
2192
+ flex-direction: column;
2193
+ gap: var(--spacing-md);
2194
+ text-align: center;
2195
+ min-height: auto;
2196
+ padding: var(--spacing-lg);
2197
+ }
2198
+
2199
+ .plugin-left {
2200
+ order: 2;
2201
+ }
2202
+
2203
+ .plugin-type {
2204
+ order: 1;
2205
+ }
2206
+
2207
+ .plugin-expand {
2208
+ order: 3;
2209
+ margin-left: 0;
2210
+ }
2211
+
2212
+ .profile-container {
2213
+ padding: 0 var(--spacing-md);
2214
+ }
2215
+
2216
+ .profile-header {
2217
+ padding: var(--spacing-xl);
2218
+ }
2219
+
2220
+ .profile-section {
2221
+ padding: var(--spacing-lg);
2222
+ }
2223
+ }
2224
+
2225
+ @media (max-width: 480px) {
2226
+ .container {
2227
+ padding: 0 var(--spacing-md);
2228
+ }
2229
+
2230
+ .hero {
2231
+ padding: 3rem var(--spacing-md) 2rem;
2232
+ }
2233
+
2234
+ .hero-title {
2235
+ font-size: 2rem;
2236
+ }
2237
+
2238
+ .section-title {
2239
+ font-size: 2rem;
2240
+ }
2241
+
2242
+ .auth-card {
2243
+ margin: var(--spacing-sm);
2244
+ padding: var(--spacing-lg);
2245
+ }
2246
+
2247
+ .sidebar-menu {
2248
+ padding: 0 var(--spacing-sm);
2249
+ }
2250
+
2251
+ .main-content {
2252
+ padding: var(--spacing-md);
2253
+ }
2254
+
2255
+ .stats-cards .stat-card,
2256
+ .plugin-details,
2257
+ .redeem-section,
2258
+ .setting-card,
2259
+ .admin-card,
2260
+ .profile-section {
2261
+ padding: var(--spacing-lg);
2262
+ }
2263
+
2264
+ .plugin-header {
2265
+ padding: var(--spacing-md);
2266
+ }
2267
+
2268
+ .form-field input,
2269
+ .form-field select,
2270
+ .form-group input,
2271
+ .form-group select,
2272
+ .btn,
2273
+ .menu-item,
2274
+ .api-key-display {
2275
+ min-height: 44px;
2276
+ }
2277
+
2278
+ .btn-sm {
2279
+ min-height: 32px;
2280
+ }
2281
+ }
2282
+ font-size: 2rem;
2283
+ }
2284
+
2285
+ .section-title {
2286
+ font-size: 2rem;
2287
+ }
2288
+
2289
+ .auth-card {
2290
+ margin: var(--spacing-sm);
2291
+ padding: var(--spacing-lg);
2292
+ }
2293
+
2294
+ .sidebar-menu {
2295
+ padding: 0 var(--spacing-sm);
2296
+ }
2297
+
2298
+ .main-content {
2299
+ padding: var(--spacing-md);
2300
+ }
2301
+
2302
+ .stats-cards .stat-card,
2303
+ .plugin-details,
2304
+ .redeem-section,
2305
+ .setting-card,
2306
+ .admin-card,
2307
+ .profile-section {
2308
+ padding: var(--spacing-lg);
2309
+ }
2310
+
2311
+ .plugin-header {
2312
+ padding: var(--spacing-md);
2313
+ }
2314
+
2315
+ .form-field input,
2316
+ .form-field select,
2317
+ .form-group input,
2318
+ .form-group select,
2319
+ .btn,
2320
+ .menu-item,
2321
+ .api-key-display {
2322
+ min-height: 44px;
2323
+ }
2324
+
2325
+ .btn-sm {
2326
+ min-height: 32px;
2327
+ }
2328
+