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>Login - The Black Hole Bay</title> 7 <link rel="icon" type="image/jpeg" href="/images/icon-haloween.jpg"> 8 <link href="css/normalize.css" rel="stylesheet" type="text/css"> 9 <link href="css/tpb.css" rel="stylesheet" type="text/css"> 10 <style> 11 :root { --bg-dark: #050505; --bg-darker: #020202; --bg-card: #0d0d0d; --border-color: #1a1a1a; --text-primary: #e0e0e0; --text-secondary: #888888; --accent-orange: #ff6b35; } 12 * { box-sizing: border-box; } 13 body { background-color: var(--bg-dark); background-image: url('https://www.transparenttextures.com/patterns/stardust.png'); background-attachment: fixed; color: var(--text-primary); font-family: 'Segoe UI', sans-serif; margin: 0; min-height: 100vh; min-height: 100svh; padding: 0 20px; overflow-y: auto; } 14 .auth-shell { min-height: 100vh; min-height: 100svh; display: grid; place-items: center; } 15 .auth-card { margin: 20px auto; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 16px; padding: 40px; width: 100%; max-width: 420px; box-shadow: 0 8px 24px rgba(0,0,0,0.8); animation: fadeIn 0.3s ease; } 16 @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } 17 .logo-wrap { text-align: center; margin-bottom: 30px; } 18 .logo-wrap img { width: 80px; height: 80px; border-radius: 16px; border: 2px solid #fff; box-shadow: 0 8px 20px rgba(0,0,0,0.5); } 19 .logo-wrap h1 { margin: 15px 0 5px 0; font-size: 28px; color: #fff; } 20 .logo-wrap p { margin: 0; color: var(--text-secondary); font-size: 14px; } 21 .tab-row { display: flex; gap: 10px; margin-bottom: 30px; background: var(--bg-darker); padding: 6px; border-radius: 12px; border: 1px solid var(--border-color); } 22 .tab { flex: 1; padding: 10px; text-align: center; background: transparent; border: 1px solid transparent; border-radius: 8px; cursor: pointer; color: var(--text-secondary); font-weight: 600; transition: 0.2s; font-size: 14px; } 23 .tab.active { background: var(--accent-orange); color: #fff; } 24 .input-group { margin-bottom: 20px; } 25 .input { width: 100%; background: var(--bg-darker); border: 1px solid var(--border-color); outline: none; padding: 15px 20px; font-size: 16px; border-radius: 10px; color: #fff; box-sizing: border-box; } 26 .input:focus { border-color: var(--accent-orange); outline: none; } 27 .tos-label { display: flex; align-items: flex-start; gap: 10px; width: 100%; margin: 0; color: var(--text-secondary); font-size: 13px; line-height: 1.6; } 28 .tos-label input[type="checkbox"] { flex: 0 0 16px; width: 16px !important; min-width: 16px !important; max-width: 16px; height: 16px; margin: 3px 0 0; } 29 .tos-label span { flex: 1; min-width: 0; } 30 .btn-3d { width: 100%; font: inherit; background-color: #2a2a2a; border: 0; color: #e0e0e0; border-radius: 9999px; font-size: 1rem; padding: 0.8em 1.2em; font-weight: 600; text-shadow: 0 0.0625em 0 #000; box-shadow: inset 0 0.0625em 0 0 #3a3a3a, 0 0.0625em 0 0 #252525, 0 0.125em 0 0 #202020, 0 0.25em 0 0 #1c1c1c, 0 0.3125em 0 0 #181818, 0 0.375em 0 0 #141414, 0 0.425em 0 0 #101010, 0 0.425em 0.5em 0 #0a0a0a; transition: 0.15s ease; cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: 8px; margin-top: 10px; } 31 .btn-3d:active { translate: 0 0.225em; box-shadow: inset 0 0.03em 0 0 #3a3a3a, 0 0.03em 0 0 #252525, 0 0.0625em 0 0 #202020, 0 0.125em 0 0 #1c1c1c, 0 0.125em 0 0 #181818, 0 0.2em 0 0 #141414, 0 0.225em 0 0 #101010, 0 0.225em 0.375em 0 #0a0a0a; } 32 .error { color: var(--accent-orange); text-align: center; margin-top: 15px; font-size: 13px; min-height: 20px; } 33 .back-link { display: block; text-align: center; margin-top: 25px; color: var(--text-secondary); text-decoration: none; font-size: 13px; } 34 .back-link:hover { color: #fff; } 35 @media(max-height:650px){.auth-card{margin:16px 0;padding:28px}.logo-wrap{margin-bottom:20px}.tab-row{margin-bottom:18px}.input-group{margin-bottom:14px}} 36 </style> 37<link rel="stylesheet" href="/css/site-layout.css"></head> 38<body> 39<main class="auth-shell"> 40<div class="auth-card"> 41 <div class="logo-wrap"> 42 <img src="/images/icon-haloween.jpg" alt="Logo"> 43 <h1>Black Hole Bay</h1> 44 <p>Access your account to upload torrents</p> 45 </div> 46 <div class="tab-row"> 47 <div class="tab active" id="login-tab" onclick="switchTab('login')">Login</div> 48 <div class="tab" id="register-tab" onclick="switchTab('register')">Register</div> 49 </div> 50 <form id="auth-form" onsubmit="handleSubmit(event)"> 51 <div class="input-group"><input type="text" id="username" class="input" placeholder="Username (3-20 chars)" required></div> 52 <div class="input-group"><input type="password" id="password" class="input" placeholder="Password (min 8 chars)" required></div> 53 <div id="confirm-group" class="input-group" style="display:none;"><input type="password" id="confirm" class="input" placeholder="Confirm Password"></div> 54 <div id="tos-group" class="input-group" style="display:none;"> 55 <label class="tos-label" for="accept-tos"> 56 <input type="checkbox" id="accept-tos">
57 <span>I have read and accept the <a href="/tos" target="_blank" style="color:var(--accent-orange);">Terms of Service</a> and the <a href="/privacy" target="_blank" style="color:var(--accent-orange);">Privacy Policy</a>.</span> 58 </label> 59 </div> 60 <button type="submit" class="btn-3d" id="submit-btn">Login</button> 61 <div class="error" id="error-msg"></div> 62 </form> 63 <a href="/" class="back-link"><< Back to Search</a> 64 <a href="/report.html#suggest" class="back-link" style="margin-top:10px;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px;vertical-align:-2px;"><path stroke-linecap="round" stroke-linejoin="round" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.488.76a2 2 0 01-1.576.897h-3.31a2 2 0 01-1.577-.897l-.488-.76z"/></svg> Have a feature idea? Suggest it here</a> 65 <a href="/apply" class="back-link" style="margin-top:10px;"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px;vertical-align:-2px;"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.903 0l1.286 3.958a1 1 0 00.95.69h4.162c.969 0 1.371 1.24.588 1.81l-3.367 2.446a1 1 0 00-.363 1.118l1.286 3.958c.3.922-.755 1.688-1.539 1.118l-3.367-2.446a1 1 0 00-1.175 0l-3.367 2.446c-.783.57-1.838-.196-1.539-1.118l1.286-3.958a1 1 0 00-.363-1.118L2.98 9.385c-.783-.57-.38-1.81.588-1.81h4.162a1 1 0 00.95-.69l1.286-3.958z"/></svg> Want to help build the site? Join the team</a> 66</div> 67</main>
68<script> 69 let mode = 'login'; 70 function switchTab(m) { 71 mode = m; 72 document.getElementById('login-tab').classList.toggle('active', m === 'login'); 73 document.getElementById('register-tab').classList.toggle('active', m === 'register'); 74 document.getElementById('confirm-group').style.display = m === 'register' ? 'block' : 'none'; 75 document.getElementById('tos-group').style.display = m === 'register' ? 'block' : 'none'; 76 document.getElementById('submit-btn').textContent = m === 'login' ? 'Login' : 'Create Account'; 77 document.getElementById('error-msg').textContent = ''; 78 } 79 async function handleSubmit(e) { 80 e.preventDefault(); 81 const u = document.getElementById('username').value; 82 const p = document.getElementById('password').value; 83 const c = document.getElementById('confirm').value; 84 const err = document.getElementById('error-msg'); 85 err.textContent = ''; 86 87 if (mode === 'register' && p !== c) { err.textContent = 'Passwords do not match'; return; } 88 if (mode === 'register' && !document.getElementById('accept-tos').checked) { err.textContent = 'You must accept the Terms of Service and Privacy Policy'; return; } 89 90 try { 91 const res = await fetch(`/api/auth/${mode}`, { 92 method: 'POST', 93 headers: { 'Content-Type': 'application/json' }, 94 body: JSON.stringify({ username: u, password: p, acceptToS: mode === 'register' }) 95 }); 96 const data = await res.json(); 97 if (!res.ok) { err.textContent = data.error || 'Failed'; return; } 98 sessionStorage.setItem('session_token', data.token); 99 sessionStorage.setItem('username', data.user.username); 100 window.location.href = '/profile.html?u=' + encodeURIComponent(data.user.username); 101 } catch(err) { 102 err.textContent = 'Network error'; 103 } 104 } 105</script>
vendor: 2 bytes, line 105
105
106<script defer src="/js/site-footer.js"></script>
106<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v4bc70e2c01a94c73b74392e4234840661791215815920" integrity="sha512-L0ha0OXavK/8okipN9F8BtP84dg9DUhPERbBXzwI6dgTA55d2+yweo3pn5CSFYs45/r8md2+xvUPtTdvTNRfjA==" data-cf-beacon='{"version":"2024.11.0","token":"fed1a331b87d4dc7b361c56f56c914c2","r":1,"spa":2}' crossorigin="anonymous"></script>
106 107</body> 108</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.