pen / login.html
senku21230's picture
Update login.html
39e13ac verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Secure Terminal Access</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
/* --- CORE VARIABLES --- */
:root {
--bg-deep: #0a0b10;
--bg-surface: #12141d;
--bg-card: rgba(22, 24, 34, 0.6);
--brand-orange: #FF6B00;
--brand-orange-light: #FFA600;
--brand-glow: rgba(255, 107, 0, 0.4);
--text-primary: #F8F9FA;
--text-secondary: #8B949E;
--input-bg: rgba(10, 11, 16, 0.8);
--border-color: rgba(255, 255, 255, 0.06);
--border-focus: rgba(255, 107, 0, 0.5);
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
}
/* --- RESET & BASE --- */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: 'Outfit', sans-serif;
background-color: var(--bg-deep);
color: var(--text-primary);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
position: relative;
}
/* --- DYNAMIC BACKGROUND & GRID --- */
.bg-grid {
position: absolute;
top: 0; left: 0; width: 100vw; height: 100vh;
background-image:
linear-gradient(to right, rgba(255,255,255,0.02) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255,255,255,0.02) 1px, transparent 1px);
background-size: 40px 40px;
z-index: 0;
transform: perspective(500px) rotateX(60deg) translateY(-100px) translateZ(-200px);
animation: gridMove 20s linear infinite;
opacity: 0.5;
}
.ambient-light {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 500px;
height: 500px;
background: radial-gradient(circle, var(--brand-glow) 0%, transparent 60%);
filter: blur(80px);
z-index: 1;
animation: pulseLight 8s alternate infinite;
}
/* --- APP LAYOUT --- */
.app-container {
width: 100%;
max-width: 440px;
position: relative;
z-index: 10;
padding: 24px;
}
/* --- MAIN LOGIN CARD --- */
.login-card {
background: var(--bg-card);
border-radius: 28px;
padding: 45px 35px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--border-color);
box-shadow: 0 30px 60px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.05);
position: relative;
transform: translateY(30px);
opacity: 0;
animation: cardReveal 1s var(--ease-out-expo) forwards;
}
.login-card::before {
content: '';
position: absolute;
top: -1px; left: -1px; right: -1px; bottom: -1px;
border-radius: 28px;
background: linear-gradient(135deg, var(--brand-orange-light), transparent 40%, transparent 60%, var(--brand-orange));
z-index: -1;
opacity: 0;
transition: opacity 0.5s ease;
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
padding: 1px;
}
.login-card:hover::before {
opacity: 0.5;
}
/* --- ADVANCED SVG LOGO --- */
.logo-wrapper {
display: flex;
justify-content: center;
margin-bottom: 35px;
position: relative;
}
.logo-core {
position: relative;
width: 85px;
height: 85px;
display: flex;
justify-content: center;
align-items: center;
animation: float 6s ease-in-out infinite;
}
.logo-svg {
width: 100%;
height: 100%;
filter: drop-shadow(0 0 15px var(--brand-glow));
}
.outer-hex {
transform-origin: center;
animation: spinRotate 20s linear infinite;
}
.inner-dash {
stroke-dasharray: 10 5;
animation: dashMove 2s linear infinite;
}
/* --- TYPOGRAPHY --- */
.header-section {
text-align: center;
margin-bottom: 40px;
}
h1 {
font-size: 26px;
font-weight: 600;
letter-spacing: -0.5px;
margin-bottom: 12px;
background: linear-gradient(to right, #FFF, #A0A5B0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
p {
font-size: 15px;
color: var(--text-secondary);
font-weight: 400;
}
/* --- FORM & INPUTS --- */
.form-group {
position: relative;
margin-bottom: 30px;
}
.input-icon, .toggle-icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.input-icon {
left: 18px;
}
.toggle-icon {
right: 18px;
cursor: pointer;
background: none;
border: none;
padding: 5px;
}
.toggle-icon:hover {
color: var(--text-primary);
}
.secure-input {
width: 100%;
background: var(--input-bg);
border: 1.5px solid var(--border-color);
border-radius: 16px;
padding: 20px 55px 20px 50px;
color: var(--brand-orange-light);
font-family: 'JetBrains Mono', monospace;
font-size: 16px;
letter-spacing: 2px;
outline: none;
transition: all 0.3s var(--ease-out-expo);
box-shadow: inset 0 2px 10px rgba(0,0,0,0.5);
}
.secure-input::placeholder {
color: rgba(139, 148, 158, 0.5);
font-family: 'Outfit', sans-serif;
letter-spacing: normal;
}
.secure-input:focus {
border-color: var(--brand-orange);
background: rgba(10, 11, 16, 0.95);
box-shadow: 0 0 0 4px rgba(255, 107, 0, 0.1), inset 0 2px 10px rgba(0,0,0,0.5);
}
.secure-input:focus ~ .input-icon {
color: var(--brand-orange);
filter: drop-shadow(0 0 5px var(--brand-glow));
}
/* --- SUBMIT BUTTON --- */
.btn-connect {
width: 100%;
background: linear-gradient(135deg, var(--brand-orange) 0%, #D85A00 100%);
color: #fff;
border: none;
border-radius: 16px;
padding: 20px;
font-size: 17px;
font-weight: 600;
font-family: 'Outfit', sans-serif;
cursor: pointer;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
box-shadow: 0 10px 25px rgba(255, 107, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
gap: 12px;
}
.btn-connect::after {
content: '';
position: absolute;
top: 0; left: -100%;
width: 50%; height: 100%;
background: linear-gradient(to right, transparent, rgba(255,255,255,0.2), transparent);
transform: skewX(-25deg);
transition: all 0.5s ease;
}
.btn-connect:hover {
transform: translateY(-2px);
box-shadow: 0 15px 35px rgba(255, 107, 0, 0.4);
background: linear-gradient(135deg, var(--brand-orange-light) 0%, var(--brand-orange) 100%);
}
.btn-connect:hover::after {
left: 200%;
}
.btn-connect:active {
transform: translateY(1px);
box-shadow: 0 5px 15px rgba(255, 107, 0, 0.3);
}
.loader-ring {
display: none;
width: 24px; height: 24px;
border: 3px solid rgba(255,255,255,0.2);
border-top: 3px solid #fff;
border-radius: 50%;
animation: spinRotate 0.8s linear infinite;
}
.btn-connect.is-loading .btn-text { display: none; }
.btn-connect.is-loading .loader-ring { display: block; }
.btn-connect.is-loading {
pointer-events: none;
opacity: 0.9;
}
/* --- SUCCESS OVERLAY --- */
.auth-success {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(18, 20, 29, 0.95);
backdrop-filter: blur(10px);
border-radius: 28px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: all 0.4s ease;
z-index: 20;
}
.auth-success.active {
opacity: 1;
pointer-events: all;
}
.shield-check {
width: 75px;
height: 75px;
color: #10B981;
margin-bottom: 25px;
stroke-dasharray: 100;
stroke-dashoffset: 100;
filter: drop-shadow(0 0 15px rgba(16, 185, 129, 0.4));
}
.auth-success.active .shield-check {
animation: drawCheck 1s var(--ease-out-expo) forwards;
animation-delay: 0.2s;
}
.success-msg {
color: #10B981;
font-size: 22px;
font-weight: 600;
letter-spacing: 1.5px;
opacity: 0;
transform: translateY(10px);
}
.auth-success.active .success-msg {
animation: slideUpFade 0.5s ease forwards;
animation-delay: 0.6s;
}
/* --- KEYFRAMES --- */
@keyframes gridMove {
0% { background-position: 0 0; }
100% { background-position: 0 40px; }
}
@keyframes pulseLight {
0% { opacity: 0.4; transform: translate(-50%, -50%) scale(1); }
100% { opacity: 0.7; transform: translate(-50%, -50%) scale(1.1); }
}
@keyframes cardReveal {
to { opacity: 1; transform: translateY(0); }
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes spinRotate {
to { transform: rotate(360deg); }
}
@keyframes dashMove {
to { stroke-dashoffset: -15; }
}
@keyframes drawCheck {
to { stroke-dashoffset: 0; }
}
@keyframes slideUpFade {
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="bg-grid"></div>
<div class="ambient-light"></div>
<div class="app-container">
<div class="login-card">
<div class="logo-wrapper">
<div class="logo-core">
<svg class="logo-svg" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFA600" />
<stop offset="100%" stop-color="#FF6B00" />
</linearGradient>
</defs>
<g class="outer-hex">
<path d="M50 2L91.569 26V74L50 98L8.431 74V26L50 2Z" stroke="url(#primaryGrad)" stroke-width="2" stroke-opacity="0.3"/>
<path d="M50 8L86.373 29V71L50 92L13.627 71V29L50 8Z" stroke="url(#primaryGrad)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" class="inner-dash"/>
</g>
<path d="M50 22L70 34V66L50 78L30 66V34L50 22Z" fill="rgba(255, 107, 0, 0.1)" stroke="url(#primaryGrad)" stroke-width="2"/>
<path d="M45 40L55 50L45 60" stroke="url(#primaryGrad)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</div>
<div class="header-section">
<h1>Secure Terminal Access</h1>
<p>Please authenticate to continue</p>
</div>
<form id="terminalForm">
<div class="form-group">
<div class="input-icon">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path>
</svg>
</div>
<input type="password" id="secretKey" class="secure-input" placeholder="Enter Security Key" required autocomplete="off">
<button type="button" class="toggle-icon" id="togglePassword">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="eyeIconSVG">
<path class="eye-path" d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle class="eye-circle" cx="12" cy="12" r="3"></circle>
<line class="eye-slash" x1="1" y1="1" x2="23" y2="23" style="display:none;"></line>
</svg>
</button>
</div>
<button type="submit" class="btn-connect" id="connectBtn">
<span class="btn-text" id="btnText">Connect to Terminal</span>
<div class="loader-ring"></div>
</button>
</form>
<div class="auth-success" id="successScreen">
<svg class="shield-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
<polyline points="9 12 11 14 15 10"></polyline>
</svg>
<div class="success-msg">ACCESS GRANTED</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('terminalForm');
const keyInput = document.getElementById('secretKey');
const toggleBtn = document.getElementById('togglePassword');
const eyeSlash = document.querySelector('.eye-slash');
const connectBtn = document.getElementById('connectBtn');
const btnText = document.getElementById('btnText');
const successScreen = document.getElementById('successScreen');
// Password Visibility Toggle Logic
toggleBtn.addEventListener('click', () => {
if (keyInput.type === 'password') {
keyInput.type = 'text';
eyeSlash.style.display = 'block';
toggleBtn.style.color = 'var(--brand-orange)';
} else {
keyInput.type = 'password';
eyeSlash.style.display = 'none';
toggleBtn.style.color = 'var(--text-secondary)';
}
});
// Real Backend Form Submit Handling
form.addEventListener('submit', async (e) => {
e.preventDefault();
const keyValue = keyInput.value.trim();
if(!keyValue) return;
// Start Loading State
connectBtn.classList.add('is-loading');
keyInput.disabled = true;
try {
// Send password to backend
const response = await fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `password=${encodeURIComponent(keyValue)}`
});
connectBtn.classList.remove('is-loading');
// Check response status
if (response.url.endsWith('/login?error=1')) {
// Error State
keyInput.disabled = false;
keyInput.style.borderColor = '#ef4444';
btnText.textContent = "Invalid Key! Try Again";
btnText.style.color = '#ef4444';
setTimeout(() => {
keyInput.style.borderColor = 'var(--border-color)';
btnText.textContent = "Connect to Terminal";
btnText.style.color = '#fff';
}, 2500);
} else {
// Success State
successScreen.classList.add('active');
setTimeout(() => {
window.location.href = '/';
}, 1500);
}
} catch (error) {
console.error("Connection failed", error);
connectBtn.classList.remove('is-loading');
keyInput.disabled = false;
}
});
});
</script>
</body>
</html>