feat: implement Story-Modus with chapter selector, Professor Atomus dialogs, level constraints, success modals, and localStorage saves

This commit is contained in:
kreidler90 2026-07-04 12:51:41 +00:00
parent d2253bfac3
commit 1577c68564
3 changed files with 632 additions and 43 deletions

292
app.js
View File

@ -5,6 +5,8 @@ const discoveryBook = document.getElementById('discovery-book');
const discoveryProgress = document.getElementById('discovery-progress'); const discoveryProgress = document.getElementById('discovery-progress');
const atomCountEl = document.getElementById('atom-count'); const atomCountEl = document.getElementById('atom-count');
const moleculeCountEl = document.getElementById('molecule-count'); const moleculeCountEl = document.getElementById('molecule-count');
const deskTitle = document.getElementById('desk-title');
const deskSubtitle = document.getElementById('desk-subtitle');
// Main Modal Elements // Main Modal Elements
const infoModal = document.getElementById('info-modal'); const infoModal = document.getElementById('info-modal');
@ -16,6 +18,14 @@ const modalCloseBtn = document.getElementById('modal-close-btn');
const modalOverlay = document.querySelector('#info-modal .modal-overlay'); const modalOverlay = document.querySelector('#info-modal .modal-overlay');
const modalCloseIcon = document.querySelector('#info-modal .modal-close-icon'); const modalCloseIcon = document.querySelector('#info-modal .modal-close-icon');
// Story Success Modal Elements
const storySuccessModal = document.getElementById('story-success-modal');
const storySuccessLevelName = document.getElementById('story-success-level-name');
const storySuccessText = document.getElementById('story-success-text');
const storyNextLevelBtn = document.getElementById('story-next-level-btn');
const storySuccessCloseIcon = document.querySelector('#story-success-modal .modal-close-icon');
const storySuccessOverlay = document.querySelector('#story-success-modal .modal-overlay');
// PSE Modal Elements // PSE Modal Elements
const pseToggleBtn = document.getElementById('pse-toggle-btn'); const pseToggleBtn = document.getElementById('pse-toggle-btn');
const pseModal = document.getElementById('pse-modal'); const pseModal = document.getElementById('pse-modal');
@ -28,6 +38,14 @@ let elementsOnDesk = [];
let draggingElement = null; let draggingElement = null;
let offsetX = 0; let offsetX = 0;
let offsetY = 0; let offsetY = 0;
let gameMode = 'sandbox'; // 'sandbox' oder 'story'
let selectedPSEElement = null;
// Geladene Entdeckungen aus dem LocalStorage
let discoveredMolecules = new Set(JSON.parse(localStorage.getItem('chem_lab_discoveries') || '[]'));
let currentLevelIndex = parseInt(localStorage.getItem('chem_lab_story_level') || '0');
let completedLevels = JSON.parse(localStorage.getItem('chem_lab_story_completed') || '[]');
let currentAllowedAtoms = [];
// Elemente Datenbank für Spawnen (Symbole, Farben, Namen) // Elemente Datenbank für Spawnen (Symbole, Farben, Namen)
const elementDetails = { const elementDetails = {
@ -179,7 +197,7 @@ const recipes = [
ingredients: ['Cl', 'Cl'], // 2x Chlor ingredients: ['Cl', 'Cl'], // 2x Chlor
result: 'Cl₂ (Chlor)', result: 'Cl₂ (Chlor)',
color: '#55efc4', color: '#55efc4',
desc: 'Chlor-Gas ist giftig, hat einen stechenden Geruch und eine grüngelbe Farbe. Es wurde im Ersten Weltkrieg als Kampfgas eingesetzt, rettet heute aber als Desinfektionsmittel in Trinkwasser und Pools Millionen Leben.' desc: 'Chlor-Gas ist giftig, hat einen stechenden Geruch und eine grüngelbe Farbe. Es wurde im Ersten Weltkrieg als Kampfgas eingesetzt, rettet heute aber als Desinfektionsmittel in Trinkwasser und Pools genutzt.'
}, },
{ {
id: 'h2', id: 'h2',
@ -193,13 +211,58 @@ const recipes = [
ingredients: ['C', 'C', 'H', 'H', 'H', 'H'], // 2x Kohlenstoff, 4x Wasserstoff ingredients: ['C', 'C', 'H', 'H', 'H', 'H'], // 2x Kohlenstoff, 4x Wasserstoff
result: 'C₂H₄ (Ethen)', result: 'C₂H₄ (Ethen)',
color: '#ffeaa7', color: '#ffeaa7',
desc: 'Ethen (Ethylen) is ein gasförmiges Pflanzenhormon, das Früchte reifen lässt. Industriell ist es der absolut wichtigste Baustein zur Herstellung des Kunststoffs Polyethylen (PE).' desc: 'Ethen (Ethylen) ist ein gasförmiges Pflanzenhormon, das Früchte reifen lässt. Industriell ist es der absolut wichtigste Baustein zur Herstellung des Kunststoffs Polyethylen (PE).'
} }
]; ];
// Geladene Entdeckungen aus dem LocalStorage // Story-Modus Level-Datenbank
let discoveredMolecules = new Set(JSON.parse(localStorage.getItem('chem_lab_discoveries') || '[]')); const levels = [
let selectedPSEElement = null; {
id: 1,
title: "Die salzige Suppe",
goalFormula: "nacl",
allowedAtoms: ['Na', 'Cl'],
intro: "Hallo Lehrling! Schön dich im Labor zu sehen. Der herzhafte Eintopf unseres Kantinenkochs schmeckt heute nach gar nichts... Er hat das Salz vergessen! Kannst du ihm helfen und 1x Kochsalz (NaCl) synthetisieren? Ziehe einfach ein Natrium-Atom (Na) und ein Chlor-Atom (Cl) auf dem Tisch zusammen!",
successText: "Großartig! Der Eintopf ist gerettet und schmeckt hervorragend. Du hast soeben gelernt, dass aus zwei gefährlichen Reinstoffen (explosives Metall und giftiges Gas) ein lebenswichtiges Gewürz entstehen kann. Bereit für die nächste Herausforderung?",
reward: "Schaltet Level 2 frei"
},
{
id: 2,
title: "Das Lebenselixier",
goalFormula: "h2o",
allowedAtoms: ['H', 'O'],
intro: "Hervorragend gemacht! Jetzt haben wir aber ein anderes Problem: Der Wasserspender im Labor ist leer und die Hitze heute ist unerträglich. Wir brauchen dringend frisches Wasser (H₂O)! Synthetisiere uns ein Wassermolekül aus zwei Wasserstoff-Atomen (H) und einem Sauerstoff-Atom (O).",
successText: "Ah, erfrischend! Kaltes, sauberes H₂O. Wusstest du, dass Wassermoleküle wegen ihrer Polarität so genial zusammenhalten? Du bist auf dem besten Weg zum Meister-Alchemisten!",
reward: "Schaltet Level 3 frei"
},
{
id: 3,
title: "Der Mülleimerbrand",
goalFormula: "co2",
allowedAtoms: ['C', 'O'],
intro: "Achtung! Ein Missgeschick ist passiert: Jemand hat ein heißes Streichholz in den Mülleimer geworfen und es brennt! Wasser nützt hier nichts, wir brauchen ein erstickendes Gas. Synthetisiere schnell 1x Kohlendioxid (CO₂) aus einem Kohlenstoff-Atom (C) und zwei Sauerstoff-Atomen (O), um die Flammen zu löschen!",
successText: "Puh, gerettet! Das CO₂ hat den Sauerstoff verdrängt und das Feuer im Handumdrehen erstickt. Ein echter Lebensretter-Einsatz! Aber lüfte danach gut durch.",
reward: "Schaltet Level 4 frei"
},
{
id: 4,
title: "Dünger für die Ernte",
goalFormula: "nh3",
allowedAtoms: ['N', 'H'],
intro: "Ein lokaler Bauer hat uns um Hilfe gebeten. Seine Nutzpflanzen wachsen schlecht und er benötigt dringend Dünger. Der wichtigste Rohstoff dafür ist Ammoniak (NH₃). Synthetisiere ein Ammoniak-Molekül aus einem Stickstoff-Atom (N) und drei Wasserstoff-Atomen (H)!",
successText: "Hervorragende Arbeit! Das NH₃ ist fertig. Es riecht zwar extrem stechend nach Urin, aber ohne diesen Kunstdünger (Haber-Bosch-Verfahren) könnten wir heute nicht die gesamte Weltbevölkerung ernähren!",
reward: "Schaltet Level 5 frei"
},
{
id: 5,
title: "Die Verdauungshilfe",
goalFormula: "hcl",
allowedAtoms: ['H', 'Cl'],
intro: "Unser Labor-Maskottchen (ein kleiner gefräßiger Drache) hat Bauchschmerzen, weil er zu viel gefressen hat. Wir müssen seine Verdauung ankurbeln! Synthetisiere Salzsäure (HCl) aus einem Wasserstoff-Atom (H) und einem Chlor-Atom (Cl), um seinen Magensaft zu verstärken!",
successText: "Perfekt! Dem kleinen Drachen geht es schon viel besser. Salzsäure ist extrem sauer und zersetzt selbst zähes Fleisch im Handumdrehen. Du hast den Story-Modus abgeschlossen! Du bist jetzt ein zertifizierter Labor-Meister!",
reward: "Story-Modus abgeschlossen! 🎉"
}
];
// Initiales Laden // Initiales Laden
updateStats(); updateStats();
@ -403,6 +466,15 @@ function checkForReactions() {
renderDiscoveryBook(); renderDiscoveryBook();
} }
// Story-Modus Ziel prüfen
if (gameMode === 'story') {
const currentLevel = levels[currentLevelIndex];
if (recipe.id === currentLevel.goalFormula) {
handleLevelSuccess(currentLevel, recipe);
break;
}
}
// Info-Modal anzeigen (bei neuer Entdeckung) // Info-Modal anzeigen (bei neuer Entdeckung)
showModal(recipe, isNew); showModal(recipe, isNew);
@ -483,7 +555,7 @@ function showModal(recipe, isNew = true) {
modalFormula.innerHTML = prettyFormula; modalFormula.innerHTML = prettyFormula;
modalFormula.style.backgroundColor = recipe.color; modalFormula.style.backgroundColor = recipe.color;
// Reiner Name (Text in Klammern) // Reiner Name (Text in Klammern aus z.B. "H₂O (Wasser)")
const cleanName = recipe.result.substring(recipe.result.indexOf('(') + 1, recipe.result.indexOf(')')); const cleanName = recipe.result.substring(recipe.result.indexOf('(') + 1, recipe.result.indexOf(')'));
modalName.innerText = cleanName; modalName.innerText = cleanName;
@ -613,7 +685,7 @@ function selectElementSteckbrief(el, canSpawn = true) {
'metall': 'Metall' 'metall': 'Metall'
}; };
document.getElementById('steckbrief-category').innerText = categoryNames[el.category] || el.category; document.getElementById('steckbrief-category').innerText = categoryNames[el.category] || el.category;
document.getElementById('steckbrief-category').className = ''; // Reset document.getElementById('steckbrief-category').className = '';
document.getElementById('steckbrief-category').classList.add(el.category); document.getElementById('steckbrief-category').classList.add(el.category);
document.getElementById('steckbrief-number').innerText = el.number; document.getElementById('steckbrief-number').innerText = el.number;
@ -621,7 +693,7 @@ function selectElementSteckbrief(el, canSpawn = true) {
document.getElementById('steckbrief-desc').innerText = el.desc; document.getElementById('steckbrief-desc').innerText = el.desc;
// Spawnen-Button steuern // Spawnen-Button steuern
if (canSpawn) { if (canSpawn && (gameMode === 'sandbox' || currentAllowedAtoms.includes(el.symbol))) {
pseSpawnBtn.classList.remove('hidden'); pseSpawnBtn.classList.remove('hidden');
} else { } else {
pseSpawnBtn.classList.add('hidden'); pseSpawnBtn.classList.add('hidden');
@ -668,3 +740,207 @@ function renderBohrModel(electronsArray) {
shellsContainer.appendChild(shellDiv); shellsContainer.appendChild(shellDiv);
}); });
} }
// =========================================
// STORY MODE LOGIC
// =========================================
// Dom Tabs switching
const tabSandboxBtn = document.getElementById('tab-sandbox-btn');
const tabStoryBtn = document.getElementById('tab-story-btn');
const sandboxContentEl = document.getElementById('sandbox-content');
const storyContentEl = document.getElementById('story-content');
tabSandboxBtn.addEventListener('click', () => {
switchMode('sandbox');
});
tabStoryBtn.addEventListener('click', () => {
switchMode('story');
});
function switchMode(mode) {
gameMode = mode;
workspace.innerHTML = '';
elementsOnDesk = [];
updateStats();
closeModal();
closeStorySuccessModal();
if (mode === 'sandbox') {
tabSandboxBtn.classList.add('active');
tabStoryBtn.classList.remove('active');
sandboxContentEl.classList.remove('hidden');
storyContentEl.classList.add('hidden');
deskTitle.innerText = "Labor-Tisch (Sandbox)";
deskSubtitle.innerText = "Ziehe Atome übereinander, um Reaktionen frei auszulösen!";
currentAllowedAtoms = Object.keys(elementDetails);
} else {
tabSandboxBtn.classList.remove('active');
tabStoryBtn.classList.add('active');
sandboxContentEl.classList.add('hidden');
storyContentEl.classList.remove('hidden');
loadStoryLevel(currentLevelIndex);
}
}
function loadStoryLevel(index) {
if (index >= levels.length) {
index = levels.length - 1;
}
currentLevelIndex = index;
localStorage.setItem('chem_lab_story_level', currentLevelIndex);
const level = levels[currentLevelIndex];
currentAllowedAtoms = level.allowedAtoms;
deskTitle.innerText = `Labor-Tisch (Story: ${level.title})`;
const recipe = recipes.find(r => r.id === level.goalFormula);
const cleanName = recipe.result.substring(recipe.result.indexOf('(') + 1, recipe.result.indexOf(')'));
deskSubtitle.innerText = `Ziel: Synthetisiere ${cleanName}`;
// Level Auswahldots zeichnen
renderLevelDots();
// Quest Panel updaten
document.getElementById('quest-level-title').innerText = `Level ${level.id}: ${level.title}`;
document.getElementById('quest-intro-text').innerText = level.intro;
const prettyFormula = recipe.id.toUpperCase().replace(/\d/g, m => '<sub>' + m + '</sub>');
document.getElementById('quest-goal-text').innerHTML = `Erzeuge 1x ${prettyFormula} (${cleanName})`;
// Checkbox zurücksetzen
const checkbox = document.querySelector('.objective-checkbox');
const objectiveItem = document.querySelector('.objective-item');
if (checkbox) checkbox.innerText = "⬜";
if (objectiveItem) objectiveItem.classList.remove('completed');
// Spawnbare Atome im Story-Gitter rendern
renderStorySpawnButtons();
}
function renderLevelDots() {
const container = document.querySelector('.level-dots-grid');
if (!container) return;
container.innerHTML = '';
levels.forEach((lvl, idx) => {
const dot = document.createElement('div');
dot.classList.add('level-dot');
dot.innerText = lvl.id;
const isCompleted = completedLevels.includes(lvl.id);
const isActive = idx === currentLevelIndex;
const isLocked = idx > 0 && !completedLevels.includes(levels[idx - 1].id);
if (isLocked) {
dot.classList.add('locked');
} else {
if (isCompleted) dot.classList.add('completed');
if (isActive) dot.classList.add('active');
dot.addEventListener('click', () => {
workspace.innerHTML = '';
elementsOnDesk = [];
updateStats();
loadStoryLevel(idx);
});
}
container.appendChild(dot);
});
const completedCount = completedLevels.length;
document.getElementById('story-overall-progress').innerText = `${completedLevels.includes(5) ? 5 : Math.max(1, completedLevels.length + 1)}/5`;
}
function renderStorySpawnButtons() {
const grid = document.getElementById('story-elements-grid');
if (!grid) return;
grid.innerHTML = '';
currentAllowedAtoms.forEach(symbol => {
const details = elementDetails[symbol];
if (details) {
const btn = document.createElement('div');
btn.classList.add('spawn-btn');
btn.dataset.element = symbol;
btn.dataset.color = details.color;
btn.innerText = symbol;
btn.title = details.name;
btn.style.backgroundColor = details.color;
if (symbol === 'C' || symbol === 'Fe') {
btn.style.color = '#fff';
} else {
btn.style.color = '#333';
}
btn.addEventListener('click', () => {
spawnAtom(symbol, details.color);
});
grid.appendChild(btn);
}
});
}
function completedMoleculesAdd(levelId) {
if (!completedLevels.includes(levelId)) {
completedLevels.push(levelId);
localStorage.setItem('chem_lab_story_completed', JSON.stringify(completedLevels));
}
}
function handleLevelSuccess(level, recipe) {
const checkbox = document.querySelector('.objective-checkbox');
const objectiveItem = document.querySelector('.objective-item');
if (checkbox) checkbox.innerText = "✅";
if (objectiveItem) objectiveItem.classList.add('completed');
completedMoleculesAdd(level.id);
renderLevelDots();
// Zeige das große Level-Erfolgs-Modal nach einer kurzen Verzögerung
setTimeout(() => {
showStorySuccessModal(level, recipe);
}, 600);
}
function showStorySuccessModal(level, recipe) {
storySuccessLevelName.innerText = `Level ${level.id} abgeschlossen!`;
storySuccessText.innerText = level.successText;
if (currentLevelIndex === levels.length - 1) {
storyNextLevelBtn.innerText = "🏆 Story-Modus beenden!";
} else {
storyNextLevelBtn.innerText = "Nächstes Level ➡️";
}
storySuccessModal.classList.remove('hidden');
}
function closeStorySuccessModal() {
storySuccessModal.classList.add('hidden');
}
// Story Next Level Button Event
storyNextLevelBtn.addEventListener('click', () => {
closeStorySuccessModal();
workspace.innerHTML = '';
elementsOnDesk = [];
updateStats();
if (currentLevelIndex < levels.length - 1) {
currentLevelIndex++;
localStorage.setItem('chem_lab_story_level', currentLevelIndex);
loadStoryLevel(currentLevelIndex);
} else {
alert("Glückwunsch! Du hast alle Level abgeschlossen. Der Sandkasten-Modus (Sandbox) steht dir weiterhin zur Verfügung!");
switchMode('sandbox');
}
});
// Zusätzliche Modal Close-Events
if (storySuccessCloseIcon) storySuccessCloseIcon.addEventListener('click', closeStorySuccessModal);
if (storySuccessOverlay) storySuccessOverlay.addEventListener('click', closeStorySuccessModal);

View File

@ -9,12 +9,19 @@
<body> <body>
<div id="sidebar"> <div id="sidebar">
<div class="sidebar-header"> <div class="sidebar-header">
<h2>🧪 Labor</h2> <h2>🧪 Labor-Zentrale</h2>
<p>Atome spawnen & fusionieren</p> <p>Atome spawnen & fusionieren</p>
</div> </div>
<div class="sidebar-tabs">
<button id="tab-sandbox-btn" class="tab-btn active">🧪 Sandbox</button>
<button id="tab-story-btn" class="tab-btn">🏆 Story</button>
</div>
<!-- SANDBOX CONTENT -->
<div id="sandbox-content" class="tab-content">
<div id="elements-section"> <div id="elements-section">
<h3>Atome</h3> <h3>Atome spawnen</h3>
<div class="elements-grid"> <div class="elements-grid">
<div class="spawn-btn" data-element="H" data-color="#ff7675" title="Wasserstoff">H</div> <div class="spawn-btn" data-element="H" data-color="#ff7675" title="Wasserstoff">H</div>
<div class="spawn-btn" data-element="He" data-color="#e84393" title="Helium">He</div> <div class="spawn-btn" data-element="He" data-color="#e84393" title="Helium">He</div>
@ -33,17 +40,59 @@
<h3>📖 Lexikon</h3> <h3>📖 Lexikon</h3>
<span id="discovery-progress">0/18</span> <span id="discovery-progress">0/18</span>
</div> </div>
<div id="discovery-book"> <div id="discovery-book" class="book-list">
<!-- Dynamisch gefüllt durch app.js --> <!-- Dynamisch gefüllt durch app.js -->
</div> </div>
</div> </div>
</div> </div>
<!-- STORY CONTENT -->
<div id="story-content" class="tab-content hidden">
<div id="story-level-selector">
<div class="level-selector-header">
<h3>Kapitel-Auswahl</h3>
<span id="story-overall-progress">1/5</span>
</div>
<div class="level-dots-grid">
<!-- Level-Auswahlknöpfe [1] [2] etc. -->
</div>
</div>
<div id="story-quest-panel">
<div class="quest-card">
<div class="quest-header">
<span id="quest-level-title">Level 1: Suppensalz</span>
</div>
<div class="professor-dialog-box">
<div class="professor-avatar">👴</div>
<div class="professor-bubble">
<p id="quest-intro-text">Hallo Lehrling! Schön dich im Labor zu sehen...</p>
</div>
</div>
<div class="quest-objective-box">
<h4>Missionsziel:</h4>
<div class="objective-item">
<span class="objective-checkbox"></span>
<span id="quest-goal-text">Erzeuge 1x NaCl (Speisesalz)</span>
</div>
</div>
</div>
</div>
<div id="story-elements-section">
<h3>Verfügbare Labor-Atome</h3>
<div id="story-elements-grid" class="elements-grid">
<!-- Atome, die für dieses Level erlaubt sind -->
</div>
</div>
</div>
</div>
<div id="lab-desk"> <div id="lab-desk">
<div class="desk-header"> <div class="desk-header">
<div> <div>
<h2>Labor-Tisch</h2> <h2 id="desk-title">Labor-Tisch (Sandbox)</h2>
<p>Ziehe Atome übereinander, um Reaktionen auszulösen!</p> <p id="desk-subtitle">Ziehe Atome übereinander, um Reaktionen auszulösen!</p>
</div> </div>
<div class="desk-controls"> <div class="desk-controls">
<div id="stats"> <div id="stats">
@ -76,6 +125,26 @@
</div> </div>
</div> </div>
<!-- Story Success Modal -->
<div id="story-success-modal" class="modal hidden">
<div class="modal-overlay"></div>
<div class="modal-content">
<div class="modal-header">
<span class="modal-emoji">🏆</span>
<h2>Level abgeschlossen!</h2>
<button class="modal-close-icon">&times;</button>
</div>
<div class="modal-body">
<div class="professor-avatarlarge">👴</div>
<h3 id="story-success-level-name">Level 1 abgeschlossen</h3>
<p id="story-success-text">Beschreibung des Erfolgs...</p>
</div>
<div class="modal-footer">
<button id="story-next-level-btn">Nächstes Level ➡️</button>
</div>
</div>
</div>
<!-- INTERAKTIVES PERIODENSYSTEM (PSE) MODAL --> <!-- INTERAKTIVES PERIODENSYSTEM (PSE) MODAL -->
<div id="pse-modal" class="modal hidden"> <div id="pse-modal" class="modal hidden">
<div class="modal-overlay"></div> <div class="modal-overlay"></div>
@ -86,7 +155,6 @@
<button id="pse-close-icon" class="modal-close-icon">&times;</button> <button id="pse-close-icon" class="modal-close-icon">&times;</button>
</div> </div>
<div class="pse-modal-body"> <div class="pse-modal-body">
<!-- Linke Spalte: Das Gitter-System des Periodensystems -->
<div class="pse-grid-container"> <div class="pse-grid-container">
<div id="pse-grid"> <div id="pse-grid">
<!-- Dynamisch befüllt durch app.js --> <!-- Dynamisch befüllt durch app.js -->
@ -102,7 +170,6 @@
</div> </div>
</div> </div>
<!-- Rechte Spalte: Der Element-Steckbrief -->
<div id="pse-steckbrief"> <div id="pse-steckbrief">
<div class="steckbrief-empty"> <div class="steckbrief-empty">
<p>Klicke auf ein leuchtendes Element im Periodensystem, um den wissenschaftlichen Steckbrief zu öffnen!</p> <p>Klicke auf ein leuchtendes Element im Periodensystem, um den wissenschaftlichen Steckbrief zu öffnen!</p>
@ -125,7 +192,6 @@
<span id="steckbrief-mass" class="stat-value">1.008 u</span> <span id="steckbrief-mass" class="stat-value">1.008 u</span>
</div> </div>
</div> </div>
<!-- Bohr-Modell Visualisierung (CSS-Basiert) -->
<div class="bohr-model-container"> <div class="bohr-model-container">
<div class="bohr-nucleus"></div> <div class="bohr-nucleus"></div>
<div id="bohr-shells"> <div id="bohr-shells">

269
style.css
View File

@ -46,7 +46,7 @@ body {
.sidebar-header { .sidebar-header {
padding: 20px; padding: 20px;
border-bottom: 1px solid var(--border-color); padding-bottom: 12px;
} }
.sidebar-header h2 { .sidebar-header h2 {
@ -60,13 +60,60 @@ body {
color: var(--text-muted); color: var(--text-muted);
} }
/* Sidebar Mode Tabs */
.sidebar-tabs {
display: flex;
background-color: rgba(0,0,0,0.25);
border-bottom: 1px solid var(--border-color);
padding: 0 10px;
}
.tab-btn {
flex: 1;
background: none;
border: none;
color: var(--text-muted);
font-weight: bold;
font-size: 0.9rem;
padding: 12px;
cursor: pointer;
transition: color 0.2s;
position: relative;
}
.tab-btn:hover {
color: #fff;
}
.tab-btn.active {
color: var(--primary);
}
.tab-btn.active::after {
content: '';
position: absolute;
bottom: -1px;
left: 10%;
width: 80%;
height: 3px;
background-color: var(--primary);
border-radius: 3px;
}
.tab-content {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow-y: auto;
}
/* Elements Selector */ /* Elements Selector */
#elements-section { #elements-section, #story-elements-section {
padding: 20px; padding: 20px;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
#elements-section h3, #book-section h3 { #elements-section h3, #book-section h3, #story-elements-section h3 {
font-size: 0.9rem; font-size: 0.9rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 1px; letter-spacing: 1px;
@ -144,13 +191,13 @@ body {
padding-right: 5px; padding-right: 5px;
} }
#discovery-book::-webkit-scrollbar { #discovery-book::-webkit-scrollbar, .tab-content::-webkit-scrollbar {
width: 6px; width: 6px;
} }
#discovery-book::-webkit-scrollbar-track { #discovery-book::-webkit-scrollbar-track, .tab-content::-webkit-scrollbar-track {
background: transparent; background: transparent;
} }
#discovery-book::-webkit-scrollbar-thumb { #discovery-book::-webkit-scrollbar-thumb, .tab-content::-webkit-scrollbar-thumb {
background: var(--border-color); background: var(--border-color);
border-radius: 3px; border-radius: 3px;
} }
@ -192,7 +239,207 @@ body {
font-size: 0.85rem; font-size: 0.85rem;
} }
/* ========================================= */
/* STORY MODE DESIGN SPECIFICS */
/* ========================================= */
#story-level-selector {
padding: 15px 20px;
background-color: rgba(0,0,0,0.15);
border-bottom: 1px solid var(--border-color);
}
.level-selector-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.level-selector-header h3 {
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-muted);
}
#story-overall-progress {
background-color: #2ed573;
padding: 2px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: bold;
color: white;
}
.level-dots-grid {
display: flex;
gap: 8px;
justify-content: space-between;
}
.level-dot {
width: 38px;
height: 38px;
border-radius: 50%;
border: 2px solid var(--border-color);
background-color: rgba(255, 255, 255, 0.03);
color: var(--text-muted);
font-weight: bold;
font-size: 0.95rem;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.1s;
user-select: none;
}
.level-dot.locked {
opacity: 0.35;
cursor: not-allowed;
}
.level-dot.active {
border-color: var(--primary);
background-color: rgba(52, 152, 219, 0.15);
color: #fff;
transform: scale(1.05);
box-shadow: 0 0 10px rgba(52, 152, 219, 0.3);
}
.level-dot.completed {
border-color: #2ed573;
background-color: rgba(46, 213, 115, 0.15);
color: #2ed573;
}
.level-dot:hover:not(.locked) {
transform: scale(1.1);
}
/* Quest Card and Dialog Bubble */
#story-quest-panel {
padding: 20px;
border-bottom: 1px solid var(--border-color);
}
.quest-card {
background-color: rgba(255, 255, 255, 0.03);
border: 1px solid var(--border-color);
border-radius: 10px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 12px;
}
.quest-header {
border-bottom: 1px solid var(--border-color);
padding-bottom: 8px;
}
#quest-level-title {
font-weight: bold;
font-size: 1.05rem;
color: #ffeaa7;
}
.professor-dialog-box {
display: flex;
gap: 12px;
align-items: flex-start;
}
.professor-avatar {
font-size: 2.2rem;
background-color: rgba(0,0,0,0.25);
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
border: 1px solid var(--border-color);
flex-shrink: 0;
}
.professor-bubble {
background-color: rgba(0,0,0,0.2);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 10px 12px;
position: relative;
}
.professor-bubble::before {
content: '';
position: absolute;
left: -6px;
top: 15px;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-right: 6px solid var(--border-color);
}
.professor-bubble p {
font-size: 0.8rem;
line-height: 1.4;
color: #dfe6e9;
text-align: left;
}
.quest-objective-box h4 {
font-size: 0.75rem;
text-transform: uppercase;
color: var(--text-muted);
letter-spacing: 0.5px;
margin-bottom: 6px;
}
.objective-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
font-weight: bold;
background-color: rgba(0,0,0,0.15);
padding: 8px;
border-radius: 6px;
border: 1px solid rgba(255,255,255,0.02);
}
.objective-checkbox {
font-size: 0.9rem;
}
.objective-item.completed {
color: #2ed573;
text-decoration: line-through;
}
/* Large Avatar in Modal */
.professor-avatarlarge {
font-size: 3.5rem;
background-color: rgba(0,0,0,0.15);
width: 80px;
height: 80px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
border: 2px solid var(--border-color);
margin-bottom: 15px;
}
/* ========================================= */
/* Labor Tisch Layout */ /* Labor Tisch Layout */
/* ========================================= */
#lab-desk { #lab-desk {
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
@ -458,8 +705,8 @@ body {
justify-content: center; justify-content: center;
} }
#modal-close-btn { #modal-close-btn, #story-next-level-btn {
background-color: var(--primary); background-color: #2ed573;
color: white; color: white;
border: none; border: none;
padding: 10px 30px; padding: 10px 30px;
@ -471,11 +718,11 @@ body {
box-shadow: 0 4px 6px rgba(0,0,0,0.2); box-shadow: 0 4px 6px rgba(0,0,0,0.2);
} }
#modal-close-btn:hover { #modal-close-btn:hover, #story-next-level-btn:hover {
background-color: var(--primary-hover); background-color: #26af5a;
} }
#modal-close-btn:active { #modal-close-btn:active, #story-next-level-btn:active {
transform: scale(0.95); transform: scale(0.95);
} }