14 Commits
Author SHA1 Message Date
tezcat 2f3680752a Add Installation.md
installation.md is a readme to understand my approach to always data
2026-05-18 00:55:27 +02:00
tezcat 2d4f609562 fix path for cybersecurity issues
fix path in admin.php & add to config.php mdp to connect to panel admin ( config.php is not commited )
2026-05-18 00:37:51 +02:00
tezcat 30b858649a fix database Always Data
Fix Admin.php Database Links
2026-05-18 00:18:20 +02:00
tezcat a2fa460287 add coms for admin.php 2026-05-18 00:16:11 +02:00
tezcat 3d819510cd add base coms for api.php 2026-05-18 00:10:20 +02:00
tezcat 4f25b9a6cb add base coms for contact.php 2026-05-18 00:08:49 +02:00
tezcat ab30692b39 add base coms for style.css 2026-05-18 00:05:08 +02:00
tezcat 3c03359964 add base coms for main.js 2026-05-18 00:03:28 +02:00
tezcat 93456c555a add base coms for index.html 2026-05-18 00:00:51 +02:00
tezcat 828f2d1127 update Readme
Update Readme With Technologies
2026-05-17 23:55:19 +02:00
tezcat 034c8a9e8e Update Readme
Update Readme With Royalties Infos
2026-05-17 23:53:05 +02:00
tezcat adeccaa4d4 Update Readme
Update Readme With Recents Informations
2026-05-17 23:50:12 +02:00
tezcat 6adb3afae4 Add Gitignore & Create Config.php
For The Always DATA version, i have to hide mdp beacause this is not a server only in tailscale tunnel. So Config.php in gitignore is a file who i have to create in always data site to store mdp for beat security falls
2026-05-17 22:26:11 +02:00
tezcat c64a003f24 Update paths to Rules Compatibles 2026-05-17 22:14:02 +02:00
12 changed files with 122 additions and 24 deletions
+1
View File
@@ -0,0 +1 @@
www/config.php
+18 -15
View File
@@ -5,7 +5,8 @@ OpenPlanetsMaps is a project that gathers and structures astronomical data (imag
## Context and Hosting
This project was carried out as part of an exam presided over by **F. LEFEVRE**.
It is hosted and accessible online at the following address: [opm.nhkyllian.fr](https://opm.nhkyllian.fr)
It is hosted and accessible online at the following address: [opm.nhkyllian.fr](https://opm.nhkyllian.fr)
Secondary URL: [openplanetsmaps.alwaysdata.net](http://openplanetsmaps.alwaysdata.net)
## Database Structure
@@ -24,19 +25,21 @@ The core of the project relies on a MySQL/MariaDB database named `OpenPlanetsMap
The system also includes a `CONTACT` table intended to store messages and requests from a potential contact form (email, subject, request, attached file).
## Installation and Configuration
To set up the database locally (for example, with XAMPP, WAMP, or directly via MariaDB/MySQL):
1. Create a new database named `OpenPlanetsMaps` (recommended encoding: `utf8mb4_general_ci`).
2. Import the structure file to initialize the tables:
```bash
mysql -u user -p OpenPlanetsMaps < SRC/DATA/Structure.sql
```
3. Then import the data file to populate the database (currently contains Earth data):
```bash
mysql -u user -p OpenPlanetsMaps < SRC/DATA/DATA.sql
```
## Technologies
- Database: MySQL / MariaDB (generated via phpMyAdmin)
- Database: MySQL / MariaDB (generated via phpMyAdmin)
- Frontend: HTML, CSS, JavaScript
- Packaging: Electron Packager
- CI/CD: GitHub Actions
- Data format: JSON
## Releases (Mobile Apps)
Native mobile applications for this project are now available. You can download them directly from the **Releases** tab of this GitHub repository:
- **Android**: Download the `.apk` file to install the app on your Android device.
- **iOS**: Download the `.ipa` file to install the app on your iOS device.
## Data Source & License
The astronomical data (images, videos, and descriptions) provided in this project is sourced from the public NASA API.
As per NASA's media guidelines, these materials are in the **public domain** and are completely free to use without any royalties.
The code and structure of this project are open-source and entirely free to use.
View File
+31
View File
@@ -0,0 +1,31 @@
# Environnement de Déploiement : AlwaysData
Ce document explique la façon dont j'ai déployé et configuré le projet OpenPlanetsMaps sur mon espace d'hébergement AlwaysData.
## 1. Hébergement et Transfert de fichiers (FTP)
Le site est configuré en tant que site **PHP (version 8.x)** sur AlwaysData.
Pour la mise en ligne, j'ai utilisé le client FTP **FileZilla**. J'ai transféré l'intégralité du contenu de mon dossier local `www/` vers le répertoire racine web de mon serveur AlwaysData à l'aide des accès FTP fournis par l'hébergeur.
## 2. Base de données
L'API et le site s'appuient sur une base de données MySQL/MariaDB hébergée sur AlwaysData.
- J'ai créé la base de données directement depuis le panel AlwaysData.
- J'ai ensuite utilisé l'outil **phpMyAdmin** fourni par l'hébergeur pour importer le script de structure `doc/Structure.sql`, ce qui a généré toutes les tables nécessaires (`EARTH`, `MARS`, ..., `CONTACT`).
- J'ai également importé le fichier `data.sql` via phpMyAdmin afin de peupler la base avec les données astronomiques de chaque planètes.
## 3. Configuration et Variables d'environnement
Pour des raisons de sécurité, les identifiants de la base de données ne sont pas codés en dur dans mes scripts publics. J'ai créé un fichier de configuration `config.php` directement sur le serveur distant, à la racine du site (`www/config.php`).
Ce fichier (non versionné sur GitHub) contient mes variables de production :
le fichier vous sera montré lors de la présentation.
## 4. Vérification finale
Une fois le déploiement terminé, j'ai effectué une série de tests sur ma version finale en production pour m'assurer que tout fonctionnait correctement :
- Accès à l'URL de mon site (ex: `https://openplanetsmaps.alwaysdata.net`).
- Vérification du bon affichage des données des planètes provenant de l'API.
- Test du formulaire de contact (l'insertion en base de données et le téléversement de fichiers sont opérationnels).
- Connexion à la page `/admin.php` avec mes identifiants pour tester l'ajout d'une entrée.
- Test du versionnage téléphone du site pour garantir une bonne adaptabilité sur mobile.
- Vérification minutieuse de l'ensemble du backlog fourni pour m'assurer de la totale conformité du livrable vis-à-vis des attentes de l'examen.
La version finale actuellement en ligne est parfaitement fonctionnelle.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

+14 -5
View File
@@ -1,9 +1,12 @@
<?php
/* --- SESSION & AUTHENTICATION --- */
session_start();
$config = require_once './config.php';
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'login') {
if ($_POST['username'] === 'admin' && $_POST['password'] === 'admin') {
if ($_POST['username'] === $config['admin_user'] && $_POST['password'] === $config['admin_pass']) {
$_SESSION['admin_logged_in'] = true;
header('Location: admin.php');
exit;
@@ -18,12 +21,14 @@ if (isset($_GET['logout'])) {
exit;
}
$host = '172.22.0.3';
$dbname = 'OpenPlanetsMaps';
$db_user = 'root';
$db_pass = 'admin123';
/* --- DATABASE CONFIGURATION --- */
$host = $config['host'];
$dbname = $config['dbname'];
$db_user = $config['username'];
$db_pass = $config['password'];
$message = '';
/* --- FORM PROCESSING & DB INSERTION --- */
if (isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'add') {
try {
$options = [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8", PDO::ATTR_EMULATE_PREPARES => false];
@@ -57,6 +62,7 @@ if (isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true
<!DOCTYPE html>
<html lang="en">
<head>
<!-- --- HEAD & STYLES --- -->
<meta charset="UTF-8">
<title>Admin Panel - OpenPlanetsMaps</title>
<link rel="stylesheet" href="style.css">
@@ -75,8 +81,10 @@ if (isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true
</style>
</head>
<body>
<!-- --- BODY & ADMIN PANEL --- -->
<div class="admin-box">
<?php if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true): ?>
<!-- --- LOGIN FORM --- -->
<h1>Admin Login</h1>
<?php if ($error): ?><p style="color: #f87171; text-align: center; margin-bottom: 1rem;"><?= $error ?></p><?php endif; ?>
<form method="POST">
@@ -87,6 +95,7 @@ if (isset($_SESSION['admin_logged_in']) && $_SESSION['admin_logged_in'] === true
</form>
<div class="links"><a href="index.html"> Back to site</a></div>
<?php else: ?>
<!-- --- ADD DATA FORM --- -->
<h1>Add a row</h1>
<?= $message ?>
<form method="POST">
+11 -4
View File
@@ -1,16 +1,20 @@
<?php
header('Content-Type: application/json');
$host = '172.22.0.3';
$dbname = 'OpenPlanetsMaps';
$username = 'root';
$password = 'admin123';
/* --- CONFIGURATION & SETUP --- */
$config = require_once 'config.php';
$host = $config['host'];
$dbname = $config['dbname'];
$username = $config['username'];
$password = $config['password'];
try {
/* --- DATABASE CONNECTION --- */
$options = [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8", PDO::ATTR_EMULATE_PREPARES => false];
$pdo = new PDO("mysql:host=$host;port=3306;dbname=$dbname;charset=utf8;protocol=tcp", $username, $password, $options);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/* --- REQUEST HANDLING --- */
$planetId = isset($_GET['planet']) ? $_GET['planet'] : '';
$allowedTables = [
@@ -27,6 +31,7 @@ try {
];
if ($planetId === 'quiz') {
/* --- QUIZ DATA GENERATION --- */
$queries = [];
$seed = date('Ymd');
foreach ($allowedTables as $key => $table) {
@@ -65,6 +70,7 @@ try {
exit;
}
/* --- PLANET DATA FETCHING --- */
if (!array_key_exists($planetId, $allowedTables)) {
echo json_encode([]);
exit;
@@ -77,6 +83,7 @@ try {
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($data);
} catch (PDOException $e) {
/* --- ERROR HANDLING --- */
http_response_code(500);
echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
}
+6
View File
@@ -1,8 +1,10 @@
<?php
/* --- SESSION & INITIALIZATION --- */
session_start();
$message_status = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
/* --- FORM PROCESSING --- */
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$subject = htmlspecialchars($_POST['objet']);
$message = htmlspecialchars($_POST['demande']);
@@ -11,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$file_path = null;
if (isset($_FILES['televersement']) && $_FILES['televersement']['error'] == UPLOAD_ERR_OK) {
/* --- FILE UPLOAD --- */
$file_tmp_name = $_FILES['televersement']['tmp_name'];
$file_name = $_FILES['televersement']['name'];
$file_size = $_FILES['televersement']['size'];
@@ -44,6 +47,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
if (!$has_error) {
/* --- DATABASE INSERTION --- */
try {
$host = '172.22.0.3';
$dbname = 'OpenPlanetsMaps';
@@ -67,11 +71,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<!DOCTYPE html>
<html lang="fr">
<head>
<!-- --- HEAD --- -->
<meta charset="UTF-8">
<title>Contact - OpenPlanetsMaps</title>
<link rel="stylesheet" href="style.css">
</head>
<body class="page-form">
<!-- --- BODY & FORM --- -->
<div class="admin-box">
<h1>Contact</h1>
<?= $message_status ?>
+18
View File
@@ -11,6 +11,7 @@
<body class="theme-home">
<div class="bg-animated"></div>
<!-- HEADER -->
<header>
<div class="menu-icon" onclick="toggleSidebar()"></div>
<h1>Open Planets Maps</h1>
@@ -20,6 +21,7 @@
</div>
</header>
<!-- SIDEBAR -->
<nav id="sidebar" class="sidebar">
<ul>
<li onclick="showLayer('home')">Home</li>
@@ -40,7 +42,9 @@
</ul>
</nav>
<!-- MAIN CONTENT -->
<main id="content-area">
<!-- HOME SECTION -->
<section id="layer-home" class="layer active">
<div class="main-img">
<iframe title="Solar System animation" frameborder="0" allow="autoplay; fullscreen; xr-spatial-tracking" src="https://sketchfab.com/models/b7c69a6b655b47c99f871d5ec5aee854/embed?autostart=1&ui_infos=0&ui_watermark=0&ui_controls=0"></iframe>
@@ -61,6 +65,7 @@
<div class="desc-box">Ready for launch? Open the side menu (☰) and select a destination to begin your journey.</div>
</section>
<!-- MERCURY SECTION -->
<section id="layer-mercury" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -86,6 +91,7 @@
</div>
</section>
<!-- VENUS SECTION -->
<section id="layer-venus" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -111,6 +117,7 @@
</div>
</section>
<!-- EARTH SECTION -->
<section id="layer-earth" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -136,6 +143,7 @@
</div>
</section>
<!-- MARS SECTION -->
<section id="layer-mars" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -161,6 +169,7 @@
</div>
</section>
<!-- JUPITER SECTION -->
<section id="layer-jupiter" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -186,6 +195,7 @@
</div>
</section>
<!-- SATURN SECTION -->
<section id="layer-saturn" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -211,6 +221,7 @@
</div>
</section>
<!-- URANUS SECTION -->
<section id="layer-uranus" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -236,6 +247,7 @@
</div>
</section>
<!-- NEPTUNE SECTION -->
<section id="layer-neptune" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -261,6 +273,7 @@
</div>
</section>
<!-- SUN SECTION -->
<section id="layer-sun" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -289,6 +302,7 @@
</div>
</section>
<!-- MOON SECTION -->
<section id="layer-moon" class="layer">
<div class="search-bar"><input type="text" placeholder="Multi-criteria search..."></div>
<div class="main-img">
@@ -317,6 +331,7 @@
</div>
</section>
<!-- QUIZ SECTION -->
<section id="layer-Quiz" class="layer">
<div class="desc-box">Test your knowledge of the solar system! Answer the questions below to see if you are a true space expert.</div>
@@ -339,10 +354,12 @@
</section>
</main>
<!-- FOOTER -->
<footer class="site-footer" onclick="openCredits()" title="Credits & About">
&copy; 2026 OpenPlanetsMaps. Royalty-free. <span class="footer-credits-hint">— Credits ↗</span>
</footer>
<!-- CREDITS MODAL -->
<div id="credits-overlay"></div>
<div id="credits-panel">
<button class="credits-close" onclick="closeCredits()"></button>
@@ -390,6 +407,7 @@
</div>
</div>
<!-- SCRIPTS -->
<script src="main.js"></script>
</body>
</html>
+6
View File
@@ -1,3 +1,4 @@
/* --- UI & NAVIGATION --- */
function toggleSidebar() {
document.getElementById('sidebar').classList.toggle('open');
}
@@ -24,6 +25,7 @@ function showLayer(layerId) {
const planetData = {};
const planetCols = {};
/* --- SEARCH & FILTERING --- */
function wireSearch(planetId) {
const layer = document.getElementById('layer-' + planetId);
if (!layer) return;
@@ -98,6 +100,7 @@ function filterTable(planetId, query) {
});
}
/* --- API & DATA FETCHING --- */
async function fetchData(planetId) {
const tbody = document.getElementById('tbody-' + planetId);
if (!tbody) return;
@@ -212,6 +215,7 @@ let quizQuestions = [];
let currentQuizIndex = 0;
let quizScore = 0;
/* --- QUIZ SYSTEM --- */
async function initQuiz() {
currentQuizIndex = 0;
quizScore = 0;
@@ -339,6 +343,7 @@ function checkAnswer(selected, correct, btn) {
}, 1800);
}
/* --- CREDITS MODAL --- */
function openCredits() {
document.getElementById('credits-panel').classList.add('open');
document.getElementById('credits-overlay').classList.add('open');
@@ -351,6 +356,7 @@ function closeCredits() {
document.body.style.overflow = '';
}
/* --- INITIALIZATION & MOBILE FALLBACK --- */
document.addEventListener('DOMContentLoaded', () => {
const overlay = document.getElementById('credits-overlay');
if (overlay) overlay.addEventListener('click', closeCredits);
+17
View File
@@ -1,3 +1,4 @@
/* --- FONTS & VARIABLES --- */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Orbitron:wght@400;600;700;900&family=Space+Mono:wght@400;700&display=swap');
:root {
@@ -21,6 +22,7 @@ body.theme-sun { --theme-color:#ffcc44; --theme-glow:rgba(255,180,40,.55);
body.theme-moon { --theme-color:#c8cfe8; --theme-glow:rgba(200,207,232,.35); --theme-subtle:rgba(200,207,232,.06); --bg-deep:#060608; --bg-mid:#0e0f14; --border:rgba(200,207,232,.12); --text-primary:#dde2f0; --text-secondary:#7e8ba8; --text-muted:#3c4258; }
body.theme-Quiz { --theme-color:#7eb8f7; --theme-glow:rgba(126,184,247,.35); --theme-subtle:rgba(126,184,247,.07); --bg-deep:#020510; --bg-mid:#060e24; --border:rgba(126,184,247,.13); --text-primary:#ddeeff; --text-secondary:#6a90b8; --text-muted:#2e4a6a; }
/* --- GLOBAL STYLES --- */
*,*::before,*::after { margin:0; padding:0; box-sizing:border-box; }
html, body { max-width:100vw; overflow-x:hidden; }
@@ -31,6 +33,7 @@ body {
transition:background-color .8s ease, color .3s ease;
}
/* --- ANIMATED BACKGROUND --- */
.bg-animated {
position:fixed; inset:0; z-index:-2;
background:radial-gradient(ellipse at 20% 10%, var(--bg-mid) 0%, var(--bg-deep) 60%);
@@ -93,6 +96,7 @@ body.theme-moon::before {
100% { opacity:.65; }
}
/* --- HEADER --- */
header {
display:flex; justify-content:space-between; align-items:center;
padding:0 2rem; height:64px;
@@ -131,6 +135,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
box-shadow:0 0 12px var(--theme-glow);
}
/* --- SIDEBAR --- */
.sidebar {
position:fixed; top:0; left:-300px; width:280px; height:100vh;
background:rgba(2,6,14,.96); backdrop-filter:blur(24px);
@@ -170,6 +175,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
.sidebar li.menu-category::after { display:none; }
.sidebar li.menu-category:hover { background:none; padding-left:1.75rem; text-shadow:none; color:var(--text-muted); }
/* --- LAYOUT & MAIN CONTENT --- */
#content-area {
flex:1; padding:2.5rem; display:flex;
max-width:1400px; margin:0 auto; width:100%;
@@ -180,6 +186,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
}
.layer.active { display:flex; }
/* --- COMPONENTS (Images, Boxes, Tickers) --- */
.main-img {
margin-bottom:2.5rem; position:relative;
border-radius:12px; overflow:hidden; border:1px solid var(--border);
@@ -259,6 +266,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
}
.ticker:hover { animation-play-state:paused; }
/* --- SEARCH BAR --- */
.search-bar { margin-bottom:2rem; position:relative; display:flex; justify-content:center; }
.search-bar::before {
content:'⌕'; position:absolute; left:calc(50% - 210px); top:50%;
@@ -279,6 +287,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
box-shadow:0 0 20px var(--theme-glow);
}
/* --- DATA TABLES --- */
.table-container { margin-bottom:3rem; }
.data-table { width:100%; max-width:1300px; margin:0 auto; border-collapse:collapse; font-size:.88rem; }
.data-table thead tr { background:rgba(255,255,255,.03); }
@@ -336,6 +345,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
.show-more-btn:hover::before { transform:scaleX(1); }
.show-more-btn:hover { box-shadow:0 0 24px var(--theme-glow); transform:translateY(1px); }
/* --- FOOTER --- */
.site-footer {
text-align:center; padding:1.25rem 2rem;
background:rgba(2,4,8,.7); backdrop-filter:blur(10px);
@@ -350,6 +360,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
.footer-credits-hint { opacity:.5; font-style:italic; transition:opacity .2s; }
.site-footer:hover .footer-credits-hint { opacity:1; color:var(--theme-color); }
/* --- QUIZ SYSTEM --- */
.daily-challenge-box {
margin:0 auto 2rem; max-width:680px; padding:1rem 1.5rem;
background:var(--theme-subtle); border:1px solid var(--border);
@@ -447,6 +458,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
/* --- CREDITS MODAL --- */
#credits-overlay {
position:fixed; inset:0; z-index:2000;
background:rgba(0,0,0,.7); backdrop-filter:blur(6px);
@@ -510,11 +522,13 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
.credits-footer { padding:1rem 2rem; border-top:1px solid var(--border); font-family:'Space Mono',monospace; font-size:.62rem; letter-spacing:.15em; color:var(--text-muted); flex-shrink:0; }
/* --- SCROLLBAR & SELECTION --- */
::-webkit-scrollbar { width:6px; }
::-webkit-scrollbar-track { background:var(--bg-deep); }
::-webkit-scrollbar-thumb { background:var(--theme-color); border-radius:3px; }
::selection { background:var(--theme-glow); color:#fff; }
/* --- KEYFRAMES --- */
@keyframes layerReveal {
from { opacity:0; transform:translateY(16px); filter:blur(4px); }
to { opacity:1; transform:translateY(0); filter:blur(0); }
@@ -544,6 +558,8 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
50% { transform:translateX(5px); }
75% { transform:translateX(-3px); }
}
/* --- MEDIA QUERIES --- */
@media (max-width:768px) {
#layer-Quiz .desc-box, #layer-Quiz .daily-challenge-box { display:none; }
}
@@ -562,6 +578,7 @@ header h1:hover { animation:glitch .4s steps(1) forwards; }
#quiz-img-preview img, #quiz-img-preview video { max-height:160px; width:auto; max-width:100%; margin:0 auto; }
}
/* --- ADMIN & FORM PAGES --- */
body.page-form { background-color: #0f172a; color: #e0e0e0; display: flex; flex-direction: row; justify-content: center; align-items: center; padding: 2rem; min-height: 100vh; overflow-x: auto; }
.admin-box { background-color: #1e293b; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); width: 100%; max-width: 500px; border: 1px solid #334155; }
.admin-box h1 { color: #00bfff; text-align: center; margin-bottom: 1.5rem; }