Files
root 22a3078af9 Add admin panel, authentication, and first-run setup wizard for v1.0
Implements credentialed admin panel and multi-step setup wizard so new
users can configure location, receivers, and preferences without editing
JSON files. Adds bcrypt password auth with session cookies, setup lockout
after first run, and expanded config schema with backward compatibility.

New files: admin/{html,css,js}, setup/{html,css,js}
Modified: server.py (auth, setup, admin APIs), index.html (dynamic title),
pixel-view.js (site/display config), requirements.txt (bcrypt),
config.json.example (full schema)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-08 08:35:07 -07:00

337 lines
5.6 KiB
CSS

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(180deg, #2c3e50 0%, #1a252f 100%);
color: #fcfcfc;
font-family: 'Courier New', monospace;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.hidden { display: none !important; }
.setup-container {
max-width: 560px;
width: 100%;
}
/* Progress */
.progress-bar {
height: 6px;
background: rgba(92, 148, 252, 0.2);
border-radius: 3px;
margin-bottom: 8px;
overflow: hidden;
}
.progress-fill {
height: 100%;
width: 0%;
background: #fcd444;
border-radius: 3px;
transition: width 0.4s ease;
}
.progress-steps {
display: flex;
justify-content: space-between;
margin-bottom: 24px;
padding: 0 4px;
}
.step-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(92, 148, 252, 0.3);
border: 2px solid #5c94fc;
transition: all 0.3s;
}
.step-dot.active {
background: #fcd444;
border-color: #fcd444;
}
.step-dot.done {
background: #54fc54;
border-color: #54fc54;
}
/* Steps */
.step {
display: none;
background: rgba(52, 73, 94, 0.9);
border: 3px solid #5c94fc;
border-radius: 12px;
padding: 32px;
text-align: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
animation: fadeIn 0.3s ease;
}
.step.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.step-icon {
font-size: 48px;
color: #fcd444;
margin-bottom: 12px;
}
.retro-title {
font-family: 'Press Start 2P', monospace;
color: #fcd444;
text-shadow: 2px 2px 0px #000;
font-size: 20px;
margin-bottom: 16px;
}
.step-title {
font-family: 'Press Start 2P', monospace;
color: #fcd444;
text-shadow: 2px 2px 0px #000;
font-size: 14px;
margin-bottom: 12px;
}
.step-desc {
color: #b4d4ec;
font-size: 14px;
line-height: 1.6;
margin-bottom: 16px;
}
.feature-list {
list-style: none;
margin-bottom: 24px;
text-align: left;
display: inline-block;
}
.feature-list li {
padding: 4px 0;
color: #b4d4ec;
font-size: 13px;
}
.feature-list li::before {
content: '\2713 ';
color: #54fc54;
font-weight: bold;
}
/* Forms */
.form-group {
margin-bottom: 16px;
text-align: left;
}
.form-group label {
display: block;
font-family: 'Press Start 2P', monospace;
font-size: 9px;
color: #b4d4ec;
margin-bottom: 6px;
}
.form-row {
display: flex;
gap: 16px;
}
.form-row .form-group {
flex: 1;
}
input[type="password"],
input[type="text"],
input[type="number"],
textarea,
select {
background: rgba(0, 0, 0, 0.5);
border: 2px solid #5c94fc;
border-radius: 6px;
color: #fcfcfc;
font-family: 'Courier New', monospace;
font-size: 14px;
padding: 10px 12px;
width: 100%;
outline: none;
transition: border-color 0.2s;
}
input:focus, textarea:focus, select:focus {
border-color: #fcd444;
}
select option {
background: #2c3e50;
color: #fcfcfc;
}
textarea {
resize: vertical;
}
/* Buttons */
.btn {
font-family: 'Press Start 2P', monospace;
font-size: 11px;
padding: 10px 20px;
border: 2px solid #5c94fc;
border-radius: 6px;
background: rgba(92, 148, 252, 0.2);
color: #fcfcfc;
cursor: pointer;
transition: all 0.15s;
}
.btn:hover {
background: rgba(92, 148, 252, 0.4);
transform: translateY(-1px);
}
.btn:active {
transform: translateY(1px);
}
.btn-primary {
background: rgba(252, 212, 68, 0.3);
border-color: #fcd444;
color: #fcd444;
}
.btn-primary:hover {
background: rgba(252, 212, 68, 0.5);
}
.btn-large {
font-size: 12px;
padding: 14px 32px;
}
.btn-detect {
font-size: 9px;
padding: 8px 14px;
margin-bottom: 12px;
border-color: #54fc54;
color: #54fc54;
}
.btn-detect:hover {
background: rgba(84, 252, 84, 0.2);
}
.step-buttons {
display: flex;
justify-content: space-between;
margin-top: 24px;
gap: 12px;
}
/* Messages */
.error-msg {
color: #fc5454;
font-size: 12px;
margin-top: 8px;
}
.status-msg {
font-size: 12px;
padding: 8px 12px;
border-radius: 6px;
margin-bottom: 12px;
}
.status-msg.success {
color: #54fc54;
background: rgba(84, 252, 84, 0.1);
border: 1px solid rgba(84, 252, 84, 0.3);
}
.status-msg.info {
color: #54d4fc;
background: rgba(84, 212, 252, 0.1);
border: 1px solid rgba(84, 212, 252, 0.3);
}
.status-msg.error {
color: #fc5454;
background: rgba(252, 84, 84, 0.1);
border: 1px solid rgba(252, 84, 84, 0.3);
}
/* Summary */
.summary-box {
background: rgba(0, 0, 0, 0.4);
border: 2px solid #5c94fc;
border-radius: 8px;
padding: 16px;
text-align: left;
margin-bottom: 20px;
}
.summary-row {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px solid rgba(92, 148, 252, 0.2);
font-size: 12px;
}
.summary-row:last-child {
border-bottom: none;
}
.summary-label {
color: #b4d4ec;
font-family: 'Press Start 2P', monospace;
font-size: 8px;
}
.summary-value {
color: #fcd444;
}
/* Mobile */
@media (max-width: 480px) {
.step {
padding: 20px;
}
.retro-title {
font-size: 16px;
}
.step-title {
font-size: 12px;
}
.form-row {
flex-direction: column;
gap: 0;
}
.step-buttons {
flex-direction: column;
}
.step-buttons .btn {
width: 100%;
}
}