<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>CTRS — Full-Sized Student Registration App</title>
<!-- jsPDF for PDF generation -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
/* Reset & fonts */
:root{
--accent:#1e88e5;
--card-bg: rgba(255,255,255,0.06);
--glass: rgba(255,255,255,0.06);
--white-faint: rgba(255,255,255,0.9);
}
*{box-sizing:border-box}
html,body{height:100%; margin:0; font-family:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial; color:var(--white-faint); -webkit-font-smoothing:antialiased}
body{overflow:hidden; background: #0b1220;} /* base for canvas */
/* canvas full-screen animated background */
#bgCanvas{ position:fixed; inset:0; z-index:0; }
/* App shell (looks like a big monitor) */
.monitor {
position:relative;
z-index:2;
width:98vw;
height:96vh;
margin:1vh auto;
border-radius:12px;
overflow:hidden;
box-shadow: 0 30px 80px rgba(2,8,23,0.7), inset 0 1px 0 rgba(255,255,255,0.02);
border: 10px solid rgba(255,255,255,0.03);
display:flex;
flex-direction:row;
}
/* Left Dock (apps) */
.dock {
width:140px;
background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));
border-right:1px solid rgba(255,255,255,0.03);
padding:18px 12px;
display:flex;
flex-direction:column;
gap:14px;
align-items:center;
}
.app-icon {
width:84px; height:84px; border-radius:12px; background:rgba(255,255,255,0.04);
display:grid; place-items:center; font-size:28px; cursor:pointer; transition: transform 0.18s, box-shadow 0.18s;
box-shadow: 0 8px 18px rgba(2,8,23,0.4);
}
.app-icon:active{ transform:translateY(3px) scale(0.98) }
.dock small { opacity:0.7; font-size:12px; margin-top:6px; text-align:center }
/* Main content area */
.main {
flex:1;
display:flex;
flex-direction:column;
}
/* Header with live date/time & settings */
.header {
display:flex; align-items:center; justify-content:space-between;
padding:18px 26px; gap:16px;
background: linear-gradient(90deg, rgba(0,0,0,0.02), transparent);
border-bottom:1px solid rgba(255,255,255,0.02);
}
.title { font-size:20px; font-weight:600; color:var(--white-faint) }
.hdr-right { display:flex; align-items:center; gap:14px }
.clock { font-size:14px; color:rgba(255,255,255,0.85) }
.small-muted { font-size:12px; color:rgba(255,255,255,0.65) }
/* Content area center */
.content {
flex:1; display:flex; align-items:center; justify-content:center; padding:30px;
}
/* "Monitor window" card */
.card {
width:820px; max-width:94%; border-radius:12px; background:linear-gradient(180deg, rgba(0,0,0,0.45), rgba(0,0,0,0.35));
padding:28px; box-shadow: 0 14px 40px rgba(2,8,23,0.6);
border: 1px solid rgba(255,255,255,0.03);
display:flex; gap:18px; align-items:stretch;
}
/* left side of card: vertical form area */
.panel {
flex:1; display:flex; flex-direction:column; gap:12px; padding:6px 12px;
}
.panel h2 { margin:4px 0 2px 0; font-size:20px; color:var(--white-faint) }
.panel p.muted { margin:0; color:rgba(255,255,255,0.6); font-size:13px }
/* single-column form */
.form {
display:flex; flex-direction:column; gap:12px; padding-top:6px;
}
.form input[type="text"], .form input[type="password"], .form input[type="date"] {
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.03);
color: var(--white-faint);
padding:12px 14px; border-radius:8px; font-size:15px; outline:none;
transition: transform 0.12s, box-shadow 0.12s;
}
.form input:focus { box-shadow:0 6px 18px rgba(30,136,229,0.12); transform: translateY(-3px) }
.actions { display:flex; gap:12px; margin-top:6px; align-items:center }
.btn-primary {
background: linear-gradient(180deg, var(--accent), #1565c0);
border: none; padding:12px 18px; border-radius:10px; color:white; font-weight:700; cursor:pointer;
box-shadow: 0 10px 30px rgba(30,136,229,0.12);
}
.btn-ghost { background:transparent; border:1px solid rgba(255,255,255,0.06); padding:10px 14px; color:var(--white-faint); border-radius:10px; cursor:pointer }
/* right side demonstration / pc-like area */
.right {
width:340px; border-left:1px solid rgba(255,255,255,0.02); padding-left:18px; display:flex; flex-direction:column; gap:12px;
}
.pc-screen {
background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.01));
border-radius:10px; height:180px; display:flex; align-items:center; justify-content:center; flex-direction:column;
border:1px solid rgba(255,255,255,0.02);
}
.pc-screen .big { font-size:18px; color: rgba(255,255,255,0.9) }
.installed { display:flex; gap:8px; margin-top:6px; justify-content:center; flex-wrap:wrap }
.installed .mini {
width:68px; height:68px; border-radius:10px; background:rgba(255,255,255,0.03); display:grid; place-items:center; font-size:20px;
}
/* fingerprint animation area */
.scanner {
display:flex; flex-direction:column; gap:8px; align-items:center; justify-content:center; margin-top:8px;
}
.finger {
width:110px; height:110px; border-radius:55px; background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.06), rgba(255,255,255,0.02));
border: 3px solid rgba(255,255,255,0.04); display:grid; place-items:center; font-size:46px; position:relative; overflow:hidden;
}
.scan-line {
position:absolute; left:0; right:0; height:6px; background: linear-gradient(90deg, transparent, rgba(30,136,229,0.6), transparent);
transform: translateY(-160px); animation: scan 2s linear infinite;
}
@keyframes scan { to { transform: translateY(160px); } }
/* settings panel */
.settings-panel {
position:fixed; right:12px; top:12vh; width:360px; max-width:92%; background:rgba(3,8,23,0.85); color:var(--white-faint);
border-radius:10px; padding:14px; z-index:5; box-shadow: 0 20px 80px rgba(2,8,23,0.6); display:none;
}
.settings-panel h3{ margin:4px 0 10px 0; }
.setting-row { display:flex; gap:8px; align-items:center; margin-bottom:10px }
/* exclamation dev button */
.dev-exclaim { position:fixed; top:18px; left:18px; z-index:6; font-size:22px; background:rgba(255,255,255,0.04); padding:8px 10px; border-radius:8px; cursor:pointer }
/* footer tiny */
.footer-small { font-size:12px; color:rgba(255,255,255,0.6); margin-top:8px }
/* responsive */
@media (max-width:980px){
.monitor { flex-direction:column }
.dock { width:100%; flex-direction:row; justify-content:space-around; padding:12px }
.card { flex-direction:column }
.right { width:100%; border-left:none; border-top:1px solid rgba(255,255,255,0.02); padding-top:12px }
}
</style>
</head>
<body>
<!-- animated background canvas -->
<canvas id="bgCanvas"></canvas>
<div class="monitor" role="application" aria-label="CTRS registration monitor">
<!-- left dock with app icons -->
<div class="dock" aria-hidden="false">
<div class="app-icon" title="Registration App" id="iconReg">📝</div>
<div class="app-icon" title="Files" id="iconFiles">📁</div>
<div class="app-icon" title="Browser" id="iconWeb">🌐</div>
<div class="app-icon" title="Settings" id="iconSettings">⚙️</div>
<small>CTRS Apps</small>
</div>
<!-- main area -->
<div class="main">
<!-- header -->
<div class="header">
<div class="title">CTRS — Student Registration (Full Screen)</div>
<div class="hdr-right">
<div class="clock" id="liveDateTime">--:--:--</div>
<button class="btn-ghost" id="openSettingsBtn">Settings</button>
</div>
</div>
<!-- center content -->
<div class="content">
<div class="card" role="region" aria-label="Registration card">
<!-- left panel: form -->
<div class="panel">
<h2 id="cardTitle">Enter Access Password</h2>
<p class="muted" id="cardSubtitle">You must provide the app password to continue.</p>
<div id="passwordGate" class="form">
<input id="gatePassword" type="password" placeholder="Access password (required)" aria-label="Access password" />
<div class="actions">
<button class="btn-primary" id="gateSubmit">Unlock</button>
<button class="btn-ghost" id="useSavedBtn">Use saved</button>
</div>
<div class="footer-small">Password is required to open the registration form.</div>
</div>
<form id="registerForm" class="form" style="display:none" onsubmit="return false;">
<input id="stuName" type="text" placeholder="Full name" required />
<input id="stuClass" type="text" placeholder="Class / Grade" required />
<input id="stuRoll" type="text" placeholder="Roll number" required />
<input id="stuPass" type="password" placeholder="Password for record" required />
<div style="display:flex; gap:10px; align-items:center">
<button class="btn-primary" id="submitBtn">Submit</button>
<button class="btn-ghost" id="saveLocalBtn">Save Locally</button>
</div>
<div class="footer-small" id="statusMsg" aria-live="polite"></div>
</form>
</div>
<!-- right side: PC-like small screen -->
<div class="right">
<div class="pc-screen">
<div class="big" id="pcStatus">Welcome — please unlock to register</div>
<div class="installed" aria-hidden="true">
<div class="mini" title="Docs">📄</div>
<div class="mini" title="Gallery">🖼️</div>
<div class="mini" title="Browser">🌐</div>
</div>
</div>
<div class="scanner" id="scannerArea" style="display:none">
<div class="finger" aria-hidden="true">
<div class="scan-line" style="animation-delay:0s;"></div>
<div style="font-size:34px">🔒</div>
</div>
<div id="scannerText" class="small-muted">Scanning fingerprint...</div>
</div>
<div style="margin-top:8px; text-align:center">
<button class="btn-ghost" id="openScannerBtn" style="display:none">Open Scanner</button>
<div class="footer-small">Submitted data can be exported to PDF.</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Settings panel -->
<div class="settings-panel" id="settingsPanel" role="dialog" aria-modal="true" aria-hidden="true">
<h3>Settings & Customization</h3>
<div class="setting-row">
<label class="small-muted">Wallpaper:</label>
<select id="wallpaperSelect" style="flex:1; padding:8px; border-radius:8px; background:rgba(255,255,255,0.03); color:var(--white-faint)">
<option value="bg1">Blue Gradient</option>
<option value="bg2">Aurora Wave</option>
<option value="bg3">Night Dots</option>
<option value="bg4">Dark Static</option>
</select>
</div>
<div class="setting-row">
<label class="small-muted">Animation style:</label>
<select id="animSelect" style="flex:1; padding:8px; border-radius:8px; background:rgba(255,255,255,0.03); color:var(--white-faint)">
<option value="smooth">Smooth</option>
<option value="energetic">Energetic</option>
<option value="calm">Calm</option>
</select>
</div>
<div class="setting-row">
<button class="btn-primary" id="scanDevicesBtn">Scan Nearby Devices (Simulated)</button>
<button class="btn-ghost" id="closeSettings">Close</button>
</div>
<div id="scanResult" style="margin-top:10px; font-size:14px; color:rgba(255,255,255,0.85)"></div>
<div style="margin-top:10px; font-size:12px; color:rgba(255,255,255,0.6)">Note: Browser cannot list Wi‑Fi networks. This scan is simulated.</div>
</div>
<!-- Dev password exclamation -->
<div class="dev-exclaim" id="devExclaim" title="Developer info (password protected)">❗</div>
<script>
/* ============================
App logic & UI bootstrap
============================ */
const APP_PASS = "6205943908"; // required unlock password
const DEFAULT_FILE_PREFIX = "CTRS_Registration";
const bgCanvas = document.getElementById('bgCanvas');
const ctx = bgCanvas.getContext('2d');
// sizing canvas
function resizeCanvas(){
bgCanvas.width = window.innerWidth;
bgCanvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
/* ------------- Animated background: multi-mode particle + gradient ------------- */
/* We'll create an animated gradient + floating particles for nice effect. */
let particles = [];
const particleCount = Math.round((window.innerWidth * window.innerHeight) / 90000); // scales with size
function initParticles(){
particles = [];
for(let i=0;i<Math.max(20, particleCount); i++){
particles.push({
x: Math.random()*bgCanvas.width,
y: Math.random()*bgCanvas.height,
r: 1 + Math.random()*3,
vx: (Math.random()-0.5) * 0.6,
vy: (Math.random()-0.5) * 0.6,
hueShift: Math.random()*60
});
}
}
initParticles();
let bgMode = 'bg1'; // default
function drawBackground(t){
// animated gradient base
const g = ctx.createLinearGradient(0, 0, bgCanvas.width, bgCanvas.height);
if(bgMode==='bg1'){
g.addColorStop(0, `hsl(${200 + Math.sin(t/5000)*20}deg 70% 30%)`);
g.addColorStop(1, `hsl(${220 + Math.cos(t/5000)*20}deg 70% 20%)`);
} else if(bgMode==='bg2'){
g.addColorStop(0, `hsl(${180 + Math.sin(t/4000)*40}deg 80% 20%)`);
g.addColorStop(1, `hsl(${260 + Math.cos(t/4000)*40}deg 60% 15%)`);
} else if(bgMode==='bg3'){
g.addColorStop(0, '#0f1724');
g.addColorStop(1, '#051428');
} else {
g.addColorStop(0, '#000000');
g.addColorStop(1, '#0b0b0f');
}
ctx.fillStyle = g;
ctx.fillRect(0,0,bgCanvas.width,bgCanvas.height);
// moving subtle waves
ctx.globalAlpha = 0.08;
for(let i=0;i<4;i++){
ctx.beginPath();
ctx.moveTo(0, bgCanvas.height * (i+1)/5 + Math.sin((t/1000) + i)*50);
for(let x=0;x<bgCanvas.width;x+=40){
ctx.lineTo(x, bgCanvas.height * (i+1)/5 + Math.sin((t/500)+x/120 + i)*60);
}
ctx.lineTo(bgCanvas.width, bgCanvas.height);
ctx.lineTo(0, bgCanvas.height);
ctx.closePath();
ctx.fillStyle = `rgba(255,255,255,${0.00 + 0.01*i})`;
ctx.fill();
}
ctx.globalAlpha = 1;
// particles
for(let p of particles){
p.x += p.vx; p.y += p.vy;
if(p.x < -10) p.x = bgCanvas.width + 10;
if(p.y < -10) p.y = bgCanvas.height + 10;
if(p.x > bgCanvas.width+10) p.x = -10;
if(p.y > bgCanvas.height+10) p.y = -10;
ctx.beginPath();
const hue = (200 + p.hueShift + Math.sin(t/2000 + p.x/300)*30) % 360;
ctx.fillStyle = `hsla(${hue}, 80%, 60%, 0.12)`;
ctx.arc(p.x, p.y, p.r, 0, Math.PI*2);
ctx.fill();
}
}
let startTime = performance.now();
function renderLoop(now){
drawBackground(now - startTime);
requestAnimationFrame(renderLoop);
}
requestAnimationFrame(renderLoop);
/* ============================
UI Components
============================ */
const gatePassword = document.getElementById('gatePassword');
const gateSubmit = document.getElementById('gateSubmit');
const useSavedBtn = document.getElementById('useSavedBtn');
const registerForm = document.getElementById('registerForm');
const stuName = document.getElementById('stuName');
const stuClass = document.getElementById('stuClass');
const stuRoll = document.getElementById('stuRoll');
const stuPass = document.getElementById('stuPass');
const submitBtn = document.getElementById('submitBtn');
const saveLocalBtn = document.getElementById('saveLocalBtn');
const statusMsg = document.getElementById('statusMsg');
const pcStatus = document.getElementById('pcStatus');
const scannerArea = document.getElementById('scannerArea');
const scannerText = document.getElementById('scannerText');
const openScannerBtn = document.getElementById('openScannerBtn');
const settingsPanel = document.getElementById('settingsPanel');
const openSettingsBtn = document.getElementById('openSettingsBtn');
const closeSettingsBtn = document.getElementById('closeSettings');
const wallpaperSelect = document.getElementById('wallpaperSelect');
const animSelect = document.getElementById('animSelect');
const scanDevicesBtn = document.getElementById('scanDevicesBtn');
const scanResult = document.getElementById('scanResult');
const devExclaim = document.getElementById('devExclaim');
const iconSettings = document.getElementById('iconSettings');
/* -------------------------
Live date & time
------------------------- */
const liveDateTime = document.getElementById('liveDateTime');
function refreshClock(){
const now = new Date();
const date = now.toLocaleDateString();
const time = now.toLocaleTimeString();
liveDateTime.textContent = `${date} • ${time}`;
}
setInterval(refreshClock, 1000);
refreshClock();
/* -------------------------
Persisted settings + data
------------------------- */
function loadState(){
try {
const s = JSON.parse(localStorage.getItem('ctrs_app_state') || '{}');
if(s.wallpaper) { wallpaperSelect.value = s.wallpaper; applyWallpaper(s.wallpaper); }
if(s.animation) { animSelect.value = s.animation; }
const d = JSON.parse(localStorage.getItem('ctrs_data') || '{}');
if(d.name) { stuName.value = d.name; stuClass.value = d.class; stuRoll.value = d.roll; stuPass.value = d.password; }
} catch(e){ console.warn('load state fail', e) }
}
loadState();
function saveState(){
const st = { wallpaper: wallpaperSelect.value, animation: animSelect.value };
localStorage.setItem('ctrs_app_state', JSON.stringify(st));
}
/* -------------------------
Unlock gate logic
------------------------- */
gateSubmit.addEventListener('click', () => {
const v = gatePassword.value.trim();
if(v === APP_PASS){
onUnlocked();
} else {
statusMsg.textContent = 'Incorrect access password.';
statusMsg.style.color = 'rgba(255,120,120,0.95)';
gatePassword.animate([{transform:'translateX(0)},{transform:'translateX(-10px)'},{transform:'translateX(10px)'},{transform:'translateX(0)'}], {duration:360});
}
});
useSavedBtn.addEventListener('click', () => {
const stored = JSON.parse(localStorage.getItem('ctrs_data') || '{}');
if(stored && stored.password) gatePassword.value = stored.password;
});
function onUnlocked(){
// hide gate, show form
document.getElementById('passwordGate').style.display = 'none';
registerForm.style.display = 'flex';
document.getElementById('cardTitle').textContent = 'Student Registration Form';
document.getElementById('cardSubtitle').textContent = 'Fill the form below and submit.';
pcStatus.textContent = 'Form unlocked — enter details';
// store unlocked marker
localStorage.setItem('ctrs_unlocked_at', new Date().toISOString());
}
/* -------------------------
Save locally
------------------------- */
saveLocalBtn.addEventListener('click', () => {
const data = collectForm();
if(!data) return;
localStorage.setItem('ctrs_data', JSON.stringify(data));
statusMsg.textContent = 'Saved locally in browser storage.';
statusMsg.style.color = 'rgba(150,255,200,0.95)';
});
/* -------------------------
Collect form
------------------------- */
function collectForm(){
const name = stuName.value.trim(), cls = stuClass.value.trim(), roll = stuRoll.value.trim(), pass = stuPass.value;
if(!name || !cls || !roll || !pass){
statusMsg.textContent = 'All fields required.';
statusMsg.style.color = 'rgba(255,180,180,0.95)';
return null;
}
return { name, class: cls, roll, password: pass, savedAt: new Date().toISOString() };
}
/* -------------------------
Submit form -> scanner -> PDF creation
------------------------- */
submitBtn.addEventListener('click', async () => {
const data = collectForm();
if(!data) return;
// save locally
localStorage.setItem('ctrs_data', JSON.stringify(data));
// show submitted message & start fake fingerprint scanning
pcStatus.textContent = 'Submitted successfully to Suman Kumar';
showScanner();
// create PDF & trigger download
await createAndDownloadPDF(data);
// after scanning completes, show options
setTimeout(() => {
scannerArea.style.display = 'none';
openScannerBtn.style.display = 'inline-block';
pcStatus.textContent = 'Ready — use Settings for extra options';
statusMsg.textContent = 'Submission complete — PDF downloaded.';
statusMsg.style.color = 'rgba(150,255,200,0.95)';
}, 4200);
});
/* show fake scanner */
function showScanner(){
scannerArea.style.display = 'flex';
openScannerBtn.style.display = 'none';
scannerText.textContent = 'Scanning fingerprint...';
}
/* open scanner manual */
openScannerBtn.addEventListener('click', () => {
if(scannerArea.style.display === 'none'){
showScanner();
setTimeout(()=>{ scannerArea.style.display='none'; openScannerBtn.style.display='inline-block'; }, 4200);
}
});
/* create and download PDF */
async function createAndDownloadPDF(data){
try {
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ unit:'pt', format:'a4' });
doc.setFontSize(18);
doc.text('CTRS — Student Registration', 40, 60);
doc.setFontSize(12);
const lines = [
`Name: ${data.name}`,
`Class: ${data.class}`,
`Roll Number: ${data.roll}`,
`Password (record): ${'●'.repeat(String(data.password||'').length)}`,
`Saved at: ${data.savedAt || new Date().toISOString()}`
];
let y = 100;
for(let l of lines){
doc.text(l, 40, y);
y += 22;
}
// add small developer footer
doc.setFontSize(10);
doc.text('Generated by CTRS App — Developer: Suman Kumar', 40, y+20);
// Trigger download (browser will prompt save location)
const filename = DEFAULT_FILE_PREFIX + '_' + (data.name.replace(/\s+/g,'_')||'student') + '.pdf';
doc.save(filename);
} catch(err){
console.error('PDF generation failed', err);
alert('PDF generation failed: ' + err);
}
}
/* -------------------------
Settings open/close & wallpaper change
------------------------- */
openSettingsBtn.addEventListener('click', () => {
settingsPanel.style.display = 'block';
settingsPanel.setAttribute('aria-hidden','false');
});
iconSettings.addEventListener('click', () => {
openSettingsBtn.click();
});
closeSettingsBtn.addEventListener('click', () => {
settingsPanel.style.display = 'none';
settingsPanel.setAttribute('aria-hidden','true');
});
wallpaperSelect.addEventListener('change', (e) => {
applyWallpaper(e.target.value);
saveState();
});
animSelect.addEventListener('change', (e) => { /* Not used heavily, reserved for animation styles */ saveState(); });
function applyWallpaper(key){
bgMode = key || 'bg1';
// refresh/breathe
}
/* -------------------------
Simulated device scanning (includes Redmi 9)
------------------------- */
scanDevicesBtn.addEventListener('click', () => {
scanResult.textContent = 'Scanning nearby devices...';
scanResult.style.color = 'rgba(255,255,255,0.9)';
setTimeout(()=>{
const found = [
{ name: 'Redmi 9', rssi: '-45 dBm' },
{ name: 'Galaxy S20', rssi: '-60 dBm' },
{ name: 'Lenovo-PC', rssi: '-72 dBm' }
];
scanResult.innerHTML = '<strong>Found devices:</strong><br>' + found.map(f => `${f.name} (${f.rssi})`).join('<br>');
}, 1400);
});
/* -------------------------
Developer exclamation (password-protected)
------------------------- */
devExclaim.addEventListener('click', () => {
const p = prompt('Enter developer password:');
if(p === APP_PASS){
alert('Developer: Suman Kumar\nBest Developer — HTML Perfection Leader\nContact:
[email protected]');
} else {
alert('Incorrect developer password.');
}
});
/* -------------------------
Simulate icon clicks (quick shortcuts)
------------------------- */
document.getElementById('iconReg').addEventListener('click', () => {
// focus on gate password
gatePassword.focus();
});
document.getElementById('iconFiles').addEventListener('click', () => {
alert('Files app (demo): Local data saved in browser storage.');
});
document.getElementById('iconWeb').addEventListener('click', () => {
alert('Browser (demo): This is a local demo app.');
});
/* -------------------------
On load: autofocus gate
------------------------- */
window.addEventListener('load', () => {
gatePassword.focus();
// load any saved data to form
const saved = JSON.parse(localStorage.getItem('ctrs_data') || '{}');
if(saved && saved.name){
stuName.value = saved.name;
stuClass.value = saved.class;
stuRoll.value = saved.roll;
stuPass.value = saved.password;
}
});
/* ============================
Accessibility: keyboard support
============================ */
document.addEventListener('keydown', (e) => {
if(e.key === 'Enter'){
const active = document.activeElement;
if(active === gatePassword) gateSubmit.click();
else if(active && active.tagName === 'INPUT' && registerForm.style.display === 'flex') submitBtn.click();
}
});
/* Save settings on unload */
window.addEventListener('beforeunload', () => saveState());
/* End of script */
</script>
</body>
</html>