Files
cluedo-hp-webapp/frontend/index.html
T
nessi a8335e2034 Prevent sheet editing after game completion and add game start celebration with enhanced splash screen animations
Added read-only enforcement for finished games by checking `winner_user_id` in backend PATCH endpoint and frontend sheet interactions. Implemented GameStartCelebration component with confetti burst, animated overlay card, and pulsing rune icon. Enhanced splash screen with orbiting border animation, sparkle effects, and title rise transition. Added haptic feedback (vibration) to sheet
2026-08-02 09:28:16 +02:00

231 lines
6.2 KiB
HTML

<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<title>Cluedo Sheet</title>
<!-- Fonts -->
<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=Cinzel+Decorative:wght@400;700&family=IM+Fell+English:ital@0;1&display=swap"
rel="stylesheet"
/>
<style>
html,
body {
margin: 0;
height: 100%;
background: radial-gradient(
ellipse at top,
rgba(30, 30, 30, 0.95),
#000
);
}
/* Splash Overlay */
#app-splash {
position: fixed;
inset: 0;
z-index: 2147483647;
display: grid;
place-items: center;
background: radial-gradient(
ellipse at top,
rgba(30, 30, 30, 0.95),
#000
);
overflow: hidden;
opacity: 1;
transition: opacity 260ms ease;
}
#app-splash.hide {
opacity: 0;
pointer-events: none;
}
/* gold animated lines */
#app-splash::before,
#app-splash::after {
content: "";
position: absolute;
inset: -40%;
background:
linear-gradient(
90deg,
transparent,
rgba(233, 216, 166, 0.18),
transparent
);
transform: rotate(12deg);
animation: goldSweep 1.6s linear infinite;
opacity: 0.55;
filter: blur(0.2px);
pointer-events: none;
}
#app-splash::after {
transform: rotate(-12deg);
animation-duration: 2.2s;
opacity: 0.35;
}
@keyframes goldSweep {
0% { transform: translateX(-25%) rotate(12deg); }
100% { transform: translateX(25%) rotate(12deg); }
}
/* glassy card */
.splash-card {
position: relative;
width: min(520px, 90vw);
border-radius: 22px;
padding: 18px 16px;
background: rgba(20, 20, 22, 0.55);
border: 1px solid rgba(233, 216, 166, 0.16);
box-shadow: 0 18px 70px rgba(0,0,0,0.55);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
text-align: center;
overflow: hidden;
}
.splash-card::after {
content: "";
position: absolute;
inset: 18% 28%;
border: 1px solid rgba(233, 216, 166, 0.24);
border-radius: 50%;
transform: rotate(-18deg);
animation: orbit 2.8s ease-in-out infinite;
pointer-events: none;
}
.magic-orbit {
position: relative;
width: 74px;
height: 42px;
margin: 0 auto 4px;
}
.magic-orbit::before,
.magic-orbit::after {
content: "✦";
position: absolute;
color: rgba(233, 216, 166, 0.92);
font-size: 16px;
animation: sparkle 1.4s ease-in-out infinite;
}
.magic-orbit::before { left: 8px; top: 14px; }
.magic-orbit::after { right: 8px; top: 3px; animation-delay: .55s; }
.splash-card::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg, transparent, rgba(233,216,166,0.16), transparent);
opacity: 0.45;
pointer-events: none;
}
.splash-title {
position: relative;
font-family: "Cinzel Decorative", serif;
font-weight: 700;
letter-spacing: 0.06em;
color: rgba(245, 239, 220, 0.92);
font-size: 18px;
line-height: 1.25;
animation: titleRise 700ms ease-out both;
}
.splash-sub {
position: relative;
margin-top: 6px;
font-family: "IM Fell English", serif;
font-style: italic;
color: rgba(233, 216, 166, 0.78);
font-size: 13px;
}
/* Loader */
.loader {
position: relative;
margin: 14px auto 0;
width: 28px;
height: 28px;
border-radius: 999px;
border: 2px solid rgba(233, 216, 166, 0.18);
border-top-color: rgba(233, 216, 166, 0.92);
animation: spin 0.85s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* tiny spark at bottom */
.spark {
position: relative;
margin: 14px auto 0;
width: 160px;
height: 2px;
border-radius: 999px;
background: linear-gradient(90deg, transparent, rgba(233,216,166,0.65), transparent);
opacity: 0.6;
filter: blur(0.2px);
animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.35; transform: scaleX(0.92); }
50% { opacity: 0.85; transform: scaleX(1.02); }
}
@keyframes orbit {
0%, 100% { transform: rotate(-18deg) scale(.94); opacity: .45; }
50% { transform: rotate(18deg) scale(1.06); opacity: .9; }
}
@keyframes sparkle {
0%, 100% { transform: translateY(3px) scale(.65); opacity: .25; }
50% { transform: translateY(-4px) scale(1.2); opacity: 1; }
}
@keyframes titleRise {
from { opacity: 0; transform: translateY(8px); letter-spacing: .18em; }
to { opacity: 1; transform: translateY(0); letter-spacing: .06em; }
}
</style>
<!-- Theme-Key sofort setzen -->
<script>
try {
const k = localStorage.getItem("hpTheme:guest") || "default";
document.documentElement.setAttribute("data-theme", k);
} catch {}
</script>
</head>
<body>
<div id="app-splash" aria-hidden="true">
<div class="splash-card">
<div class="magic-orbit" aria-hidden="true"></div>
<div class="splash-title">Zauber-Detektiv Notizbogen</div>
<div class="splash-sub">Magie wird vorbereitet…</div>
<div class="loader" aria-label="Laden"></div>
<div class="spark"></div>
</div>
</div>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>