radical/login.html
King Omar 45f8c80ceb Restore original login step labels
Step 2: Choose Your Dictator (not 'Choose Your Enemy')
Step 3: Who Would You Kill? (not 'One Bullet in History')

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 03:16:23 +10:00

1354 lines
No EOL
56 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Emoji Login - RADICAL</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #ff0099;
--secondary: #333;
--dark: #000;
--light: #fff;
--border: #444;
--gray: #777;
--error: #ff3333;
--success: #33cc33;
--bg-gradient: linear-gradient(to bottom, #111, #000);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Roboto Mono', monospace;
background: var(--bg-gradient);
color: var(--light);
line-height: 1.6;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
width: 100%;
max-width: 500px;
margin: 0 auto;
text-align: center;
}
header {
margin-bottom: 30px;
}
h1 {
color: var(--primary);
font-size: 3rem;
letter-spacing: 1px;
margin-bottom: 10px;
}
.tagline {
font-size: 1.2rem;
letter-spacing: 3px;
margin-bottom: 10px;
font-weight: 300;
}
.login-container {
background-color: rgba(34, 34, 34, 0.7);
border: 1px solid var(--border);
border-radius: 0;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 0 20px rgba(255, 0, 153, 0.2);
}
.login-title {
font-size: 1.5rem;
margin-bottom: 20px;
color: var(--primary);
}
.emoji-grid {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 10px;
margin-bottom: 20px;
max-height: 300px;
overflow-y: auto;
padding: 10px;
border: 1px solid var(--border);
background-color: rgba(0, 0, 0, 0.5);
scrollbar-width: thin;
scrollbar-color: var(--primary) var(--dark);
}
/* Webkit browsers custom scrollbar */
.emoji-grid::-webkit-scrollbar {
width: 8px;
}
.emoji-grid::-webkit-scrollbar-track {
background: var(--dark);
border-radius: 4px;
}
.emoji-grid::-webkit-scrollbar-thumb {
background-color: var(--primary);
border-radius: 4px;
border: 2px solid var(--dark);
}
.emoji-grid::-webkit-scrollbar-thumb:hover {
background-color: #ff33aa;
}
.emoji-item {
font-size: 24px;
cursor: pointer;
padding: 5px;
border-radius: 4px;
transition: all 0.2s ease;
user-select: none;
}
.emoji-item:hover {
background-color: rgba(255, 255, 255, 0.1);
transform: scale(1.2);
}
.selected-emojis {
display: flex;
justify-content: center;
margin-bottom: 20px;
gap: 10px;
}
.emoji-slot {
width: 50px;
height: 50px;
border: 1px dashed var(--primary);
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
background-color: rgba(0, 0, 0, 0.5);
position: relative;
}
.emoji-slot.filled {
border-style: solid;
}
.emoji-slot .remove-emoji {
position: absolute;
top: -8px;
right: -8px;
background-color: var(--error);
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s;
}
.emoji-slot:hover .remove-emoji {
opacity: 1;
}
.action-buttons {
display: flex;
gap: 10px;
justify-content: center;
}
button {
background-color: var(--dark);
color: var(--light);
border: 1px solid var(--primary);
padding: 10px 20px;
font-family: 'Roboto Mono', monospace;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 500;
}
button:hover {
background-color: var(--primary);
color: var(--dark);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.clear-btn {
border-color: var(--gray);
}
.login-btn {
border-color: var(--primary);
}
.category-nav {
display: flex;
overflow-x: auto;
margin-bottom: 15px;
padding-bottom: 5px;
gap: 10px;
scrollbar-width: thin;
scrollbar-color: var(--primary) var(--dark);
}
/* Webkit browsers custom scrollbar */
.category-nav::-webkit-scrollbar {
height: 6px;
}
.category-nav::-webkit-scrollbar-track {
background: var(--dark);
border-radius: 3px;
}
.category-nav::-webkit-scrollbar-thumb {
background-color: var(--primary);
border-radius: 3px;
border: 1px solid var(--dark);
}
.section-title {
font-size: 1.4rem;
margin: 30px 0 10px;
color: var(--primary);
text-transform: uppercase;
letter-spacing: 1px;
}
.section-desc {
font-size: 0.9rem;
margin-bottom: 15px;
color: var(--light);
opacity: 0.8;
}
.dictator-selection {
display: flex;
gap: 10px;
overflow-x: auto;
padding: 10px 0;
margin-bottom: 25px;
scrollbar-width: thin;
scrollbar-color: var(--primary) var(--dark);
}
.dictator-selection::-webkit-scrollbar {
height: 6px;
}
.dictator-selection::-webkit-scrollbar-track {
background: var(--dark);
border-radius: 3px;
}
.dictator-selection::-webkit-scrollbar-thumb {
background-color: var(--primary);
border-radius: 3px;
border: 1px solid var(--dark);
}
.dictator-selection::-webkit-scrollbar-thumb:hover {
background-color: #ff33aa;
}
.dictator-card {
min-width: 120px;
max-width: 120px;
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid var(--border);
border-radius: 0;
overflow: hidden;
transition: all 0.3s ease;
cursor: pointer;
position: relative;
}
.dictator-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(255, 0, 153, 0.3);
}
.dictator-card.selected {
border: 2px solid var(--primary);
}
.dictator-card.selected::after {
content: "✓";
position: absolute;
top: 5px;
right: 5px;
background-color: var(--primary);
color: var(--dark);
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
}
.dictator-image {
width: 100%;
height: 150px;
object-fit: cover;
filter: grayscale(50%) contrast(120%) brightness(80%);
display: block;
}
.time-travel-targets {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 15px;
margin-bottom: 25px;
}
.target-card {
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid var(--border);
border-radius: 0;
padding: 10px;
transition: all 0.3s ease;
cursor: pointer;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
height: 100%;
}
.target-card:hover {
background-color: rgba(20, 20, 20, 0.8);
border-color: var(--primary);
}
.target-card.selected {
border: 2px solid var(--primary);
background-color: rgba(40, 0, 20, 0.4);
}
.target-card.selected::after {
content: "✓";
position: absolute;
top: 5px;
right: 5px;
background-color: var(--primary);
color: var(--dark);
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
}
.target-image {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: 50%;
filter: sepia(30%) contrast(120%);
margin-bottom: 10px;
border: 1px solid var(--border);
}
.target-card.selected .target-image {
filter: sepia(0%) contrast(120%) brightness(90%);
border-color: var(--primary);
}
.target-name {
font-size: 14px;
font-weight: 500;
text-align: center;
margin-bottom: 5px;
}
.target-desc {
font-size: 11px;
text-align: center;
color: var(--gray);
line-height: 1.3;
}
.category-btn {
padding: 5px 10px;
white-space: nowrap;
font-size: 12px;
}
.category-btn.active {
background-color: var(--primary);
color: var(--dark);
}
.search-container {
margin-bottom: 15px;
position: relative;
}
.search-input {
width: 100%;
padding: 8px 15px;
border: 1px solid var(--border);
background-color: rgba(0, 0, 0, 0.5);
color: var(--light);
font-family: 'Roboto Mono', monospace;
}
.search-icon {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
color: var(--gray);
}
.error-message {
color: var(--error);
margin-top: 10px;
font-size: 14px;
min-height: 20px;
}
.success-message {
color: var(--success);
margin-top: 10px;
font-size: 14px;
min-height: 20px;
}
.create-account {
margin-top: 20px;
font-size: 14px;
color: var(--gray);
}
.create-account a {
color: var(--primary);
text-decoration: none;
}
.create-account a:hover {
text-decoration: underline;
}
.tooltip {
position: fixed;
max-width: 200px;
background-color: rgba(0, 0, 0, 0.9);
color: white;
border: 1px solid var(--primary);
padding: 8px;
font-size: 12px;
z-index: 100;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
@media (max-width: 500px) {
.emoji-grid {
grid-template-columns: repeat(6, 1fr);
}
.emoji-slot {
width: 40px;
height: 40px;
font-size: 24px;
}
}
/* Animation effects */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.animate-fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s infinite;
}
.footer {
margin-top: 20px;
font-size: 12px;
color: var(--gray);
}
.how-it-works {
background: #050505;
border: 1px solid #222;
border-bottom: 2px solid var(--primary);
padding: 16px 20px;
margin-bottom: 20px;
display: flex;
flex-direction: column;
gap: 10px;
}
.hiw-step {
display: flex;
align-items: flex-start;
gap: 12px;
font-family: 'Roboto Mono', monospace;
font-size: 12px;
color: #aaa;
line-height: 1.5;
}
.hiw-num {
background: var(--primary);
color: #000;
font-weight: 700;
font-size: 11px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 1px;
}
.hiw-step strong { color: #fff; }
.anon-option {
margin-top: 16px;
padding: 14px 20px;
border: 1px solid #222;
background: #050505;
text-align: center;
font-size: 13px;
color: var(--gray);
font-family: 'Roboto Mono', monospace;
}
.anon-option span { display: block; }
.anon-link {
display: inline-block;
margin: 8px 0 6px;
color: var(--primary);
text-decoration: none;
font-weight: 700;
font-size: 14px;
}
.anon-link:hover { text-decoration: underline; }
.anon-note {
font-size: 11px;
color: #444;
line-height: 1.5;
}
</style>
</head>
<body>
<div class="container animate-fade-in">
<header>
<h1>RADICAL</h1>
<div class="tagline">THE UNDERGROUND PARLIAMENT</div>
<p>Login or sign up — no email, no password, just your private key</p>
</header>
<div class="how-it-works">
<div class="hiw-step"><span class="hiw-num">1</span><span><strong>New here?</strong> Pick any 5 emojis + your enemy + your target → your account is created on the spot.</span></div>
<div class="hiw-step"><span class="hiw-num">2</span><span><strong>Already have a key?</strong> Pick the same combination → you're logged back in.</span></div>
<div class="hiw-step"><span class="hiw-num">3</span><span><strong>Your combo IS your password.</strong> Nobody else can log in as you unless they know your exact 7 choices.</span></div>
</div>
<div class="login-container">
<h2 class="login-title">Step 1 — Pick 5 Emojis (your secret key)</h2>
<div class="search-container">
<input type="text" id="emoji-search" class="search-input" placeholder="Search emojis...">
<span class="search-icon">🔍</span>
</div>
<div class="category-nav" id="category-nav">
<!-- Categories will be added via JavaScript -->
</div>
<div class="selected-emojis">
<div class="emoji-slot" data-index="0"></div>
<div class="emoji-slot" data-index="1"></div>
<div class="emoji-slot" data-index="2"></div>
<div class="emoji-slot" data-index="3"></div>
<div class="emoji-slot" data-index="4"></div>
</div>
<div class="emoji-grid" id="emoji-grid">
<!-- Emojis will be loaded here via JavaScript -->
</div>
<h3 class="section-title">Step 2 — Choose Your Dictator</h3>
<p class="section-desc">Every revolutionary needs an enemy. Pick yours (part of your private key):</p>
<div class="dictator-selection" id="dictator-selection">
<!-- Dictators will be loaded here via JavaScript -->
</div>
<h3 class="section-title">Step 3 — Who Would You Kill?</h3>
<p class="section-desc">If you had one bullet and could go back in time, which freedom fighter gets it? (also part of your key):</p>
<div class="time-travel-targets" id="time-travel-targets">
<!-- Time travel targets will be loaded here via JavaScript -->
</div>
<div class="action-buttons">
<button class="clear-btn" id="clear-btn">Clear</button>
<button class="login-btn" id="login-btn" disabled>Login / Sign Up →</button>
</div>
<div class="error-message" id="error-message"></div>
<div class="success-message" id="success-message"></div>
</div>
<div class="create-account">
Your 5-emoji combination is your private key — it's both your login and your account. No email, no password, no tracking. <a href="#how" title="Learn more about RADICAL security">How it works</a>
</div>
<div class="anon-option">
<span>Don't want to log in?</span>
<a href="/" class="anon-link">Continue anonymously →</a>
<span class="anon-note">Anonymous users can still vote and post petitions. Login ties your activity to your AEC membership for verified petition signatures.</span>
</div>
<div class="footer">
RADICAL - Direct Democracy Movement 🇦🇺 &copy; 2026
</div>
</div>
<div class="tooltip" id="tooltip"></div>
<script>
// Emoji categories with sample emojis for each category
const emojiCategories = [
{ name: 'Frequently Used', emojis: [] },
{ name: 'Smileys & People', emojis: ['😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊', '😋', '😎', '😍', '😘', '🥰', '😗', '😙', '😚', '🙂', '🤗', '🤩', '🤔', '🤨', '😐', '😑', '😶', '🙄', '😏', '😣', '😥', '😮', '🤐', '😯', '😪', '😫', '😴', '😌', '😛', '😜', '😝', '🤤', '😒', '😓', '😔', '😕', '🙃', '🤑', '😲', '☹️', '🙁', '😖', '😞', '😟', '😤', '😢', '😭', '😦', '😧', '😨', '😩', '🤯', '😬', '😰', '😱', '🥵', '🥶', '😳', '🤪', '😵', '😡', '😠', '🤬', '😷', '🤒', '🤕', '🤢', '🤮', '🤧', '😇', '🤠', '🤡', '🥳', '🥴', '🥺', '🤥', '🤫', '🤭', '🧐', '🤓', '👶', '👦', '👧', '👨', '👩', '👴', '👵'] },
{ name: 'Animals & Nature', emojis: ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🦝', '🐻', '🐼', '🦘', '🦡', '🐨', '🐯', '🦁', '🐮', '🐷', '🐽', '🐸', '🐵', '🙈', '🙉', '🙊', '🐒', '🐔', '🐧', '🐦', '🐤', '🐣', '🐥', '🦆', '🦢', '🦉', '🦚', '🦜', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🐛', '🦋', '🐌', '🐚', '🐞', '🐜', '🦗', '🕷', '🕸', '🦂', '🦟', '🦠', '🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦀', '🐡', '🐠', '🐟', '🐬', '🐳', '🐋', '🦈', '🐊', '🐅', '🐆', '🦓', '🦍', '🐘', '🦏', '🦛', '🐪', '🐫', '🦙', '🦒', '🐃', '🐂', '🐄', '🐎', '🐖', '🐏', '🐑', '🐐', '🦌', '🐕', '🐩', '🐈', '🐓', '🦃', '🕊', '🐇', '🐁', '🐀', '🐿', '🦔', '🐾', '🐉', '🐲', '🌵', '🎄', '🌲', '🌳', '🌴', '🌱', '🌿', '☘️', '🍀', '🎍', '🎋', '🍃', '🍂', '🍁', '🍄', '🌾', '💐', '🌷', '🌹', '🥀', '🌺', '🌸', '🌼', '🌻'] },
{ name: 'Food & Drink', emojis: ['🍏', '🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🍈', '🍒', '🍑', '🥭', '🍍', '🥥', '🥝', '🍅', '🍆', '🥑', '🥦', '🥒', '🥬', '🌶', '🌽', '🥕', '🥔', '🍠', '🥐', '🍞', '🥖', '🥨', '🥯', '🧀', '🥚', '🍳', '🥞', '🥓', '🥩', '🍗', '🍖', '🌭', '🍔', '🍟', '🍕', '🥪', '🥙', '🌮', '🌯', '🥗', '🥘', '🥫', '🍝', '🍜', '🍲', '🍛', '🍣', '🍱', '🥟', '🍤', '🍙', '🍚', '🍘', '🍥', '🥠', '🥮', '🍢', '🍡', '🍧', '🍨', '🍦', '🥧', '🍰', '🎂', '🍮', '🍭', '🍬', '🍫', '🍿', '🧂', '🍩', '🍪', '🌰', '🥜', '🍯', '🥛', '🍼', '☕️', '🍵', '🥤', '🍶', '🍺', '🍻', '🥂', '🍷', '🥃', '🍸', '🍹', '🍾', '🥄', '🍴', '🍽', '🥣', '🥡', '🥢'] },
{ name: 'Activities', emojis: ['⚽️', '🏀', '🏈', '⚾️', '🥎', '🏐', '🏉', '🎾', '🥏', '🎱', '🏓', '🏸', '🥅', '🏒', '🏑', '🥍', '🏏', '⛳️', '🏹', '🎣', '🥊', '🥋', '🎽', '⛸', '🥌', '🛷', '🛹', '🎿', '⛷', '🏂', '🏋️‍♀️', '🏋🏻‍♂️', '🤼‍♀️', '🤼‍♂️', '🤸‍♀️', '🤸‍♂️', '⛹️‍♀️', '⛹️‍♂️', '🤺', '🤾‍♀️', '🤾‍♂️', '🏌️‍♀️', '🏌️‍♂️', '🏇', '🧘‍♀️', '🧘‍♂️', '🏄‍♀️', '🏄‍♂️', '🏊‍♀️', '🏊‍♂️', '🤽‍♀️', '🤽‍♂️', '🚣‍♀️', '🚣‍♂️', '🧗‍♀️', '🧗‍♂️', '🚵‍♀️', '🚵‍♂️', '🚴‍♀️', '🚴‍♂️', '🎪', '🎭', '🎨', '🎬', '🎤', '🎧', '🎼', '🎹', '🥁', '🎷', '🎺', '🎸', '🎻', '🎲', '🧩', '♟', '🎯', '🎳', '🎮', '🎰'] },
{ name: 'Travel & Places', emojis: ['🚗', '🚕', '🚙', '🚌', '🚎', '🏎', '🚓', '🚑', '🚒', '🚐', '🚚', '🚛', '🚜', '🛴', '🚲', '🛵', '🏍', '🚨', '🚔', '🚍', '🚘', '🚖', '🚡', '🚠', '🚟', '🚃', '🚋', '🚞', '🚝', '🚄', '🚅', '🚈', '🚂', '🚆', '🚇', '🚊', '🚉', '✈️', '🛫', '🛬', '🛩', '💺', '🛰', '🚀', '🛸', '🚁', '🛶', '⛵️', '🚤', '🛥', '🛳', '⛴', '🚢', '⚓️', '⛽️', '🚧', '🚦', '🚥', '🚏', '🗺', '🗿', '🗽', '🗼', '🏰', '🏯', '🏟', '🎡', '🎢', '🎠', '⛲️', '⛱', '🏖', '🏝', '🏜', '🌋', '⛰', '🏔', '🗻', '🏕', '⛺️', '🏠', '🏡', '🏘', '🏚', '🏗', '🏭', '🏢', '🏬', '🏣', '🏤', '🏥', '🏦', '🏨', '🏪', '🏫', '🏩', '💒', '🏛', '⛪️', '🕌', '🕍', '🕋', '⛩', '🛤', '🛣', '🗾', '🎑', '🏞', '🌅', '🌄', '🌠', '🎇', '🎆', '🌇', '🌆', '🏙', '🌃', '🌌', '🌉', '🌁'] },
{ name: 'Objects', emojis: ['⌚️', '📱', '📲', '💻', '⌨️', '🖥', '🖨', '🖱', '🖲', '🕹', '🗜', '💽', '💾', '💿', '📀', '📼', '📷', '📸', '📹', '🎥', '📽', '🎞', '📞', '☎️', '📟', '📠', '📺', '📻', '🎙', '🎚', '🎛', '⏱', '⏲', '⏰', '🕰', '⌛️', '⏳', '📡', '🔋', '🔌', '💡', '🔦', '🕯', '🗑', '🛢', '💸', '💵', '💴', '💶', '💷', '💰', '💳', '🧾', '💎', '⚖️', '🔧', '🔨', '⚒', '🛠', '⛏', '🔩', '⚙️', '⛓', '🔫', '💣', '🔪', '🗡', '⚔️', '🛡', '🚬', '⚰️', '⚱️', '🏺', '🧭', '🧱', '🔮', '🧿', '🧸', '📿', '💈', '⚗️', '🔭', '🧰', '🧲', '🧪', '🧫', '🧬', '🧯', '🔬', '🕳', '💊', '💉', '🌡', '🚽', '🚰', '🚿', '🛁', '🛀', '🛌', '🧻', '🧺', '🧹', '🧼', '🧽', '🛎', '🔑', '🗝', '🚪', '🛋', '🛏', '🛌', '🖼', '🛍', '🧳', '🛒', '🎁', '🎈', '🎏', '🎀', '🎊', '🎉', '🧨', '🎎', '🏮', '🎐', '🧧', '✉️', '📩', '📨', '📧', '💌', '📥', '📤', '📦', '🏷', '📪', '📫', '📬', '📭', '📮', '📯', '📜', '📃', '📄', '📑', '📊', '📈', '📉', '🗒', '🗓', '📆', '📅', '📇', '🗃', '🗳', '🗄', '📋', '📁', '📂', '🗂', '🗞', '📰', '📓', '📔', '📒', '📕', '📗', '📘', '📙', '📚', '📖', '🔖', '🔗', '📎', '🖇', '📐', '📏', '📌', '📍', '✂️', '🖊', '🖋', '✒️', '🖌', '🖍', '📝', '✏️', '🔍', '🔎', '🔏', '🔐', '🔒', '🔓'] },
{ name: 'Symbols', emojis: ['❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '☮️', '✝️', '☪️', '🕉', '☸️', '✡️', '🔯', '🕎', '☯️', '☦️', '🛐', '⛎', '♈️', '♉️', '♊️', '♋️', '♌️', '♍️', '♎️', '♏️', '♐️', '♑️', '♒️', '♓️', '🆔', '⚛️', '🉑', '☢️', '☣️', '📴', '📳', '🈶', '🈚️', '🈸', '🈺', '🈷️', '✴️', '🆚', '💮', '🉐', '㊙️', '㊗️', '🈴', '🈵', '🈹', '🈲', '🅰️', '🅱️', '🆎', '🆑', '🅾️', '🆘', '❌', '⭕️', '🛑', '⛔️', '📛', '🚫', '💯', '💢', '♨️', '🚷', '🚯', '🚳', '🚱', '🔞', '📵', '🚭', '❗️', '❕', '❓', '❔', '‼️', '⁉️', '🔅', '🔆', '〽️', '⚠️', '🚸', '🔱', '⚜️', '🔰', '♻️', '✅', '🈯️', '💹', '❇️', '✳️', '❎', '🌐', '💠', 'Ⓜ️', '🌀', '💤', '🏧', '🚾', '♿️', '🅿️', '🈳', '🈂️', '🛂', '🛃', '🛄', '🛅', '🚹', '🚺', '🚼', '🚻', '🚮', '🎦', '📶', '🈁', '🔣', '', '🔤', '🔡', '🔠', '🆖', '🆗', '🆙', '🆒', '🆕', '🆓', '0⃣', '1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟', '🔢', '#️⃣', '*️⃣', '⏏️', '▶️', '⏸', '⏯', '⏹', '⏺', '⏭', '⏮', '⏩', '⏪', '⏫', '⏬', '◀️', '🔼', '🔽', '➡️', '⬅️', '⬆️', '⬇️', '↗️', '↘️', '↙️', '↖️', '↕️', '↔️', '↪️', '↩️', '⤴️', '⤵️', '🔀', '🔁', '🔂', '🔄', '🔃', '🎵', '🎶', '', '', '➗', '✖️', '♾', '💲', '💱', '™️', '©️', '®️', '〰️', '➰', '➿', '🔚', '🔙', '🔛', '🔝', '🔜', '✔️', '☑️', '🔘', '⚪️', '⚫️', '🔴', '🔵', '🔺', '🔻', '🔸', '🔹', '🔶', '🔷', '🔳', '🔲', '▪️', '▫️', '◾️', '◽️', '◼️', '◻️', '⬛️', '⬜️', '🔈', '🔇', '🔉', '🔊', '🔔', '🔕', '📣', '📢', '👁‍🗨', '💬', '💭', '🗯', '♠️', '♣️', '♥️', '♦️', '🃏', '🎴', '🀄️', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛', '🕜', '🕝', '🕞', '🕟', '🕠', '🕡', '🕢', '🕣', '🕤', '🕥', '🕦', '🕧'] },
{ name: 'Flags', emojis: ['🏳️', '🏴', '🏁', '🚩', '🏳️‍🌈', '🇦🇺', '🇦🇹', '🇧🇪', '🇧🇷', '🇨🇦', '🇨🇱', '🇨🇳', '🇨🇴', '🇩🇰', '🇫🇮', '🇫🇷', '🇩🇪', '🇬🇷', '🇭🇰', '🇮🇳', '🇮🇩', '🇮🇪', '🇮🇱', '🇮🇹', '🇯🇵', '🇰🇷', '🇲🇽', '🇳🇱', '🇳🇿', '🇳🇴', '🇵🇭', '🇵🇱', '🇵🇹', '🇷🇺', '🇸🇦', '🇸🇬', '🇿🇦', '🇪🇸', '🇸🇪', '🇨🇭', '🇹🇭', '🇹🇷', '🇺🇦', '🇦🇪', '🇬🇧', '🇺🇸', '🇻🇳'] }
];
// Demo emoji combinations for login (in a real application, these would be stored securely)
const demoUsers = [
{ username: 'Radical', combination: ['🔥', '🇦🇺', '🤔', '🚀', '💯'], dictator: 'stalin' },
{ username: 'Admin', combination: ['🔒', '🔑', '👁️', '🛡️', '⚙️'], dictator: 'kim' },
{ username: 'Test', combination: ['😀', '😃', '😄', '😁', '😆'], dictator: 'hitler' }
];
// Dictator options
const dictators = [
{ id: 'stalin', name: 'Joseph Stalin', image: 'https://theradicalparty.com/memes/stalin.jpg' },
{ id: 'hitler', name: 'Adolf Hitler', image: 'https://theradicalparty.com/memes/hitler.jpg' },
{ id: 'kim', name: 'Kim Jong-un', image: 'https://theradicalparty.com/memes/kim.jpg' },
{ id: 'mao', name: 'Mao Zedong', image: 'https://theradicalparty.com/memes/mao.jpg' },
{ id: 'castro', name: 'Fidel Castro', image: 'https://theradicalparty.com/memes/fidel.jpg' },
{ id: 'putin', name: 'Vladimir Putin', image: 'https://theradicalparty.com/memes/putin.jpg' },
{ id: 'mussolini', name: 'Benito Mussolini', image: 'https://theradicalparty.com/memes/benito.jpg' },
{ id: 'pol', name: 'Pol Pot', image: 'https://theradicalparty.com/memes/pol.jpg' },
{ id: 'kanye', name: 'Kanye West', image: 'https://theradicalparty.com/memes/ye.jpg' },
{ id: 'khomeini', name: 'Ayatollah Khomeini', image: 'https://theradicalparty.com/memes/khomeini.jpg' },
{ id: 'netanyahu', name: 'Benjamin Netanyahu', image: 'https://theradicalparty.com/memes/netanyahu.jpg' },
{ id: 'zelensky', name: 'Volodymyr Zelensky', image: 'https://theradicalparty.com/memes/zelensky.jpg' },
{ id: 'gaddafi', name: 'Muammar Gaddafi', image: 'https://theradicalparty.com/memes/gaddafi.jpg' },
{ id: 'shapiro', name: 'Ben Shapiro', image: 'https://theradicalparty.com/memes/shapiro.jpg' },
{ id: 'musk', name: 'Elon Musk', image: 'https://theradicalparty.com/memes/musk.jpg' }
];
// Global variables
let selectedEmojis = [];
let currentCategory = 'Smileys & People';
let searchTimeout;
let loginAttempts = 0;
let selectedDictator = null;
let selectedTimeTarget = null;
// Time travel targets
const timeTargets = [
{ id: 'mlk', name: 'Martin Luther King Jr.', desc: 'Civil rights leader who advocated for nonviolent protest', image: 'https://theradicalparty.com/memes/mlk.jpg' },
{ id: 'gandhi', name: 'Mahatma Gandhi', desc: 'Led India to independence through nonviolent civil disobedience', image: 'https://theradicalparty.com/memes/gandhi.jpg' },
{ id: 'mandela', name: 'Nelson Mandela', desc: 'Anti-apartheid revolutionary and first Black president of South Africa', image: 'https://theradicalparty.com/memes/mandela.jpg' },
{ id: 'jesus', name: 'Jesus Christ', desc: 'Religious leader who preached equality, compassion, and rebellion against systems of power', image: 'https://theradicalparty.com/memes/jesus.jpg' },
{ id: 'xmen', name: 'Malcolm X', desc: 'African American Muslim minister and human rights activist', image: 'https://theradicalparty.com/memes/malcolm.jpg' },
{ id: 'chavez', name: 'Cesar Chavez', desc: 'Labor leader and civil rights activist for farm workers', image: 'https://theradicalparty.com/memes/chavez.jpg' },
{ id: 'milk', name: 'Harvey Milk', desc: 'One of the first openly gay elected officials in the US', image: 'https://theradicalparty.com/memes/harvey.jpg' },
{ id: 'tubman', name: 'Harriet Tubman', desc: 'Abolitionist who rescued enslaved people via the Underground Railroad', image: 'https://theradicalparty.com/memes/tubman.jpg' }
];
// Document ready
document.addEventListener('DOMContentLoaded', () => {
// Initialize the app
initApp();
});
// Initialize the application
function initApp() {
// Setup category navigation
setupCategoryNav();
// Load emojis for initial category
loadEmojisForCategory(currentCategory);
// Setup dictator selection
setupDictatorSelection();
// Setup time travel targets
setupTimeTargets();
// Add event listeners
setupEventListeners();
// Add randomly selected emojis to frequently used
populateFrequentlyUsed();
}
// Setup time travel targets
function setupTimeTargets() {
const targetContainer = document.getElementById('time-travel-targets');
if (!targetContainer) return;
// Clear any existing content
targetContainer.innerHTML = '';
// Add time travel target cards
timeTargets.forEach(target => {
const card = document.createElement('div');
card.className = 'target-card';
card.dataset.targetId = target.id;
const image = document.createElement('img');
image.className = 'target-image';
image.src = target.image;
image.alt = target.name;
image.loading = 'lazy';
image.onerror = function() { this.style.display='none'; };
const name = document.createElement('div');
name.className = 'target-name';
name.textContent = target.name;
const desc = document.createElement('div');
desc.className = 'target-desc';
desc.textContent = target.desc;
card.appendChild(image);
card.appendChild(name);
card.appendChild(desc);
// Add click event
card.addEventListener('click', () => {
selectTimeTarget(target.id);
});
targetContainer.appendChild(card);
});
}
// Select a time travel target
function selectTimeTarget(targetId) {
// Update selected target
selectedTimeTarget = targetId;
// Update UI
const cards = document.querySelectorAll('.target-card');
cards.forEach(card => {
if (card.dataset.targetId === targetId) {
card.classList.add('selected');
} else {
card.classList.remove('selected');
}
});
// Check if login button should be enabled
updateLoginButton();
// Clear any error messages
clearMessages();
}
// Setup dictator selection
function setupDictatorSelection() {
const dictatorSelection = document.getElementById('dictator-selection');
if (!dictatorSelection) return;
// Clear any existing content
dictatorSelection.innerHTML = '';
// Add dictator cards
dictators.forEach(dictator => {
const card = document.createElement('div');
card.className = 'dictator-card';
card.dataset.dictatorId = dictator.id;
const image = document.createElement('img');
image.className = 'dictator-image';
image.src = dictator.image;
image.alt = dictator.name;
image.loading = 'lazy';
image.onerror = function() { this.style.display='none'; };
const name = document.createElement('div');
name.className = 'dictator-name';
name.textContent = dictator.name;
card.appendChild(image);
card.appendChild(name);
// Add click event
card.addEventListener('click', () => {
selectDictator(dictator.id);
});
dictatorSelection.appendChild(card);
});
}
// Select a dictator
function selectDictator(dictatorId) {
// Update selected dictator
selectedDictator = dictatorId;
// Update UI
const cards = document.querySelectorAll('.dictator-card');
cards.forEach(card => {
if (card.dataset.dictatorId === dictatorId) {
card.classList.add('selected');
} else {
card.classList.remove('selected');
}
});
// Check if login button should be enabled
updateLoginButton();
// Clear any error messages
clearMessages();
}
// Setup category navigation
function setupCategoryNav() {
const categoryNav = document.getElementById('category-nav');
emojiCategories.forEach(category => {
const button = document.createElement('button');
button.className = 'category-btn';
button.textContent = category.name;
button.dataset.category = category.name;
if (category.name === currentCategory) {
button.classList.add('active');
}
button.addEventListener('click', () => {
// Remove active class from all buttons
document.querySelectorAll('.category-btn').forEach(btn => {
btn.classList.remove('active');
});
// Add active class to clicked button
button.classList.add('active');
// Load emojis for this category
currentCategory = category.name;
loadEmojisForCategory(currentCategory);
});
categoryNav.appendChild(button);
});
}
// Load emojis for a category
function loadEmojisForCategory(categoryName) {
const emojiGrid = document.getElementById('emoji-grid');
emojiGrid.innerHTML = '';
const category = emojiCategories.find(cat => cat.name === categoryName);
if (!category) return;
category.emojis.forEach(emoji => {
const emojiItem = document.createElement('div');
emojiItem.className = 'emoji-item';
emojiItem.textContent = emoji;
emojiItem.title = `Click to select ${emoji}`;
// Check if this emoji is already selected
if (selectedEmojis.includes(emoji)) {
emojiItem.style.opacity = '0.5';
}
emojiItem.addEventListener('click', () => {
selectEmoji(emoji);
});
// Show tooltip on hover
emojiItem.addEventListener('mouseenter', (e) => {
showTooltip(e, emoji);
});
emojiItem.addEventListener('mouseleave', () => {
hideTooltip();
});
emojiGrid.appendChild(emojiItem);
});
}
// Populate frequently used category with random emojis
function populateFrequentlyUsed() {
const allEmojis = [];
// Collect all emojis from all categories except Frequently Used
emojiCategories.forEach(category => {
if (category.name !== 'Frequently Used') {
allEmojis.push(...category.emojis);
}
});
// Shuffle and pick 30 random emojis
const shuffled = allEmojis.sort(() => 0.5 - Math.random());
const selected = shuffled.slice(0, 30);
// Set these as Frequently Used
const frequentlyUsedCategory = emojiCategories.find(cat => cat.name === 'Frequently Used');
if (frequentlyUsedCategory) {
frequentlyUsedCategory.emojis = selected;
}
}
// Setup event listeners
function setupEventListeners() {
const clearBtn = document.getElementById('clear-btn');
const loginBtn = document.getElementById('login-btn');
const searchInput = document.getElementById('emoji-search');
// Clear button event
clearBtn.addEventListener('click', clearSelection);
// Login button event
loginBtn.addEventListener('click', attemptLogin);
// Search input event
searchInput.addEventListener('input', () => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
const searchTerm = searchInput.value.trim().toLowerCase();
if (searchTerm) {
searchEmojis(searchTerm);
} else {
// If search is cleared, return to current category
loadEmojisForCategory(currentCategory);
}
}, 300);
});
}
// Select an emoji
function selectEmoji(emoji) {
// Check if already selected
const index = selectedEmojis.indexOf(emoji);
if (index !== -1) {
// If already selected, remove it
selectedEmojis.splice(index, 1);
updateSlots();
updateEmojiGrid();
return;
}
// Check if we already have 5 emojis
if (selectedEmojis.length >= 5) {
showError('You can only select 5 emojis. Remove one first.');
return;
}
// Add emoji to selected list
selectedEmojis.push(emoji);
// Update the UI
updateSlots();
updateEmojiGrid();
// Clear any error messages
clearMessages();
// Check if we can enable login button
updateLoginButton();
}
// Update login button state
function updateLoginButton() {
const loginBtn = document.getElementById('login-btn');
loginBtn.disabled = selectedEmojis.length !== 5 || !selectedDictator || !selectedTimeTarget;
}
// Update the emoji slots
function updateSlots() {
const slots = document.querySelectorAll('.emoji-slot');
slots.forEach((slot, index) => {
// Clear existing content
slot.innerHTML = '';
slot.classList.remove('filled');
if (selectedEmojis[index]) {
// Add emoji to slot
slot.textContent = selectedEmojis[index];
slot.classList.add('filled');
// Add remove button
const removeBtn = document.createElement('span');
removeBtn.className = 'remove-emoji';
removeBtn.textContent = '×';
removeBtn.title = 'Remove emoji';
removeBtn.addEventListener('click', (e) => {
e.stopPropagation();
removeEmojiAt(index);
});
slot.appendChild(removeBtn);
}
});
}
// Update emoji grid to show selected state
function updateEmojiGrid() {
const emojiItems = document.querySelectorAll('.emoji-item');
emojiItems.forEach(item => {
const emoji = item.textContent;
if (selectedEmojis.includes(emoji)) {
item.style.opacity = '0.5';
} else {
item.style.opacity = '1';
}
});
}
// Remove emoji at specific index
function removeEmojiAt(index) {
if (index >= 0 && index < selectedEmojis.length) {
selectedEmojis.splice(index, 1);
updateSlots();
updateEmojiGrid();
updateLoginButton();
}
}
// Clear selection
function clearSelection() {
selectedEmojis = [];
selectedDictator = null;
selectedTimeTarget = null;
// Clear emoji selection
updateSlots();
updateEmojiGrid();
// Clear dictator selection
const dictatorCards = document.querySelectorAll('.dictator-card');
dictatorCards.forEach(card => {
card.classList.remove('selected');
});
// Clear time target selection
const targetCards = document.querySelectorAll('.target-card');
targetCards.forEach(card => {
card.classList.remove('selected');
});
updateLoginButton();
clearMessages();
}
// Search emojis
function searchEmojis(term) {
const emojiGrid = document.getElementById('emoji-grid');
emojiGrid.innerHTML = '';
// Temporary array to hold matching emojis
const matchingEmojis = [];
// Check all categories for matching emojis
emojiCategories.forEach(category => {
category.emojis.forEach(emoji => {
// For simplicity, just check if emoji contains the term
// In a real app, you'd likely have emoji names/descriptions to search
if (emoji.toLowerCase().includes(term)) {
matchingEmojis.push(emoji);
}
});
});
// Display results
if (matchingEmojis.length === 0) {
emojiGrid.innerHTML = '<div style="grid-column: 1 / -1; text-align: center; padding: 20px;">No emojis found matching your search</div>';
return;
}
// Display matching emojis
matchingEmojis.forEach(emoji => {
const emojiItem = document.createElement('div');
emojiItem.className = 'emoji-item';
emojiItem.textContent = emoji;
// Check if this emoji is already selected
if (selectedEmojis.includes(emoji)) {
emojiItem.style.opacity = '0.5';
}
emojiItem.addEventListener('click', () => {
selectEmoji(emoji);
});
emojiGrid.appendChild(emojiItem);
});
}
// Attempt login/signup with emoji combination
// Updated attemptLogin function for login.html
function attemptLogin() {
// Validate that we have all required selections
if (selectedEmojis.length !== 5) {
showError('Please select exactly 5 emojis for your private key');
return;
}
if (!selectedDictator) {
showError('Please select your favorite dictator');
return;
}
if (!selectedTimeTarget) {
showError('Please select who you would eliminate if you could time travel');
return;
}
// Show loading state
const loginBtn = document.getElementById('login-btn');
loginBtn.disabled = true;
loginBtn.textContent = 'Processing...';
// Prepare data for the server
const loginData = {
emojiCombination: selectedEmojis,
selectedDictator: selectedDictator,
selectedTarget: selectedTimeTarget
};
// Send login request to server
fetch('https://theradicalparty.com/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(loginData)
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Store session in localStorage so main site recognises the logged-in user
localStorage.setItem('radical_user_id', data.userId);
localStorage.setItem('radical_username', data.username);
// Overwrite the anonymous user so their activity syncs
localStorage.setItem('radical_user', JSON.stringify({ id: data.userId, name: data.username }));
showSuccess(data.isNewUser ?
`Key registered! Welcome to RADICAL, ${data.username}!` :
`Welcome back, ${data.username}!`);
const dictator = dictators.find(d => d.id === selectedDictator);
const dictatorName = dictator ? dictator.name : 'Unknown';
const timeTarget = timeTargets.find(t => t.id === selectedTimeTarget);
const timeTargetName = timeTarget ? timeTarget.name : 'Unknown';
animateLoginSuccess(data.isNewUser, data.username, dictatorName, timeTargetName);
} else {
showError(data.message || 'Login failed. Please try again.');
loginBtn.disabled = false;
loginBtn.textContent = 'Enter RADICAL';
}
})
.catch(error => {
console.error('Login error:', error);
showError('Network error. Please try again.');
loginBtn.disabled = false;
loginBtn.textContent = 'Enter RADICAL';
});
}
// Compare two arrays for equality (order matters)
function compareArrays(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
// Show error message
function showError(message) {
const errorMessage = document.getElementById('error-message');
errorMessage.textContent = message;
errorMessage.style.display = 'block';
// Clear success message
document.getElementById('success-message').textContent = '';
}
// Show success message
function showSuccess(message) {
const successMessage = document.getElementById('success-message');
successMessage.textContent = message;
successMessage.style.display = 'block';
// Clear error message
document.getElementById('error-message').textContent = '';
}
// Clear messages
function clearMessages() {
document.getElementById('error-message').textContent = '';
document.getElementById('success-message').textContent = '';
}
// Show tooltip
function showTooltip(event, emoji) {
const tooltip = document.getElementById('tooltip');
tooltip.textContent = `Select ${emoji}`;
tooltip.style.left = `${event.clientX + 10}px`;
tooltip.style.top = `${event.clientY + 10}px`;
tooltip.style.opacity = '1';
}
// Hide tooltip
function hideTooltip() {
const tooltip = document.getElementById('tooltip');
tooltip.style.opacity = '0';
}
// Animate successful login/signup
function animateLoginSuccess(isNewUser, username, dictatorName, timeTargetName) {
// Disable inputs
document.getElementById('login-btn').disabled = true;
document.getElementById('clear-btn').disabled = true;
document.querySelectorAll('.emoji-item').forEach(item => {
item.style.pointerEvents = 'none';
});
document.querySelectorAll('.dictator-card, .target-card').forEach(card => {
card.style.pointerEvents = 'none';
});
// Add success class to container
document.querySelector('.login-container').classList.add('pulse');
// Get the selected emojis as a display string
const emojiDisplay = selectedEmojis.join(' ');
// Get the dictator image
const dictator = dictators.find(d => d.id === selectedDictator);
const dictatorImage = dictator ? dictator.image : '';
// Get the time target image
const timeTarget = timeTargets.find(t => t.id === selectedTimeTarget);
const timeTargetImage = timeTarget ? timeTarget.image : '';
setTimeout(() => {
document.querySelector('.login-container').innerHTML = `
<div style="text-align: center; padding: 40px 20px;">
<h2 style="color: var(--primary); margin-bottom: 20px;">🚀 Welcome to RADICAL, ${username}!</h2>
<p style="margin-bottom: 20px; color: #aaa;">
${isNewUser ?
'Your private key is registered. Welcome to the underground parliament!' :
'Access granted. Redirecting you now...'}
</p>
<div style="margin: 30px 0;">
<div style="text-align: center; margin-bottom: 20px;">
<p style="margin-bottom: 10px; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: #666;">YOUR PRIVATE KEY</p>
<div style="font-size: 36px; line-height: 1.2; border: 1px solid #333; padding: 12px; display: inline-block;">${emojiDisplay}</div>
</div>
<div style="display: flex; justify-content: center; align-items: center; gap: 30px; margin-top: 30px;">
<div style="text-align: center;">
<p style="margin-bottom: 10px; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #666;">YOUR ENEMY</p>
<img src="${dictatorImage}" style="width: 80px; height: 80px; object-fit: cover; border: 2px solid var(--primary);" onerror="this.style.display='none'">
<p style="margin-top: 5px; font-size: 12px; color: #aaa;">${dictatorName}</p>
</div>
<div style="text-align: center;">
<p style="margin-bottom: 10px; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #666;">YOUR TARGET</p>
<img src="${timeTargetImage}" style="width: 80px; height: 80px; object-fit: cover; border: 2px solid var(--primary); border-radius: 50%;" onerror="this.style.display='none'">
<p style="margin-top: 5px; font-size: 12px; color: #aaa;">${timeTargetName}</p>
</div>
</div>
</div>
<p style="color: #555; font-size: 11px; margin: 16px 0;">Remember your emoji combination — it's the only way back in.</p>
<p style="color: var(--primary); font-size: 13px;">Entering the underground parliament...</p>
<div style="display:inline-block;width:20px;height:20px;border:3px solid rgba(255,0,153,.3);border-radius:50%;border-top-color:var(--primary);animation:spin 1s ease-in-out infinite;margin-top:10px;"></div>
</div>
<style>@keyframes spin { to { transform: rotate(360deg); } }</style>
`;
// Redirect to main site after 2.5 seconds
setTimeout(() => { window.location.href = '/'; }, 2500);
}, 1000);
}
</script>
</body>
</html>