253 lines
7.6 KiB
PHP
253 lines
7.6 KiB
PHP
<?php
|
||
// Wichtig: echten 404-Status setzen
|
||
http_response_code(404);
|
||
|
||
// Request-Daten absichern
|
||
$requestUri = htmlspecialchars($_SERVER['REQUEST_URI'] ?? '', ENT_QUOTES, 'UTF-8');
|
||
$method = htmlspecialchars($_SERVER['REQUEST_METHOD'] ?? '', ENT_QUOTES, 'UTF-8');
|
||
|
||
// Optional: einfaches Logging
|
||
error_log("[404] " . ($_SERVER['REMOTE_ADDR'] ?? '') . " $method $requestUri");
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<link rel="icon" href="/assets/images/favicon.ico" sizes="any">
|
||
<link rel="stylesheet" href="/style.css">
|
||
<title>404 – Seite nicht gefunden | Geizkragen</title>
|
||
</head>
|
||
<body>
|
||
|
||
<main>
|
||
<div class="container" style="
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 100vh;
|
||
text-align: center;
|
||
padding-block: 4rem;
|
||
">
|
||
<!-- 404 Glitch-Zahl -->
|
||
<div class="error-code" aria-hidden="true">404</div>
|
||
|
||
<!-- Card -->
|
||
<div class="error-card">
|
||
<div class="error-card__icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||
stroke-linecap="round" stroke-linejoin="round" width="28" height="28">
|
||
<circle cx="11" cy="11" r="8"/>
|
||
<path d="M21 21l-4.35-4.35"/>
|
||
<line x1="8" y1="11" x2="14" y2="11"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<h1 class="error-card__title">Seite nicht gefunden</h1>
|
||
<p class="error-card__text">
|
||
Die Seite, die du suchst, existiert leider nicht oder wurde verschoben.
|
||
</p>
|
||
|
||
<div class="error-card__path"><?php echo $requestUri; ?></div>
|
||
|
||
<div class="error-card__actions">
|
||
<a href="/index.php" class="btn btn--primary">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||
stroke-linecap="round" stroke-linejoin="round" width="18" height="18">
|
||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||
</svg>
|
||
Zur Startseite
|
||
</a>
|
||
<button onclick="history.back()" class="btn btn--ghost">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||
stroke-linecap="round" stroke-linejoin="round" width="18" height="18">
|
||
<line x1="19" y1="12" x2="5" y2="12"/>
|
||
<polyline points="12 19 5 12 12 5"/>
|
||
</svg>
|
||
Zurück
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<style>
|
||
/* ── 404 Glitch-Zahl ── */
|
||
.error-code {
|
||
font-size: clamp(7rem, 18vw, 12rem);
|
||
font-weight: 900;
|
||
line-height: 1;
|
||
letter-spacing: -0.04em;
|
||
background: linear-gradient(135deg, var(--color-primary), #4f46e5, var(--color-accent));
|
||
background-size: 200% 200%;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
animation: gradientShift 4s ease-in-out infinite;
|
||
margin-bottom: 1.5rem;
|
||
position: relative;
|
||
display: inline-block;
|
||
}
|
||
|
||
.error-code::before,
|
||
.error-code::after {
|
||
content: '404';
|
||
position: absolute;
|
||
top: 0; left: 0; right: 0;
|
||
overflow: hidden;
|
||
background: inherit;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.error-code::before {
|
||
clip-path: inset(0 0 65% 0);
|
||
animation: glitch1 3s infinite linear alternate-reverse;
|
||
}
|
||
|
||
.error-code::after {
|
||
clip-path: inset(65% 0 0 0);
|
||
animation: glitch2 3s infinite linear alternate-reverse;
|
||
}
|
||
|
||
@keyframes glitch1 {
|
||
0%,92% { transform: translate(0); }
|
||
93% { transform: translate(-6px,-2px); }
|
||
94% { transform: translate(3px,1px); }
|
||
95% { transform: translate(-2px,2px); }
|
||
96%,100%{ transform: translate(0); }
|
||
}
|
||
|
||
@keyframes glitch2 {
|
||
0%,90% { transform: translate(0); }
|
||
91% { transform: translate(4px,2px); }
|
||
92% { transform: translate(-5px,-1px); }
|
||
93% { transform: translate(2px,-2px); }
|
||
94%,100%{ transform: translate(0); }
|
||
}
|
||
|
||
/* ── Card ── */
|
||
.error-card {
|
||
background: rgba(31, 41, 55, 0.55);
|
||
backdrop-filter: blur(20px);
|
||
-webkit-backdrop-filter: blur(20px);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-xl);
|
||
padding: 2.5rem 2.5rem 2rem;
|
||
max-width: 520px;
|
||
width: 100%;
|
||
box-shadow: var(--shadow-md), 0 0 60px var(--color-primary-glow);
|
||
animation: fadeInUp 0.6s ease-out 0.1s both;
|
||
}
|
||
|
||
.error-card__icon {
|
||
width: 56px;
|
||
height: 56px;
|
||
margin: 0 auto 1.25rem;
|
||
background: var(--color-primary-soft);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--color-primary);
|
||
animation: pulse-glow 3s ease-in-out infinite;
|
||
}
|
||
|
||
.error-card__title {
|
||
font-size: 1.4rem;
|
||
font-weight: 800;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.6rem;
|
||
}
|
||
|
||
.error-card__text {
|
||
color: var(--text-muted);
|
||
font-size: 0.95rem;
|
||
line-height: 1.6;
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.error-card__path {
|
||
display: inline-block;
|
||
background: var(--color-primary-soft);
|
||
border: 1px solid rgba(39, 74, 151, 0.25);
|
||
color: #6b8fd8;
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
padding: 0.35rem 0.9rem;
|
||
border-radius: var(--radius-md);
|
||
margin: 1rem 0 1.5rem;
|
||
word-break: break-all;
|
||
max-width: 100%;
|
||
}
|
||
|
||
/* ── Buttons ── */
|
||
.error-card__actions {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.45rem;
|
||
padding: 0.7rem 1.4rem;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
font-family: var(--font-family);
|
||
text-decoration: none;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all var(--transition-smooth);
|
||
}
|
||
|
||
.btn--primary {
|
||
background: var(--color-primary);
|
||
color: #fff;
|
||
box-shadow: 0 4px 14px var(--color-primary-glow);
|
||
}
|
||
|
||
.btn--primary:hover {
|
||
background: var(--color-primary-hover);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 24px var(--color-primary-glow);
|
||
color: #fff;
|
||
}
|
||
|
||
.btn--ghost {
|
||
background: rgba(255,255,255,0.04);
|
||
color: var(--text-muted);
|
||
border: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.btn--ghost:hover {
|
||
background: rgba(255,255,255,0.09);
|
||
color: var(--text-primary);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
/* ── Responsive ── */
|
||
@media (max-width: 480px) {
|
||
.error-card {
|
||
padding: 1.8rem 1.25rem 1.5rem;
|
||
}
|
||
.error-card__actions {
|
||
flex-direction: column;
|
||
}
|
||
.btn {
|
||
justify-content: center;
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
</body>
|
||
</html>
|