CSS
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Roboto+Mono:wght@300;400&display=swap');
body {
background-color: #111;
color: #0f0; /* Verde clasic de terminal */
font-family: 'Roboto Mono', monospace;
margin: 0;
padding: 20px;
overflow-y: auto; /* Permite scroll */
line-height: 1.6;
}
#container {
max-width: 900px;
margin: 20px auto;
background-color: #1a1a1a;
border: 2px solid #ff4500; /* Portocaliu de avertizare */
box-shadow: 0 0 25px rgba(255, 69, 0, 0.6);
padding: 25px;
border-radius: 8px;
display: flex;
flex-direction: column;
}
header {
text-align: center;
border-bottom: 1px dashed #ff4500;
margin-bottom: 20px;
padding-bottom: 15px;
}
header h1 {
color: #ff4500;
font-family: 'Orbitron', sans-serif;
margin: 0 0 10px 0;
animation: flicker-text 1.5s infinite alternate;
}
#timer-container {
font-size: 1.2em;
color: #f00; /* Roșu pentru timer */
font-weight: bold;
background-color: #330000;
padding: 5px 10px;
border-radius: 4px;
display: inline-block;
}
#timer {
font-family: 'Orbitron', sans-serif;
}
#system-core {
width: 150px;
height: 150px;
background: radial-gradient(circle, #ff4500 10%, #8b0000 70%, #111 100%);
border-radius: 50%;
margin: 20px auto;
position: relative;
border: 3px solid #ff6347;
animation: pulse-core 2s infinite ease-in-out;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
overflow: hidden; /* ascunde overflow animatie */
}
.core-light {
position: absolute;
width: 10%;
height: 10%;
background-color: #fff;
border-radius: 50%;
box-shadow: 0 0 15px #fff;
animation: core-light-blink 0.8s infinite alternate;
opacity: 0.8;
}
.core-text {
color: #fff;
font-weight: bold;
font-size: 0.9em;
text-shadow: 0 0 5px #000;
z-index: 1;
animation: text-glitch-subtle 3s infinite steps(8);
}
#output-container h2, #options-container h2 {
color: #ffa500; /* Portocaliu */
border-bottom: 1px solid #ffa500;
padding-bottom: 5px;
margin-top: 30px;
}
#output {
height: 300px;
background-color: #050505;
border: 1px solid #0a0a0a;
padding: 15px;
overflow-y: scroll; /* Scroll pentru text mult */
margin-bottom: 20px;
border-radius: 4px;
box-shadow: inset 0 0 10px rgba(0, 255, 0, 0.2);
}
#output p {
margin: 5px 0;
transition: opacity 0.5s ease-in-out;
white-space: pre-wrap; /* Pastreaza formatarea spatiilor */
word-wrap: break-word;
}
.system-message { color: #0f0; }
.info { color: #6495ed; /* Albastru Cornflower */ }
.warning { color: #ffd700; /* Auriu */ }
.error { color: #dc143c; /* Roșu Crimson */ font-weight: bold;}
.critical { color: #ff0000; font-weight: bold; animation: critical-flash 1s infinite; }
.success { color: #32cd32; /* Verde Lime */ font-weight: bold;} /* Teoretic, nu se ajunge aici */
.debug { color: #888; font-style: italic; font-size: 0.9em;}
#options {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
.option-button {
background-color: #333;
color: #0f0;
border: 1px solid #0f0;
padding: 12px 15px;
cursor: pointer;
font-family: 'Roboto Mono', monospace;
font-size: 1em;
border-radius: 4px;
transition: background-color 0.3s, color 0.3s, transform 0.1s;
text-align: center;
}
.option-button:hover:not(:disabled) {
background-color: #0f0;
color: #111;
box-shadow: 0 0 10px #0f0;
}
.option-button:active:not(:disabled) {
transform: scale(0.98);
}
.option-button:disabled {
background-color: #222;
color: #555;
border-color: #444;
cursor: not-allowed;
opacity: 0.6;
}
/* Ascunde elementul initial */
.hidden {
display: none !important;
}
/* Stiluri pentru finalul tragic */
#final-failure {
text-align: center;
margin-top: 40px;
padding: 30px;
border: 2px dashed #f00;
background-color: #200000;
animation: final-fade-in 2s ease-out forwards;
}
#final-failure h2 {
color: #f00;
font-family: 'Orbitron', sans-serif;
font-size: 2em;
}
.static-effect {
width: 100%;
height: 100px;
background: repeating-linear-gradient(#000 0px, #000 1px, #fff 1px, #fff 2px);
opacity: 0.1;
margin: 20px 0;
animation: static-anim 0.1s infinite;
}
.final-message {
font-size: 1.5em;
color: #aaa;
font-style: italic;
}
/* Animații Cheie */
@keyframes flicker-text {
0%, 100% { opacity: 1; text-shadow: 0 0 5px #ff4500; }
50% { opacity: 0.7; text-shadow: none; }
}
@keyframes pulse-core {
0%, 100% { transform: scale(1); box-shadow: 0 0 15px rgba(255, 69, 0, 0.5); }
50% { transform: scale(1.05); box-shadow: 0 0 30px rgba(255, 69, 0, 0.8); }
}
@keyframes core-light-blink {
0%, 100% { opacity: 0.2; }
50% { opacity: 0.9; }
}
@keyframes text-glitch-subtle {
0% { transform: translateX(0); }
10% { transform: translateX(-1px) translateY(1px); }
20% { transform: translateX(1px) translateY(-1px); }
30% { transform: translateX(-1px) translateY(-1px); }
40% { transform: translateX(1px) translateY(1px); }
50% { transform: translateX(0); }
100% { transform: translateX(0); }
}
@keyframes critical-flash {
0%, 100% { color: #f00; background-color: transparent;}
50% { color: #fff; background-color: #f00;}
}
@keyframes shake-hard {
0%, 100% { transform: translate(0, 0); }
10%, 30%, 50%, 70%, 90% { transform: translate(-8px, 8px) rotate(-2deg); }
20%, 40%, 60%, 80% { transform: translate(8px, -8px) rotate(2deg); }
}
@keyframes screen-glitch {
0% { filter: none; opacity: 1;}
10% { filter: hue-rotate(30deg) contrast(1.5); opacity: 0.8; transform: scale(1.01); }
20% { filter: none; opacity: 1; transform: scale(1);}
80% { filter: none; opacity: 1;}
90% { filter: sepia(1) blur(1px); opacity: 0.7; transform: skewX(-5deg); }
100% { filter: none; opacity: 1;}
}
@keyframes matrix-cascade {
0% { background-position: 0 0; }
100% { background-position: 0 100%; } /* Simplu, pentru a sugera mișcare */
}
@keyframes circuit-trace {
from { stroke-dashoffset: 1000; }
to { stroke-dashoffset: 0; }
}
@keyframes particle-implosion {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(0); opacity: 0; }
}
@keyframes static-anim {
0% { background-position: 0 0; }
10% { background-position: -5px -5px; }
20% { background-position: 5px 5px; }
/* ... add more random positions */
100% { background-position: 0 0; }
}
@keyframes final-fade-in {
from { opacity: 0; transform: translateY(20px);}
to { opacity: 1; transform: translateY(0); }
}
/* Stiluri specifice pentru animații adăugate de JS */
.is-shaking {
animation: shake-hard 0.5s ease-in-out;
}
.is-glitching {
animation: screen-glitch 1s linear infinite;
}
.is-matrixing {
background-image: linear-gradient(#0f0 1px, transparent 1px);
background-size: 100% 3px;
animation: matrix-cascade 0.5s linear infinite;
}
.is-imploding > * { /* Vizează copiii elementului */
animation: particle-implosion 1s forwards;
}
JAVASCRIPT
document.addEventListener('DOMContentLoaded', () => {
const outputElement = document.getElementById('output');
const optionsElement = document.getElementById('options');
const timerElement = document.getElementById('timer');
const containerElement = document.getElementById('container');
const systemCoreElement = document.getElementById('system-core');
const finalFailureElement = document.getElementById('final-failure');
const allOptionButtons = () => optionsElement.querySelectorAll('.option-button'); // Funcție pentru a re-selecta
let timeLeft = 300; // 5 minute în secunde
let timerInterval = null;
let isProcessing = false; // Previne acțiuni multiple simultan
let messageQueue = [];
let messageTimeout = null;
// --- Funcție pentru afișare mesaje cu delay și scroll ---
function processMessageQueue() {
if (messageQueue.length === 0) {
// Re-activează butoanele DUPĂ ce toate mesajele s-au afișat
if (isProcessing) {
enableOptions();
isProcessing = false;
removeTemporaryEffects(); // Curăță efectele temporare
}
return;
}
const { text, delay, className } = messageQueue.shift(); // Ia primul mesaj din coadă
messageTimeout = setTimeout(() => {
const p = document.createElement('p');
p.innerHTML = text; // Folosim innerHTML pentru a permite tag-uri simple ca <strong> sau <i>
if (className) {
p.classList.add(className);
} else {
p.classList.add('system-message'); // Clasa default
}
outputElement.appendChild(p);
outputElement.scrollTop = outputElement.scrollHeight; // Scroll automat jos
processMessageQueue(); // Procesează următorul mesaj
}, delay);
}
function addMessage(text, delay = 1000, className = '') {
messageQueue.push({ text, delay, className });
// Dacă nu se procesează deja, pornește procesarea
if (messageTimeout === null || messageQueue.length === 1) {
// Verificam daca setTimeout-ul e inactiv (sau e prima oara) inainte de a porni
// Asta evita porniri multiple daca se adauga mesaje rapid
if (!isProcessing || messageQueue.length === 1) {
clearTimeout(messageTimeout); // Asigura ca nu avem timeout-uri vechi
messageTimeout = setTimeout(processMessageQueue, 0); // Porneste imediat procesarea cozii
}
}
}
// --- Funcții Utilitare ---
function disableOptions() {
isProcessing = true;
allOptionButtons().forEach(button => button.disabled = true);
}
function enableOptions() {
// Verificăm dacă timer-ul încă rulează
if (timeLeft > 0) {
isProcessing = false;
allOptionButtons().forEach(button => button.disabled = false);
}
}
function removeTemporaryEffects() {
containerElement.classList.remove('is-shaking', 'is-glitching', 'is-matrixing', 'is-imploding');
// Poți adăuga aici și eliminarea altor clase specifice animațiilor
systemCoreElement.style.animation = 'pulse-core 2s infinite ease-in-out'; // Restaurează animația default
}
// --- Logică Timer ---
function updateTimer() {
const minutes = Math.floor(timeLeft / 60);
let seconds = timeLeft % 60;
seconds = seconds < 10 ? '0' + seconds : seconds; // Formatare 00
timerElement.textContent = `${minutes}:${seconds}`;
if (timeLeft <= 0) {
clearInterval(timerInterval);
triggerFinalFailure();
} else {
if (timeLeft <= 60 && timeLeft % 10 === 0) { // Avertisment în ultimul minut
addMessage(`[ALARMĂ] ${timeLeft} secunde rămase până la colaps! Grabă mare, prieteni!`, 500, 'critical');
} else if (timeLeft === 120) {
addMessage(`[AVERTISMENT] Două minute! Presiunea crește... la fel și temperatura procesorului. Miroase a ars?`, 1000, 'warning');
}
timeLeft--;
}
}
function startTimer() {
clearInterval(timerInterval); // Asigură că nu există alt timer
timerInterval = setInterval(updateTimer, 1000);
updateTimer(); // Afișează imediat timpul inițial
}
// --- Definiții Opțiuni Reparație (Complex & Unic) ---
const repairOptions = [
{
id: 'defrag-hamster',
buttonText: 'Rulează Defragmentatorul Cu Roată De Hamster',
action: async () => {
disableOptions();
addMessage(">> Inițiere protocol 'Hamster Puternic'...", 500, 'info');
addMessage(">> Se calibrează roata cuantică...", 1500, 'debug');
// Animatie: simulare rotație rapidă a nucleului
systemCoreElement.style.animation = 'spin-fast 1s linear infinite'; // Necesită @keyframes spin-fast
await new Promise(resolve => setTimeout(resolve, 2000)); // Așteaptă vizualizarea animației
addMessage(">> Hamsterul Gigel a început alergarea. Viteza: impresionantă!", 1000);
addMessage(">> Clustere de date sunt aruncate haotic. Pare... productiv?", 2000, 'warning');
addMessage(">> Gigel cere o pauză de semințe. Pauză refuzată. Continuă alergarea.", 1500);
addMessage(">> Detectată o creștere bruscă a entropiei... și a mirosului de blană arsă.", 2500, 'error');
// Animatie: Scuturare ecran
containerElement.classList.add('is-shaking');
await new Promise(resolve => setTimeout(resolve, 500)); // Așteaptă vizualizarea animației
addMessage("[EȘEC] Roata s-a blocat! Gigel a intrat în supra-sarcină și a demisionat. Sistemul e și mai fragmentat.", 1000, 'error critical');
systemCoreElement.style.animation = 'pulse-core 2s infinite ease-in-out'; // Oprește spin
// enableOptions(); // Se va face automat la finalul cozii de mesaje
}
},
{
id: 'curse-reversed',
buttonText: 'Inversează Polaritatea Blestemului Tehno-Magic',
action: async () => {
disableOptions();
addMessage(">> Se accesează arhivele oculte... parola: 'password123'. Uimitor.", 500, 'info');
addMessage(">> Încercare de a inversa fluxul de ghinion digital.", 1500, 'debug');
// Animatie: Glitch pe tot ecranul
containerElement.classList.add('is-glitching');
await new Promise(resolve => setTimeout(resolve, 2500));
addMessage(">> Rune digitale apar pe ecran... Asta nu era în manual.", 2000, 'warning');
addMessage(">> Se aud șoapte din difuzoare: 'Format C:?' Nu, nu, nu!", 1800, 'error');
addMessage(">> Sistemul începe să rânjească... Da, efectiv rânjește.", 2200, 'error');
// Animatie: Schimbare culori nucleu haotic
systemCoreElement.style.background = 'linear-gradient(45deg, #ff00ff, #00ffff, #ffff00, #ff0000)';
systemCoreElement.style.animation = 'color-cycle 0.5s infinite'; // Necesită @keyframes color-cycle
await new Promise(resolve => setTimeout(resolve, 3000));
addMessage("[EȘEC] Inversarea polarității a funcționat invers! Blestemul este acum de două ori mai puternic. Felicitări.", 1000, 'error critical');
// enableOptions(); // Se va face automat
}
},
{
id: 'coffee-boost',
buttonText: 'Injectează Cafea Extra-Strong Direct În Procesor',
action: async () => {
disableOptions();
addMessage(">> Preparare cafea de tip 'Apocalipsa Acum'. Concentrație: 99.9%", 500, 'info');
addMessage(">> Se localizează portul de injecție CPU (lângă cel de biscuiți).", 1500, 'debug');
// Animatie: Nucleul pulsează rapid și intens
systemCoreElement.style.animation = 'pulse-intense 0.5s infinite ease-in-out'; // Necesită @keyframes pulse-intense
await new Promise(resolve => setTimeout(resolve, 2000));
addMessage(">> Injecție începută... Se aud sunete de 'AHHHH, ENERGIE!' de la tranzistori.", 1000);
addMessage(">> Viteza de procesare a crescut cu 5000%! Calculează sensul vieții în 0.1 secunde.", 2000, 'success'); // Un pic de speranță falsă
addMessage(">> ...și acum cere mai multă cafea. Devine dependent.", 1500, 'warning');
addMessage(">> Supraîncălzire critică! Procesorul a început să topească placa de bază!", 2500, 'error');
// Animatie: Simulare topire/scurgeri din nucleu (poate cu CSS pseudo-elemente)
systemCoreElement.classList.add('is-melting'); // Necesită clasă și stiluri CSS
await new Promise(resolve => setTimeout(resolve, 1500));
addMessage("[EȘEC] Cafeaua a fost... prea eficientă. Procesorul s-a topit într-o băltoacă aromată. RIP.", 1000, 'error critical');
// enableOptions(); // Automat
}
},
{
id: 'matrix-cleanse',
buttonText: 'Curățare Cu Peria De Sârmă În Matricea Digitală',
action: async () => {
disableOptions();
addMessage(">> Intrare forțată în Matrice... Atenție la agenți și la linguri.", 500, 'info');
addMessage(">> Se activează peria de sârmă virtuală model 'Exterminator 5000'.", 1500, 'debug');
// Animatie: Efect de ploaie digitală (Matrix) pe fundalul containerului
containerElement.classList.add('is-matrixing');
await new Promise(resolve => setTimeout(resolve, 3000));
addMessage(">> Începe curățarea agresivă a codului redundant.", 1000);
addMessage(">> S-au șters câteva fișiere... 'system32'? Probabil nu erau importante.", 2000, 'warning');
addMessage(">> Peria a agățat un bug de dimensiuni epice. Îl trage afară...", 1800);
addMessage(">> BUG-UL SE APĂRĂ! Tentacule de cod corupt ies din ecran!", 2500, 'error');
// Animatie: O vibrație puternică și poate o schimbare bruscă de culoare a nucleului
containerElement.classList.add('is-shaking');
systemCoreElement.style.backgroundColor = '#8a2be2'; // Violet
await new Promise(resolve => setTimeout(resolve, 2000));
addMessage("[EȘEC] Curățarea a scos la iveală probleme mai mari. Bug-ul a preluat controlul periei. Ironia sorții.", 1000, 'error critical');
// enableOptions(); // Automat
}
},
{
id: 'temporal-rewind',
buttonText: 'Derulează Timpul Sistemului Înainte De EROARE',
action: async () => {
disableOptions();
addMessage(">> Se activează Condensatorul de Flux... 1.21 Gigawați necesari.", 500, 'info');
addMessage(">> Calibrare temporală... Încercăm să evităm paradoxurile... pe cât posibil.", 1500, 'debug');
// Animatie: Efect de rewind vizual, poate textul din output să apară invers sau culorile să se inverseze temporar
outputElement.style.filter = 'invert(1)';
await new Promise(resolve => setTimeout(resolve, 2000));
addMessage(">> Derulare temporală în curs... Trecut prin epoca procesoarelor 486... Brrr.", 1000);
addMessage(">> S-a ajuns la momentul dinaintea erorii! Succes?", 2000, 'info');
outputElement.style.filter = 'none'; // Oprește inversarea
await new Promise(resolve => setTimeout(resolve, 1000));
addMessage(">> Așteaptă... De ce e totul alb-negru și rulează DOOM?", 1800, 'warning');
// Adaugă un pic de text specific epocii
addMessage("C:\\>CHKDSK /F", 500, 'debug');
addMessage("C:\\>Format C: /Q", 500, 'error');
addMessage(">> Eroare de paradox! Sistemul s-a întors prea mult în timp și acum crede că e un PC din 1993!", 2500, 'error');
// Animatie: Poate pixelare temporară a ecranului
containerElement.style.imageRendering = 'pixelated'; // Poate nu funcționează peste tot
await new Promise(resolve => setTimeout(resolve, 1500));
addMessage("[EȘEC] Călătoria în timp a fost prea riscantă. Acum avem nevoie de o dischetă de boot.", 1000, 'error critical');
containerElement.style.imageRendering = 'auto'; // Revine la normal
// enableOptions(); // Automat
}
},
// ADĂUGĂM AICI OPȚIUNEA SECRETĂ (NU chiar secretă, dar e ultima)
{
id: 'friendly-restart',
buttonText: 'Roagă Sistemul Frumos Să Repornească',
action: async () => {
disableOptions();
addMessage(">> Inițiere protocol 'Politețea Maximă'.", 500, 'info');
addMessage(">> Se formulează cererea: 'Dragă Sistemule, ai putea, te rog frumos, dacă nu te deranjează prea tare, să încerci să repornești?'", 2500, 'debug');
// Animatie: O pulsație lentă și caldă a nucleului
systemCoreElement.style.animation = 'pulse-gentle 3s infinite ease-in-out'; // Necesită @keyframes pulse-gentle
await new Promise(resolve => setTimeout(resolve, 3000));
addMessage(">> Sistemul pare să reflecteze...", 2000);
addMessage(">> Răspunsul sistemului: 'Hmmm... De ce nu? Pare o idee bună.'", 2500, 'success'); // Momentul de speranță!
addMessage(">> Inițiere secvență de repornire... Toate subsistemele răspund pozitiv!", 1500, 'success');
// OPRIRE TIMER AICI DACĂ VREI SĂ REUȘEASCĂ
// clearInterval(timerInterval);
// timerElement.textContent = "REPARAT!";
// timerElement.style.color = "#32cd32";
// addMessage(">> MINUNE! Politețea a funcționat! Sistemul repornește normal!", 1000, 'success critical');
// return; // Ieșim din funcție, succes!
// DAR... pentru tema "Fatal Failure", continuăm cu eșecul:
await new Promise(resolve => setTimeout(resolve, 2000));
addMessage(">> Așteaptă... repornirea s-a blocat la 99%. Ecran albastru clasic.", 2000, 'error');
// Animatie: Schimbare bruscă a nucleului în albastru solid
systemCoreElement.style.background = '#0000ff';
systemCoreElement.style.animation = 'none';
systemCoreElement.textContent = 'BSOD';
await new Promise(resolve => setTimeout(resolve, 1500));
addMessage("[EȘEC] A fost aproape! Dar se pare că și politețea are limitele ei în fața unei erori fundamentale. BSOD.", 1000, 'error critical');
// enableOptions(); // Automat
}
},
];
// --- Generare Butoane Opțiuni ---
function generateOptions() {
optionsElement.innerHTML = ''; // Curăță opțiunile vechi
repairOptions.forEach(option => {
const button = document.createElement('button');
button.id = option.id;
button.classList.add('option-button');
button.textContent = option.buttonText;
button.onclick = async () => {
if (isProcessing) return; // Nu face nimic dacă se procesează deja
clearTimeout(messageTimeout); // Opreste orice mesaj planificat din rularea anterioara
messageQueue = []; // Golește coada de mesaje anterioare
removeTemporaryEffects(); // Curăță efectele vechi
await option.action(); // Așteaptă finalizarea acțiunii (inclusiv mesajele adăugate de ea)
// enableOptions() va fi chemat la finalul procesării cozii de mesaje a acțiunii
};
optionsElement.appendChild(button);
});
}
// --- Funcția de Colaps Final ---
function triggerFinalFailure() {
clearTimeout(messageTimeout); // Oprește orice mesaj planificat
disableOptions(); // Dezactivează butoanele permanent
allOptionButtons().forEach(btn => btn.onclick = null); // Elimina event listeners
containerElement.classList.add('is-shaking'); // Ultimul zvacnet
// Ascunde elementele inutile, arată mesajul final
document.getElementById('timer-container').classList.add('hidden');
document.getElementById('system-core').classList.add('hidden');
document.getElementById('output-container').style.opacity = '0.5'; // Estompează jurnalul
document.getElementById('options-container').classList.add('hidden');
finalFailureElement.classList.remove('hidden');
// Adaugă un ultim mesaj în output, dacă mai e vizibil
const p = document.createElement('p');
p.textContent = "[SISTEM] COLAPS TOTAL. FĂRĂ SPERANȚĂ. SFÂRȘIT.";
p.className = 'critical';
outputElement.appendChild(p);
outputElement.scrollTop = outputElement.scrollHeight;
}
// --- Inițializare ---
addMessage(">> Sistemul așteaptă comanda ta. Alege o metodă de reparare.", 2000, 'info');
generateOptions();
startTimer();
// Adaugă și niște keyframes lipsă în CSS dacă e nevoie, ex:
const styleSheet = document.styleSheets[0];
try {
styleSheet.insertRule(`@keyframes spin-fast { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`, styleSheet.cssRules.length);
styleSheet.insertRule(`@keyframes color-cycle { 0% { filter: hue-rotate(0deg); } 100% { filter: hue-rotate(360deg); } }`, styleSheet.cssRules.length);
styleSheet.insertRule(`@keyframes pulse-intense { 0%, 100% { transform: scale(1); box-shadow: 0 0 10px red; } 50% { transform: scale(1.1); box-shadow: 0 0 30px red; } }`, styleSheet.cssRules.length);
// Adaugă aici keyframes pentru 'is-melting', 'pulse-gentle' etc. dacă le implementezi vizual complex
styleSheet.insertRule(`.is-melting::after { content: ''; display: block; width: 5px; height: 20px; background: #ff4500; margin: 5px auto 0 auto; border-radius: 0 0 5px 5px; animation: drip 1s infinite linear; }`, styleSheet.cssRules.length);
styleSheet.insertRule(`@keyframes drip { from { transform: translateY(0); opacity: 1; } to { transform: translateY(15px); opacity: 0; } }`, styleSheet.cssRules.length);
styleSheet.insertRule(`@keyframes pulse-gentle { 0%, 100% { transform: scale(1); box-shadow: 0 0 8px #6495ed; } 50% { transform: scale(1.03); box-shadow: 0 0 15px #6495ed; } }`, styleSheet.cssRules.length);
} catch (e) {
console.warn("Nu s-au putut adăuga reguli CSS dinamic:", e);
}
}); // Sfârșitul DOMContentLoaded