im Markup — so bleibt die
Vorlage in der Verwaltung unverändert. */
.jahres-events-grid-einzeln .jahres-event-datum { grid-column: 2; margin-bottom: .35rem; }
.jahres-events-grid-einzeln .jahres-event-card h3 {
grid-column: 2;
font-size: 1.5rem;
line-height: 1.22;
letter-spacing: -.012em;
margin-bottom: .55rem;
}
.jahres-events-grid-einzeln .jahres-event-textwrap { grid-column: 2; margin-bottom: 1.05rem; }
.jahres-events-grid-einzeln .jahres-event-card p {
font-size: 1rem;
line-height: 1.62;
margin-bottom: 0;
}
.jahres-events-grid-einzeln .jahres-event-mehr { grid-column: 2; justify-self: start; }
.jahres-events-grid-einzeln .jahres-event-bild:not([hidden]) { grid-column: 1; grid-row: 1 / -1; }
@media (max-width: 900px) {
.jahres-events-grid-einzeln .jahres-event-card:not([hidden]) { grid-template-columns: 1fr; grid-template-rows: none; gap: .9rem; padding: 1.2rem 1.3rem; }
.jahres-events-grid-einzeln .jahres-event-datum,
.jahres-events-grid-einzeln .jahres-event-card h3,
.jahres-events-grid-einzeln .jahres-event-card p,
.jahres-events-grid-einzeln .jahres-event-mehr { grid-column: 1; }
.jahres-events-grid-einzeln .jahres-event-bild:not([hidden]) { grid-column: 1; grid-row: auto; height: auto; min-height: 0; aspect-ratio: 16/9; }
.jahres-events-grid-einzeln .jahres-event-card h3 { font-size: 1.25rem; }
}
/* Optionales Admin-Bild pro Event (20.08.2026, "Event des Jahres" jetzt in
der Verwaltung pflegbar) — bleibt per [hidden] unsichtbar, solange kein
Bild gesetzt ist, damit die textbasierten Standard-Karten unverändert
aussehen. Bugfix (per Playwright-Test gefunden): "display:block" allein
hätte dieselbe Spezifität wie die eingebaute [hidden]-Regel des Browsers
und würde sie im Zweifel überschreiben (leerer Bild-Rahmen wäre auch OHNE
gesetztes Bild sichtbar gewesen) — deshalb hier zusätzlich explizit
:not([hidden]) statt nur der Klasse allein. */
.jahres-event-bild[hidden] { display: none; }
.jahres-event-bild:not([hidden]) {
display: block;
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
border-radius: calc(var(--radius) - 4px);
margin-bottom: .9rem;
}
/* ---------- "Event des Jahres" — Detail-Fenster (20.08.2026) ----------
Nutzer-Wunsch: "wen ich drauf drücke dass dein ein kleines fenster
aufgeht wo das bild bissl größer ist mit einem größeren text und
beschreibung, und mit einem link ... bereite das richtig geil krank
vor." Augenschonend gehalten (siehe Projektregel): kein grelles Weiß,
sanftes Ein-/Ausblenden statt hartem Umschalten, respektiert
prefers-reduced-motion. */
.jahres-event-modal-overlay {
position: fixed;
inset: 0;
z-index: 200;
display: flex;
align-items: center;
justify-content: center;
padding: 4vh 5vw;
background: rgba(5, 7, 11, .78);
backdrop-filter: blur(6px);
opacity: 0;
transition: opacity .22s ease;
}
.jahres-event-modal-overlay.offen { opacity: 1; }
.jahres-event-modal-overlay[hidden] { display: none; }
body.modal-offen { overflow: hidden; }
.jahres-event-modal {
position: relative;
width: min(640px, 100%);
max-height: 90vh;
overflow-y: auto;
background: var(--card-bg);
border: 1px solid rgba(212, 175, 55, .4);
border-radius: var(--radius);
box-shadow: 0 24px 60px rgba(0, 0, 0, .5), 0 0 40px rgba(212, 175, 55, .12);
transform: scale(.94) translateY(10px);
transition: transform .25s ease;
}
.jahres-event-modal-overlay.offen .jahres-event-modal { transform: scale(1) translateY(0); }
@media (prefers-reduced-motion: reduce) {
.jahres-event-modal-overlay, .jahres-event-modal { transition: none; }
}
.jahres-event-modal-close {
position: absolute;
top: .9rem; right: .9rem;
z-index: 2;
width: 38px; height: 38px;
border-radius: 50%;
border: 1px solid rgba(255, 255, 255, .25);
background: rgba(5, 7, 11, .7);
color: var(--text);
font-size: 1.1rem;
cursor: pointer;
transition: border-color .15s ease, transform .15s ease;
}
.jahres-event-modal-close:hover { border-color: rgba(212, 175, 55, .7); transform: scale(1.06); }
.jahres-event-modal-bild {
display: block;
width: 100%;
max-height: 46vh;
object-fit: cover;
border-radius: var(--radius) var(--radius) 0 0;
}
.jahres-event-modal-bild[hidden] { display: none; }
.jahres-event-modal-body { padding: 1.8rem 2rem 2.2rem; }
.jahres-event-modal-datum {
display: block;
color: #e8c465;
font-weight: 700;
font-size: .92rem;
letter-spacing: .03em;
margin-bottom: .5rem;
}
.jahres-event-modal-body h2 { font-size: 1.7rem; margin: 0 0 .8rem; }
.jahres-event-modal-body p { font-size: 1.08rem; line-height: 1.7; color: var(--text-muted); margin: 0 0 1.4rem; }
.jahres-event-modal-link[hidden] { display: none; }
/* ---------- Cards ---------- */
/* ---------- Die Kachel (überarbeitet 03.09.2026) -------------------------
Sie war eine Fläche mit einem Rand. Jetzt ist sie ein Gegenstand mit
einer Oberkante -- und das ist der ganze Unterschied.
Drei Dinge, die zusammen wirken:
1. LICHTKANTE OBEN. Ein einzelner heller Strich an der oberen
Kante, so wie Licht auf die Kante einer Glasplatte fällt. Es ist
die billigste und wirksamste Art, aus einem Rechteck einen
Körper zu machen -- eine Kachel ohne sie wirkt wie ein Loch in
der Seite, eine mit ihr wie ein Ding darauf.
2. VERLAUF STATT FLÄCHE. Oben eine Spur heller als unten. Kaum zu
sehen, aber ohne ihn bleibt die Fläche tot.
3. TIEFE. Ein Schatten nach unten -- nicht mittig, sondern versetzt,
so wie ein Gegenstand seinen Schatten wirft.
Beim Überfahren hebt sie sich, der Schatten wird länger und die
Lichtkante heller: als käme sie einem entgegen. Alles gedeckt, nichts
leuchtet -- diese Kacheln stehen zu Dutzenden auf einer Seite. */
.card {
position: relative;
background:
linear-gradient(180deg,
color-mix(in srgb, #fff 3.5%, var(--card-bg)),
var(--card-bg) 46%);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.6rem;
box-shadow:
var(--shadow),
inset 0 1px 0 rgba(255, 255, 255, .07);
height: 100%;
transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}
/* Die Lichtkante. Als eigenes Element, damit sie den runden Ecken folgt
und in der Mitte am hellsten ist -- eine durchgehend gleich helle
Linie sieht aus wie ein Strich, nicht wie Licht. */
.card::before {
content: "";
position: absolute; top: 0; left: 12%; right: 12%; height: 1px;
background: linear-gradient(90deg,
transparent, rgba(255, 255, 255, .5), transparent);
pointer-events: none;
opacity: .85;
transition: opacity .15s ease;
}
.card:hover {
border-color: var(--accent);
transform: translateY(-3px);
box-shadow:
var(--shadow),
inset 0 1px 0 rgba(255, 255, 255, .1),
0 16px 34px -20px color-mix(in srgb, var(--accent) 70%, transparent);
}
.card:hover::before { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
.card, .card:hover { transition: none; transform: none; }
}
@media (forced-colors: active) {
.card::before { display: none; }
}
/* Kachel-Überschriften: gleiche Optik für h2 UND h3. Manche Kacheln
sind semantisch
(eigenständige Abschnitte direkt unter der
Seiten-h1, z.B. die Werte auf werte.html), sollen aber so kompakt
aussehen wie die h3-Kacheln -- nicht in globaler h2-Größe. Diese Regel
berührt NUR das nackte .card; die Varianten .card-brand/.card-feature
behalten über ihre eigenen h3-Regeln ihre abweichenden Größen. */
.card h3 { margin-bottom: .4rem; }
.card > h2 { font-size: 1.62rem; margin-bottom: .4rem; line-height: 1.2; }
.card .tag {
display: inline-block;
font-size: .72rem;
text-transform: uppercase;
letter-spacing: .08em;
color: var(--accent);
border: 1px solid var(--accent);
border-radius: 999px;
padding: .15rem .6rem;
margin-bottom: .8rem;
}
.grid { display: grid; gap: 1.4rem; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 980px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }
/* ---------- Profil-Karten (Team/Creator) ---------- */
.profile-card {
position: relative;
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
text-align: center;
padding: 2rem 1.2rem 1.7rem;
transition: border-color .3s ease, transform .3s ease, box-shadow .3s ease;
}
/* dezenter Lichtschein hinter dem Avatar */
.profile-card::before {
content: "";
position: absolute;
top: -30%;
left: 50%;
width: 200px;
height: 200px;
transform: translateX(-50%);
background: radial-gradient(circle, color-mix(in srgb, var(--accent) 20%, transparent), transparent 70%);
pointer-events: none;
}
.profile-card:hover {
border-color: color-mix(in srgb, var(--accent) 55%, transparent);
transform: translateY(-4px);
box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
}
.profile-card h3 { margin: 0 0 .25rem; font-size: 1.15rem; }
/* Avatar-Kreis mit Akzent-Ring.
WICHTIG: hier kommen fertig zugeschnittene Gesichts-Ausschnitte rein
(assets/img/avatar-*.jpg), NICHT die großen Team-Karten — die sind bei
dieser Größe nur Matsch. Siehe `avatar`-Feld in assets/js/data-modis.js. */
.avatar {
width: 108px;
height: 108px;
border-radius: 50%;
margin: 0 auto 1rem;
position: relative;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background: linear-gradient(140deg, var(--accent), var(--accent-2));
box-shadow:
0 0 0 2px var(--card-bg),
0 0 0 4px color-mix(in srgb, var(--accent) 55%, transparent),
0 10px 26px rgba(0, 0, 0, .45);
transition: box-shadow .3s ease, transform .3s ease;
}
.avatar img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* Leichter Glanz oben, damit der Kreis nicht flach wirkt */
.avatar::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background: linear-gradient(165deg, rgba(255, 255, 255, .18), transparent 55%);
pointer-events: none;
}
.avatar-initial {
font-family: var(--font-head);
font-weight: 800;
font-size: 2.4rem;
line-height: 1;
color: var(--accent-contrast);
text-shadow: 0 2px 6px rgba(0, 0, 0, .25);
}
.profile-card:hover .avatar {
transform: translateY(-2px);
box-shadow:
0 0 0 2px var(--card-bg),
0 0 0 4px var(--frame, var(--accent)),
0 14px 32px rgba(0, 0, 0, .5);
}
/* Fest lila bei JEDER Profilkarte (Modis, Scouts, Creator) — Wunsch von
Dogi, nachdem ihm Michis zufällig lila geloster Ring gefallen hat.
Fester Hex-Wert statt var(--accent-2), damit es auch auf den roten
Agentur-Seiten (Scout/Creator) lila bleibt statt orange zu werden. */
.profile-card { --frame: #8b5cf6; }
.profile-card .avatar {
/* Fester lila-Verlauf statt var(--accent-2), damit der Avatar-Hintergrund
auch auf roten Agentur-Seiten sauber lila bleibt statt lila+orange zu mischen. */
background: linear-gradient(140deg, var(--frame, var(--accent)), #6d28d9);
box-shadow:
0 0 0 2px var(--card-bg),
0 0 0 4px color-mix(in srgb, var(--frame, var(--accent)) 60%, transparent),
0 10px 26px rgba(0, 0, 0, .45);
}
.profile-card::before {
background: radial-gradient(circle,
color-mix(in srgb, var(--frame, var(--accent)) 20%, transparent), transparent 70%);
}
.profile-card:hover { border-color: color-mix(in srgb, var(--frame, var(--accent)) 60%, transparent); }
.profile-card .role { color: var(--accent); font-weight: 600; font-size: .85rem; margin-bottom: .6rem; }
.profile-card .quote { font-style: italic; font-size: .9rem; }
.profile-card .socials { display: flex; justify-content: center; gap: .6rem; margin-top: .8rem; }
.profile-card .socials a {
border: 1px solid var(--border);
border-radius: 999px;
padding: .35rem .8rem;
font-size: .78rem;
color: var(--text-muted);
}
.profile-card .socials a:hover { color: var(--accent); border-color: var(--accent); }
/* ---------- Placeholder-Bild-Boxen (bis echte Fotos da sind) ---------- */
.img-placeholder {
aspect-ratio: 4 / 3;
border-radius: var(--radius);
background: repeating-linear-gradient(135deg, var(--bg-alt), var(--bg-alt) 10px, var(--card-bg) 10px, var(--card-bg) 20px);
border: 1px dashed var(--border);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: .3rem;
color: var(--text-muted);
font-size: .8rem;
text-align: center;
padding: 1rem;
}
/* ---------- Timeline (Zeitreise) — alte, einfache Punkt+Linie-Variante ---------- */
.timeline { position: relative; margin: 2rem 0; padding-left: 2rem; border-left: 2px solid var(--border); }
.timeline-item { position: relative; padding-bottom: 2.4rem; }
.timeline-item::before {
content: "";
position: absolute;
left: -2.45rem;
top: .2rem;
width: 14px; height: 14px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 0 4px var(--bg);
}
.timeline-item .date { color: var(--accent); font-weight: 700; font-size: .85rem; }
/* ---------- Zeitbaum (Zeitreise) — die Reise als wachsender Baum ----------
Ein Stamm (::before, per clip-path unten dicker als oben = "Wachstum")
läuft mittig durch alle Stationen. Jede Station ("Ast") hängt sich
abwechselnd links/rechts an den Stamm, verbunden über eine glühende
Astlinie. Meilenstein-Stationen bekommen eine goldene statt babyblaue
Aura. Oben ein Keim (🌱, Anfang), unten eine Krone (🌳, Fortsetzung). */
.zeit-baum {
position: relative;
margin: 3rem 0 1rem;
padding: 2.4rem 0;
}
.zeit-baum::before {
content: "";
position: absolute;
left: 50%;
top: 0; bottom: 0;
width: 44px;
transform: translateX(-50%);
background: linear-gradient(180deg,
rgba(143,217,234,.55) 0%,
rgba(139,92,246,.55) 45%,
rgba(217,196,90,.6) 100%);
clip-path: polygon(47% 0%, 53% 0%, 66% 100%, 34% 100%);
filter: blur(.2px);
box-shadow: 0 0 60px 6px rgba(143,217,234,.18);
opacity: .85;
}
/* "Diese Seite wächst noch"-Hinweis (20.08.2026, Nutzer-Wunsch) — bewusst
einladend statt wie eine Fehler-/Baustellen-Meldung, im selben Babyblau
wie der Rest des Wachstums-Baum-Themas dieser Seite (.zeit-baum-kappe/
-wurzel). Sitzt VOR dem Baum, damit Besucher sofort verstehen: hier
entsteht noch etwas, ohne dass es wie ein Fehler wirkt. */
.zeit-baustelle {
display: flex;
align-items: flex-start;
gap: 1rem;
max-width: 640px;
margin: 0 auto 2.6rem;
padding: 1.1rem 1.4rem;
border-radius: var(--radius);
background: rgba(143, 217, 234, .06);
border: 1.5px solid rgba(143, 217, 234, .35);
box-shadow: 0 0 24px rgba(143, 217, 234, .12);
}
.zeit-baustelle-icon {
flex-shrink: 0;
font-size: 1.8rem;
line-height: 1;
filter: drop-shadow(0 0 8px rgba(143, 217, 234, .55));
animation: zeit-baustelle-wiegen 3.5s ease-in-out infinite;
}
.zeit-baustelle strong {
display: block;
font-size: 1.05rem;
margin-bottom: .3rem;
color: var(--text);
}
.zeit-baustelle p {
margin: 0;
font-size: .92rem;
color: var(--text-muted);
line-height: 1.55;
}
@keyframes zeit-baustelle-wiegen {
0%, 100% { transform: rotate(-5deg); }
50% { transform: rotate(5deg); }
}
@media (prefers-reduced-motion: reduce) {
.zeit-baustelle-icon { animation: none; }
}
.zeit-baum-kappe {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: .3rem;
margin-bottom: .5rem;
text-align: center;
font-size: .85rem;
font-weight: 700;
color: var(--accent);
text-shadow: 0 0 14px rgba(143,217,234,.55);
}
.zeit-baum-kappe span:first-child { font-size: 1.6rem; filter: drop-shadow(0 0 10px rgba(143,217,234,.6)); }
.zeit-baum-wurzel {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: .3rem;
margin-top: 1rem;
text-align: center;
font-size: .85rem;
font-weight: 700;
color: #e8d78f;
text-shadow: 0 0 14px rgba(217,196,90,.5);
}
.zeit-baum-wurzel span:first-child { font-size: 1.9rem; filter: drop-shadow(0 0 14px rgba(217,196,90,.6)); }
.zeit-ast {
position: relative;
display: flex;
width: 100%;
padding: 1.1rem 0;
}
.zeit-ast:nth-child(odd) { justify-content: flex-start; }
.zeit-ast:nth-child(even) { justify-content: flex-end; }
.zeit-node {
position: absolute;
left: 50%;
top: 50%;
width: 16px; height: 16px;
transform: translate(-50%, -50%);
border-radius: 50%;
background: radial-gradient(circle at 35% 30%, #fff, var(--accent) 60%, var(--accent-2) 100%);
box-shadow: 0 0 0 4px var(--bg), 0 0 18px 3px rgba(143,217,234,.6);
z-index: 2;
animation: zeit-node-pulse 3.2s ease-in-out infinite;
}
.zeit-ast.meilenstein .zeit-node {
background: radial-gradient(circle at 35% 30%, #fff, #e8d78f 55%, #b8892f 100%);
box-shadow: 0 0 0 4px var(--bg), 0 0 22px 5px rgba(232,215,143,.7);
}
@keyframes zeit-node-pulse {
0%, 100% { box-shadow: 0 0 0 4px var(--bg), 0 0 14px 2px rgba(143,217,234,.5); }
50% { box-shadow: 0 0 0 4px var(--bg), 0 0 24px 6px rgba(143,217,234,.85); }
}
.zeit-karte {
position: relative;
width: calc(50% - 2.6rem);
background: linear-gradient(160deg, rgba(23,27,33,.82), rgba(23,27,33,.55));
backdrop-filter: blur(6px);
border: 1px solid rgba(143,217,234,.25);
border-radius: 16px;
padding: 1.1rem 1.3rem;
box-shadow: 0 10px 26px rgba(0,0,0,.35);
transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.zeit-ast.meilenstein .zeit-karte { border-color: rgba(232,215,143,.4); }
.zeit-karte::before {
content: "";
position: absolute;
top: 50%;
width: 2.6rem;
height: 2px;
background: linear-gradient(90deg, rgba(143,217,234,.05), rgba(143,217,234,.65));
transform: translateY(-50%);
}
.zeit-ast:nth-child(odd) .zeit-karte::before { right: -2.6rem; }
.zeit-ast:nth-child(even) .zeit-karte::before { left: -2.6rem; background: linear-gradient(270deg, rgba(143,217,234,.05), rgba(143,217,234,.65)); }
.zeit-ast.meilenstein:nth-child(odd) .zeit-karte::before { background: linear-gradient(90deg, rgba(232,215,143,.05), rgba(232,215,143,.75)); }
.zeit-ast.meilenstein:nth-child(even) .zeit-karte::before { background: linear-gradient(270deg, rgba(232,215,143,.05), rgba(232,215,143,.75)); }
.zeit-karte:hover {
transform: translateY(-4px);
border-color: rgba(143,217,234,.55);
box-shadow: 0 16px 34px rgba(0,0,0,.45), 0 0 24px rgba(143,217,234,.2);
}
.zeit-ast.meilenstein .zeit-karte:hover {
border-color: rgba(232,215,143,.7);
box-shadow: 0 16px 34px rgba(0,0,0,.45), 0 0 26px rgba(232,215,143,.3);
}
.zeit-datum {
color: var(--accent);
font-weight: 700;
font-size: .82rem;
letter-spacing: .02em;
margin-bottom: .25rem;
}
.zeit-ast.meilenstein .zeit-datum { color: #e8d78f; }
.zeit-karte h3 { margin: 0 0 .4rem; font-size: 1.15rem; }
.zeit-karte p { margin: 0; color: var(--text-muted); font-size: .93rem; line-height: 1.55; }
.zeit-ast.zeit-final .zeit-karte { width: calc(100% - 4rem); max-width: 640px; text-align: center; }
.zeit-ast.zeit-final { justify-content: center !important; }
.zeit-ast.zeit-final .zeit-karte::before { display: none; }
/* Bugfix 20.08.2026 (Nutzer-Report: "wieso dieser Punkt da in der Mitte"):
.zeit-node ist bei allen normalen Karten position:absolute; left:50%;
top:50% relativ zu .zeit-ast — das sitzt korrekt in der Baum-Mitte,
WEIL die Karte dort nur die halbe Breite einnimmt. Die Finale-Karte
(.zeit-final) wird aber auf fast volle Breite gestreckt und zentriert
(siehe .zeit-karte-Regel oben) — der Knoten landete dadurch mitten im
Text statt am Rand. Die Verbindungslinie (::before, direkt drüber)
wurde dafür schon 2025 ausgeblendet, der Knoten selbst wurde dabei
übersehen. */
.zeit-ast.zeit-final .zeit-node { display: none; }
.zeit-zitat {
font-weight: 700;
color: var(--text);
font-style: italic;
margin: .8rem 0 .5rem !important;
}
.zeit-familie {
font-weight: 800;
font-size: 1.05rem !important;
color: var(--accent) !important;
text-shadow: 0 0 14px rgba(143,217,234,.5);
}
.zeit-signoff {
margin-top: .8rem !important;
color: var(--text-muted);
font-style: italic;
}
/* Reveal-Animation (per IntersectionObserver in zeitreise.html getriggert) */
.zeit-ast { opacity: 0; transform: translateY(28px); transition: opacity .7s ease, transform .7s ease; }
.zeit-ast.zeit-sichtbar { opacity: 1; transform: translateY(0); }
@media (max-width: 780px) {
.zeit-baum::before { left: 22px; width: 30px; clip-path: polygon(44% 0%, 56% 0%, 70% 100%, 30% 100%); }
.zeit-ast, .zeit-ast:nth-child(odd), .zeit-ast:nth-child(even) { justify-content: flex-start; padding-left: 3rem; }
.zeit-node { left: 22px; }
.zeit-karte { width: 100%; }
.zeit-karte::before,
.zeit-ast:nth-child(even) .zeit-karte::before { left: -2.2rem; right: auto; width: 2.2rem; background: linear-gradient(270deg, rgba(143,217,234,.05), rgba(143,217,234,.65)); }
.zeit-ast.meilenstein .zeit-karte::before,
.zeit-ast.meilenstein:nth-child(even) .zeit-karte::before { background: linear-gradient(270deg, rgba(232,215,143,.05), rgba(232,215,143,.75)); }
.zeit-ast.zeit-final .zeit-karte { width: 100%; text-align: left; }
.zeit-ast.zeit-final { padding-left: 3rem; }
}
/* ---------- Gallery / Lightbox ---------- */
.filter-bar { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: 1.6rem; }
.filter-btn {
border: 1px solid var(--border);
background: transparent;
color: var(--text-muted);
padding: .5rem 1rem;
border-radius: 999px;
cursor: pointer;
font-size: .85rem;
}
.filter-btn.active, .filter-btn:hover { border-color: var(--accent); color: var(--accent); }
.gallery-item { cursor: pointer; }
.lightbox {
position: fixed; inset: 0; background: rgba(0,0,0,.85);
display: none; align-items: center; justify-content: center; z-index: 200; padding: 5vh 5vw;
}
.lightbox.open { display: flex; }
.lightbox img, .lightbox .img-placeholder { max-height: 85vh; max-width: 90vw; }
.lightbox-close {
position: absolute; top: 20px; right: 30px; color: #fff; font-size: 2rem; cursor: pointer; background: none; border: none;
}
/* ---------- Formulare ---------- */
form.app-form { display: grid; gap: 1rem; max-width: 640px; }
.field { display: grid; gap: .4rem; }
.field label { font-weight: 600; font-size: .9rem; }
.field input, .field select, .field textarea {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 10px;
padding: .75rem .9rem;
color: var(--text);
font-family: var(--font-body);
}
.field textarea { min-height: 120px; resize: vertical; }
.field .error-msg { color: #ff6b6b; font-size: .8rem; display: none; }
.field.has-error input, .field.has-error select, .field.has-error textarea { border-color: #ff6b6b; }
.field.has-error .error-msg { display: block; }
.form-status { padding: .9rem 1.1rem; border-radius: 10px; font-size: .9rem; display: none; }
.form-status.show { display: block; }
.form-status.success { background: rgba(143,217,234,.12); border: 1px solid var(--accent); }
.form-status.error { background: rgba(255,107,107,.1); border: 1px solid #ff6b6b; }
.tabs { display: flex; gap: .6rem; margin-bottom: 1.8rem; flex-wrap: wrap; }
.tab-btn {
border: 1px solid var(--border); background: var(--card-bg); color: var(--text-muted);
padding: .7rem 1.3rem; border-radius: 999px; cursor: pointer; font-weight: 600;
}
.tab-btn.active { border-color: var(--accent); color: var(--accent); }
.tab-panel { display: none; }
.tab-panel.active { display: block; }
/* ---------- Footer ---------- */
footer.site-footer {
border-top: 1px solid var(--border);
padding: 3rem 0 2rem;
margin-top: 4rem;
position: relative;
z-index: 1;
/* Voll deckender Hintergrund (nicht color-mix/transparent) — auf Seiten
mit body.mit-hintergrund lag der Footer sonst direkt über dem fixen,
nur teilweise abgedunkelten Hintergrundfoto, was bei axe-core einen
color-contrast-Verstoß für .footer-grid .brand auslöste (04.08.2026). */
background: var(--bg);
}
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 2rem; }
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
/* Die Fußzeilen-Spaltentitel sind semantisch (eigenständige
Abschnitte unter der Seiten-h1), sehen aber bewusst klein und
gedämpft aus -- diese Regel überschreibt die große globale h2-Größe.
Bis 28.08.2026 waren es , was einen Sprung in der
Überschriftenordnung erzeugte (h2 -> h4); die Optik ist unverändert. */
.footer-grid h2 { font-size: .85rem; text-transform: uppercase; letter-spacing: .08em; color: var(--accent); margin: 0 0 .5em; }
.footer-grid ul { display: grid; gap: .5rem; }
.footer-grid a { color: var(--text-muted); font-size: .9rem; }
.footer-grid a:hover { color: var(--accent); }
/* Fußzeilen-Links auf Handys als richtige Tippziele (21.08.2026, Teil des
"alles muss auf dem Handy perfekt erreichbar sein"-Auftrags). Am Rechner
sind 20px hohe Textlinks mit der Maus problemlos zu treffen, mit dem
Finger nicht -- hier sind es 18 Links dicht untereinander, entsprechend
leicht erwischt man den falschen. inline-block + Innenabstand vergrößert
die Trefferfläche auf ~44px, ohne dass sich die Optik nennenswert ändert
(der Text bleibt gleich groß, nur die unsichtbare Fläche wächst). */
@media (max-width: 760px) {
.footer-grid ul { gap: .15rem; }
.footer-grid a {
display: inline-block;
padding: .62rem 0;
min-height: 44px;
box-sizing: border-box;
}
}
.footer-bottom {
margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border);
display: flex; justify-content: space-between; flex-wrap: wrap; gap: .8rem;
font-size: .8rem; color: var(--text-muted);
}
/* Impressum/AGB auf Handys ebenfalls als echte Tippziele (21.08.2026).
Diese beiden sind rechtlich vorgeschrieben und müssen leicht erreichbar
sein -- mit 17px Höhe waren sie mit dem Finger kaum zu treffen. */
@media (max-width: 760px) {
.footer-bottom { align-items: center; }
.footer-bottom a {
display: inline-block;
padding: .6rem 0;
min-height: 44px;
/* min-width für kurze Beschriftungen wie "AGB" -- sonst ist das Ziel
zwar hoch genug, aber nur ~24px breit. */
min-width: 44px;
box-sizing: border-box;
}
}
/* ---------- Foto-Collage (Polaroid-Scrapbook, z.B. Dogfather & Casper) ---------- */
.collage-wrap {
position: relative;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-end;
gap: 1.6rem 1rem;
padding: 2.5rem 0 1.5rem;
max-width: 900px;
margin: 0 auto;
}
.collage-item {
background: #fff;
padding: 10px 10px 30px;
border-radius: 6px;
box-shadow: 0 16px 30px rgba(0, 0, 0, .4);
width: 190px;
transition: transform .25s ease, box-shadow .25s ease;
cursor: default;
}
.collage-item:nth-child(1) { transform: rotate(-7deg) translateY(12px); }
.collage-item:nth-child(2) { transform: rotate(4deg) translateY(-10px); z-index: 2; width: 210px; }
.collage-item:nth-child(3) { transform: rotate(-3deg) translateY(4px); }
.collage-item:nth-child(4) { transform: rotate(8deg) translateY(-6px); }
.collage-item:nth-child(5) { transform: rotate(-9deg) translateY(10px); }
.collage-item:hover {
transform: scale(1.08) rotate(0deg) !important;
z-index: 5;
box-shadow: 0 22px 40px rgba(0, 0, 0, .55);
}
/* Alle Fotoflächen bekommen denselben Rahmen-Look wie die Avatare:
feine Linie in der Rahmenfarbe, dunkle Trennkante, weicher Schlagschatten.
Die Farbe steuert die Variable --frame — Standard ist die Markenfarbe.
Andere Farben über die Klassen .frame-silver / .frame-lila / .frame-gold /
.frame-rot setzen (siehe unten). */
.collage-photo {
--frame: var(--accent);
position: relative;
aspect-ratio: 1 / 1;
border-radius: 10px;
overflow: hidden;
background: repeating-linear-gradient(135deg, #e8ebee, #e8ebee 10px, #f6f7f9 10px, #f6f7f9 20px);
/* Statt eines starren, matten Rahmens: ein "atmender" Polarlicht-Glanz,
der langsam heller/dunkler und weiter/enger pulsiert (siehe
@keyframes collage-aurora-glow unten). Box-shadow wird von
overflow:hidden NICHT beschnitten, deshalb bleibt der Glanz auch am
Rand sichtbar, obwohl das Foto selbst innen sauber zugeschnitten ist. */
box-shadow:
0 0 0 2px color-mix(in srgb, var(--frame) 62%, transparent),
0 0 0 4px rgba(0, 0, 0, .55),
0 0 26px color-mix(in srgb, var(--frame) 22%, transparent),
0 14px 34px rgba(0, 0, 0, .45);
animation: collage-aurora-glow 5s ease-in-out infinite;
transition: transform .3s ease;
}
@keyframes collage-aurora-glow {
0%, 100% {
box-shadow:
0 0 0 2px color-mix(in srgb, var(--frame) 62%, transparent),
0 0 0 4px rgba(0, 0, 0, .55),
0 0 26px color-mix(in srgb, var(--frame) 30%, transparent),
0 0 46px color-mix(in srgb, var(--frame) 12%, transparent),
0 14px 34px rgba(0, 0, 0, .45);
}
50% {
box-shadow:
0 0 0 2px color-mix(in srgb, var(--frame) 95%, transparent),
0 0 0 4px rgba(0, 0, 0, .55),
0 0 46px color-mix(in srgb, var(--frame) 62%, transparent),
0 0 80px color-mix(in srgb, var(--frame) 32%, transparent),
0 14px 34px rgba(0, 0, 0, .45);
}
}
.collage-photo:hover {
transform: translateY(-3px);
animation-play-state: paused;
box-shadow:
0 0 0 2px var(--frame),
0 0 0 4px rgba(0, 0, 0, .55),
0 0 46px color-mix(in srgb, var(--frame) 55%, transparent),
0 0 80px color-mix(in srgb, var(--frame) 30%, transparent),
0 18px 42px rgba(0, 0, 0, .5);
}
@media (prefers-reduced-motion: reduce) {
.collage-photo { animation: none; }
}
/* Farbvarianten für Abwechslung */
.frame-silver { --frame: #c7ccd1; }
.frame-lila { --frame: var(--accent-2); }
.frame-gold { --frame: #d8b25a; }
.frame-rot { --frame: #d94a5c; }
.frame-tuerkis{ --frame: #6ee7d8; }
.collage-photo img {
width: 100%;
height: 100%;
object-fit: cover;
/* Kräftigerer "produced look": mehr Sättigung/Kontrast als vorher, damit
auch schlichte Portraitfotos neben aufwendig gestalteten Postern
(z.B. dem DogFather-Manager-Artwork) nicht flach wirken. */
filter: saturate(1.26) contrast(1.15) brightness(1.03);
}
/* Sehr hohe Hochkant-Bilder (z.B. streamer-mascot.jpg mit 900x2812 px) würden
mit aspect-ratio:auto + height:auto in voller natürlicher Höhe rendern und die
danebenstehende Textspalte komplett erschlagen (Nutzer-Report 20.08.2026:
"der soll bissl kleiner sein und nicht so riesig"). Ein zu knapper max-height-
Deckel (erster Versuch: 460px) machte es dann aber zu klein und ließ eine
sichtbare Lücke unter dem Bild, weil die Textspalte daneben normalerweise
deutlich mehr Platz braucht (Nutzer-Report 21.08.2026: "die größe vom bild
vom husky soll dem text rechts nebendran angepasst werden").
Ausprobiert und wieder verworfen: die Höhe per CSS Grid align-items:stretch +
height:100% exakt an die Textspalte zu koppeln. Funktioniert bei Grid NICHT
robust, weil ein 'auto' sizing Track seine Höhe am MAX-CONTENT-Beitrag beider
Felder ausrichtet -- bei einem derart extremen Hochkantbild (Seitenverhältnis
~1:3.1) zieht das Bild die ganze Zeile (und damit auch die Textspalte) auf
seine eigene, riesige natürliche Höhe hoch, egal was man an min-height
probiert (min-height wirkt nur auf den Mindest-, nicht den Wachstums-Beitrag).
Robuster Kompromiss stattdessen: ein großzügiger fester max-height-Wert
(720px statt 460px), der sich an der TYPISCHEN Höhe der Textspalte in diesem
Abschnitt orientiert (auf normalen Desktop-Breiten ~715-850px hoch) -- das
Bild wirkt dadurch angemessen groß und auf Augenhöhe mit dem Text, ohne die
fragile/rückkoppelnde Grid-Stretch-Mechanik. width:fit-content lässt den
Rahmen dabei eng am Bild sitzen, statt breite gestreifte Hintergrund-Balken
danebenzulassen.
WICHTIG: muss NACH ".collage-photo img" stehen — beide Regeln haben dieselbe
Spezifität (eine Klasse + ein Element), die spätere gewinnt. Stünde dieser
Block davor, würde width:100%/height:100% oben die Deckelung wieder aufheben. */
.collage-photo-kompakt {
aspect-ratio: auto;
width: fit-content;
max-width: 100%;
margin: 0 auto;
}
.collage-photo-kompakt img {
width: auto;
height: auto;
max-height: 720px;
max-width: 100%;
display: block;
object-fit: contain;
}
@media (max-width: 780px) {
/* Auf Mobilgeräten stehen die Grid-Spalten untereinander -- dort ist die
Textspalte durch die volle Breite viel kürzer, ein 720px hohes Bild wäre
unangemessen groß für einen schmalen Handy-Screen. Deckel daher kleiner. */
.collage-photo-kompakt img { max-height: 420px; }
}
/* Cineastischer "Poster-Grade" für JEDES Präsentationsfoto auf der Seite:
zwei Farbschein-Blooms in der jeweiligen Rahmenfarbe (oben-links /
unten-rechts, wie ein Studio-Rimlight — nutzt dieselbe --frame-Variable
wie der Rahmen, damit Bild und Rand optisch zusammengehören), eine
sanfte Vignette unten für Tiefe/Fokus aufs Gesicht, plus feines
Filmkorn (SVG-Turbulence). Macht auch ein simples Handy-Foto "produziert",
ohne den eigentlichen Bildinhalt zu verdecken. */
.collage-photo::after {
content: "";
position: absolute;
inset: 0;
background-image:
radial-gradient(125% 140% at 8% -14%, color-mix(in srgb, var(--frame) 75%, transparent) 0%, transparent 46%),
radial-gradient(125% 140% at 112% 116%, color-mix(in srgb, var(--frame) 65%, transparent) 0%, transparent 48%),
linear-gradient(180deg, transparent 58%, rgba(0, 0, 0, .5) 100%),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.4'/%3E%3C/svg%3E");
background-size: cover, cover, cover, 170px 170px;
background-blend-mode: screen, screen, multiply, overlay;
mix-blend-mode: overlay;
pointer-events: none;
}
/* Zusätzlicher, langsam wandernder Lichtschimmer in der Rahmenfarbe —
dieselbe Machart wie beim Bewerben-Knopf/den Buttons, nur sehr dezent,
damit das Foto selbst gut lesbar bleibt. */
.collage-photo::before {
content: "";
position: absolute;
inset: 0;
z-index: 3;
background: linear-gradient(115deg, transparent 40%, color-mix(in srgb, var(--frame) 65%, white 35%) 50%, transparent 60%);
background-size: 240% 100%;
mix-blend-mode: overlay;
opacity: .55;
animation: btn-shimmer 7s linear infinite;
pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
.collage-photo::before { animation: none; }
}
.collage-photo .img-placeholder {
position: absolute;
inset: 0;
border-radius: 0;
border: none;
color: #6b7280;
}
.collage-caption {
text-align: center;
font-family: "Comic Sans MS", "Segoe Print", cursive;
color: #2a2a2a;
font-size: .85rem;
margin-top: .5rem;
}
@media (max-width: 620px) {
.collage-item, .collage-item:nth-child(2) { width: 140px; }
}
/* ---------- Hero-Atmosphäre (Startseite): Polarlicht oben → Rauch Mitte → Nebel unten ----------
Drei Zonen, die weich ineinander übergehen, plus 4 Husky-/Hasen-Silhouetten mit leuchtend
blauen Augen, die deutlich erkennbar (aber nicht grell) darin stehen. ---------- */
.hero-atmosphere {
position: absolute;
inset: 0;
z-index: 0;
overflow: hidden;
pointer-events: none;
}
/* Verbindender Farbverlauf über die ganze Höhe: babyblau (oben) → neutral (Mitte) → silbrig (unten) */
.atmosphere-blend {
position: absolute;
inset: 0;
/* Fallback für Browser ohne color-mix() */
background: linear-gradient(
to bottom,
rgba(143, 217, 234, .18) 0%,
rgba(139, 92, 246, .12) 38%,
rgba(154, 166, 178, .10) 68%,
rgba(210, 216, 222, .14) 100%
);
background: linear-gradient(
to bottom,
color-mix(in srgb, var(--accent) 22%, transparent) 0%,
color-mix(in srgb, var(--accent-2) 14%, transparent) 38%,
rgba(154, 166, 178, .10) 68%,
rgba(210, 216, 222, .14) 100%
);
mix-blend-mode: screen;
opacity: .8;
}
/* ---- Zone 1: Polarlicht (oben) ---- */
.aurora-band {
position: absolute;
width: 150%;
height: 60%;
left: -25%;
border-radius: 50%;
filter: blur(65px);
opacity: .22;
mix-blend-mode: screen;
animation: aurora-drift 30s ease-in-out infinite;
}
.aurora-band.a1 { top: -16%; background: radial-gradient(ellipse at center, var(--accent) 0%, transparent 70%); animation-duration: 26s; }
.aurora-band.a2 { top: 4%; background: radial-gradient(ellipse at center, var(--accent-2) 0%, transparent 70%); animation-duration: 36s; animation-delay: -9s; opacity: .18; }
.aurora-band.a3 { top: 16%; background: radial-gradient(ellipse at center, #6ee7d8 0%, transparent 70%); animation-duration: 44s; animation-delay: -18s; opacity: .14; }
@keyframes aurora-drift {
0%, 100% { transform: translateX(-4%) translateY(0) scaleY(1); }
50% { transform: translateX(4%) translateY(-3%) scaleY(1.18); }
}
/* ---- Zone 2: Rauch (Mitte) ---- */
.smoke-blob {
position: absolute;
top: 32%;
border-radius: 50%;
background: radial-gradient(circle, rgba(210, 214, 220, .16), transparent 72%);
filter: blur(40px);
animation: smoke-float 30s ease-in-out infinite;
}
@keyframes smoke-float {
0%, 100% { transform: translate(0,0) scale(1); }
50% { transform: translate(3%, -4%) scale(1.12); }
}
/* ---- Zone 3: Nebel (unten) ---- */
.fog-ground {
position: absolute;
bottom: -8%;
left: -15%;
width: 130%;
height: 42%;
background: linear-gradient(to top, rgba(220, 224, 228, .28), transparent 85%);
filter: blur(30px);
animation: fog-drift 40s ease-in-out infinite;
}
@keyframes fog-drift {
0%, 100% { transform: translateX(-3%); }
50% { transform: translateX(3%); }
}
@media (prefers-reduced-motion: reduce) {
.aurora-band, .smoke-blob, .fog-ground { animation: none; }
}
/* ==========================================================================
KINO-HINTERGRUND — das große Trio-Artwork (Dogfather · Dogi · HasiDog)
Aufbau in drei Schichten, damit der Text immer perfekt lesbar bleibt:
1. ::before = das Artwork selbst, mit langsamer Ken-Burns-Fahrt
2. ::after = Abdunkelung (Vignette + Verlauf), blendet unten in die Seite
3. darüber = die bestehende Polarlicht/Rauch/Nebel-Atmosphäre, gedimmt
========================================================================== */
.hero-cinematic {
/* Etwas mehr vertikaler Raum als vorher, damit das Trio-Artwork (läuft
mit background-size:contain mit) auf großen Desktop-Bildschirmen
spürbar größer wirkt statt klein in der Mitte zu schweben. */
padding: clamp(5.5rem, 15vw, 10.5rem) 0;
isolation: isolate;
}
.hero-artwork {
position: absolute;
inset: 0;
z-index: 0;
overflow: hidden;
pointer-events: none;
}
/* Untere Ebene: dieselbe Szene verwaschen als Cover — füllt jeden Rand,
den das scharfe Bild freilässt. */
.hero-artwork::before {
content: "";
position: absolute;
inset: 0;
background-image: url("../img/universe-trio-blur.jpg?v=20260820h");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
/* Obere Ebene: das scharfe Artwork, ungeschnitten und mittig — wie zuvor
"contain", nur eben als echtes Bild (siehe Begründung in index.html).
DER ENTSCHEIDENDE TEIL IST DIE MASKE (27.08.2026):
Vorher endete das scharfe Bild an einer messerscharfen Kante, oben wie
unten (bei 1366x800 z.B. exakt bei 570px und 1345px) — dort traf helles,
scharfes Bild auf dunklen, verwaschenen Untergrund. Das las sich nicht
als Hintergrund, sondern als Fremdkörper quer über der Seite.
Die Maske blendet das scharfe Bild an seinen EIGENEN Rändern weich in
die verwaschene Fassung darunter über. Weil sie am Bild hängt und nicht
am Fenster, sitzt der Übergang auf jedem Bildschirm richtig — genau das
war mit einem CSS-Hintergrund nicht möglich, dessen Kante je nach
Fensterformat wandert. Unten wird großzügiger ausgeblendet als oben,
weil dort die Kacheln liegen: Je ruhiger es unter ihnen wird, desto
klarer heben sie sich ab. */
.hero-artwork-scharf {
position: absolute;
inset: 0;
margin: auto;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
-webkit-mask-image:
linear-gradient(to bottom, transparent 0%, #000 9%, #000 72%, transparent 100%),
linear-gradient(to right, transparent 0%, #000 7%, #000 93%, transparent 100%);
mask-image:
linear-gradient(to bottom, transparent 0%, #000 9%, #000 72%, transparent 100%),
linear-gradient(to right, transparent 0%, #000 7%, #000 93%, transparent 100%);
-webkit-mask-composite: source-in;
mask-composite: intersect;
}
.hero-artwork::after {
content: "";
position: absolute;
inset: 0;
background:
/* Vignette: Mitte frei, Ränder dunkel — lenkt den Blick auf die Figuren */
radial-gradient(ellipse 118% 86% at 50% 44%,
rgba(0, 0, 0, .10) 0%, rgba(0, 0, 0, .52) 68%, rgba(0, 0, 0, .84) 100%),
/* Verlauf: oben dunkel für die Navigation, unten sauberer Übergang in die Seite */
linear-gradient(to bottom,
rgba(0, 0, 0, .62) 0%,
rgba(0, 0, 0, .30) 26%,
rgba(0, 0, 0, .34) 58%,
rgba(0, 0, 0, .78) 88%,
var(--bg) 100%);
}
/* Atmosphäre über dem Artwork nur noch als feiner Schleier */
.hero-cinematic .hero-atmosphere { opacity: .5; }
/* Text bekommt eine weiche Abschattung, damit er auf jedem Bildausschnitt sitzt */
.hero-cinematic h1,
.hero-cinematic .lead,
.hero-cinematic .eyebrow { text-shadow: 0 2px 18px rgba(0, 0, 0, .75), 0 1px 3px rgba(0, 0, 0, .9); }
/* Auf Wunsch: auf der Startseite wirkte alles (Überschrift, Text, Live-
Status-Kästchen, Buttons) auf großen PC-Bildschirmen zu klein — hier
moderat vergrößert, ohne die mobile Größe (untere Klammer der clamp()s)
anzufassen. */
/* Feinschliff 27.08.2026: Je größer eine Schrift gesetzt ist, desto mehr
Luft steht zwischen den Buchstaben — bei 4rem wirkt normale Laufweite
auseinandergefallen. Negative Sperrung und engerer Zeilenabstand sind
der Unterschied zwischen "groß geschrieben" und "gesetzt". text-wrap:
balance verteilt die drei Zeilen gleichmäßig, statt eine kurze
Restzeile stehen zu lassen. */
.hero-cinematic h1 {
font-size: clamp(2.3rem, 6.2vw, 4.2rem);
letter-spacing: -.022em;
line-height: 1.08;
text-wrap: balance;
}
.hero-cinematic .lead {
font-size: clamp(1.25rem, 1.9vw, 1.55rem);
max-width: 34ch;
margin-left: auto;
margin-right: auto;
}
.hero-cinematic .eyebrow { font-size: .88rem; letter-spacing: .2em; }
.hero-cinematic .card { padding: 1.3rem 1.8rem; }
.hero-cinematic .card .badge { font-size: .9rem; }
.hero-cinematic .card .small { font-size: 1.05rem; }
.hero-cinematic .btn-row .btn { font-size: 1.15rem; padding: 1rem 1.9rem; }
/* Die drei Welten-Karten (DogFather/HasiDog/Manager) unter dem Hero
sollen ebenfalls etwas größer wirken, wie auf Wunsch — Text war auf
großen Bildschirmen zu klein. */
/* Die drei Welt-Kacheln liegen direkt auf dem Artwork. Als flache
dunkle Rechtecke wirkten sie wie ausgeschnitten und aufgeklebt
(27.08.2026). Jetzt: eine Spur Milchglas und ein feiner Lichtsaum
oben, wie ihn eine Fläche bekommt, auf die Licht von vorne fällt —
dadurch gehören sie sichtbar zur selben Szene. Deckkraft bleibt hoch
genug, dass der Text ruhig lesbar bleibt (Projektregel: augenschonend
vor Effekt).
FEINSCHLIFF 27.08.2026 ("soll nur noch hochwertiger und professioneller
aussehen"): Jede Kachel trägt jetzt die Farbe IHRER Welt statt dreimal
derselben Standardfarbe — Babyblau für DogFather, Silber für HasiDog,
das gedeckte Rot von Spicy Media für den Manager. Die Werte sind nicht
erfunden, sondern exakt die --accent-Töne der drei Themen-Dateien; die
Kacheln führen damit sichtbar in die Welt, in die sie verlinken.
Übernommen wird der Ton an drei Stellen: Lichtsaum, Plakette und
Rahmen beim Darüberfahren — dezent, nicht als Farbanstrich. */
.hero-cinematic .hero-grid .card {
position: relative;
--welt: var(--accent);
padding: 1.75rem 1.5rem 1.65rem;
background: linear-gradient(180deg, rgba(22, 26, 35, .88), rgba(14, 17, 23, .92));
border-color: rgba(255, 255, 255, .10);
-webkit-backdrop-filter: blur(7px);
backdrop-filter: blur(7px);
box-shadow: 0 14px 38px rgba(0, 0, 0, .40);
transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.hero-cinematic .hero-grid .card[data-theme="dogfather"] { --welt: #8fd9ea; }
.hero-cinematic .hero-grid .card[data-theme="hasidog"] { --welt: #c7ccd1; }
.hero-cinematic .hero-grid .card[data-theme="spicymedia"] { --welt: #d94a5c; }
.hero-cinematic .hero-grid .card::before {
content: "";
position: absolute;
top: 0; left: 14%; right: 14%;
height: 1px;
background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--welt) 60%, transparent), transparent);
opacity: .75;
transition: opacity .18s ease;
pointer-events: none;
}
.hero-cinematic .hero-grid .card:hover,
.hero-cinematic .hero-grid .card:focus-visible {
border-color: color-mix(in srgb, var(--welt) 45%, transparent);
box-shadow: 0 18px 46px rgba(0, 0, 0, .5);
}
.hero-cinematic .hero-grid .card:hover::before { opacity: 1; }
/* Plakette: kleiner, in Versalien und weit gesperrt. Das liest sich als
Kapitelmarke ("Welt 1") statt als Beschriftung und ist der Grund,
warum dieselbe Kachel plötzlich wertiger wirkt — nicht mehr Farbe. */
.hero-cinematic .hero-grid .tag {
font-size: .68rem;
letter-spacing: .14em;
text-transform: uppercase;
color: var(--welt);
border-color: color-mix(in srgb, var(--welt) 40%, transparent);
background: color-mix(in srgb, var(--welt) 9%, transparent);
}
/* Überschrift enger gesetzt (große Schrift braucht weniger Laufweite),
Fließtext mit ruhigerem Zeilenabstand und begrenzter Zeilenlänge —
sonst franst der zentrierte Satz unregelmäßig aus. */
.hero-cinematic .hero-grid h2 { letter-spacing: -.012em; line-height: 1.18; margin-top: .55rem; }
.hero-cinematic .hero-grid p {
line-height: 1.62;
max-width: 31ch;
margin-left: auto;
margin-right: auto;
}
.hero-cinematic .hero-grid h3 { font-size: 1.45rem; }
.hero-cinematic .hero-grid p { font-size: 1.05rem; }
/* Bugfix 21.08.2026 (Nutzer-Report per Bild: "der hintergrund da nicht genau,
der soll genau hinter dem text sein so dass es schön aussieht und man das
bild auch sieht hinter dem text").
Ursache: .hero-artwork hat "inset:0" -- es füllt also die GESAMTE Höhe von
.hero-cinematic, und diese Sektion umschließt nicht nur die Überschrift,
sondern auch die 3 Welt-Kacheln darunter. Auf Desktop ist das unauffällig
(Sektion ist nicht viel höher als das Bild), aber auf dem Handy wird die
Sektion durch den 4-zeilig umbrechenden Titel + Kacheln SEHR hoch (~1570px
bei 390px Breite) -- das Bild (16:9, per background-size:contain an die
Breite angepasst) wird dadurch nur rund 220px hoch und mittig in dieser
riesigen Fläche zentriert. Ergebnis: das Bild landete als schmaler Streifen
irgendwo zwischen den Buttons und den Welt-Kacheln -- nicht hinter der
Überschrift, für die es eigentlich gedacht ist.
Fix: .hero-artwork bekommt auf dem Handy sein eigenes, festes Seiten-
verhältnis (4:3, per Bildschirmtests etwas höher als 16:9 gewählt --
zeigt mehr vom Bild und lässt den Verlauf sanfter ausklingen) und wird
von OBEN verankert statt über die volle (riesige) Höhe zentriert. Damit
sitzt es exakt dort, wo die Überschrift beginnt. background-size wechselt
auf "cover" (statt "contain") -- bei diesem moderateren Seitenverhältnis
bleibt der Ausschnitt erkennbar (nicht wie bei "cover" auf die volle
Sektionshöhe stark eingezoomt), füllt aber die Box randlos.
Verlauf (::after) eigens für die jetzt kürzere Box abgestimmt: die
Desktop-Version fasst den Übergang über die ganze (dort kürzere) Sektion
zusammen -- 1:1 auf die neue, kleinere Handy-Box übertragen, wäre der
Übergang zu abrupt (an mehreren Bildschirmbreiten mit Playwright
gegengeprüft) gewesen. Bewusst nur bis 760px (bestehende Schwelle dieser
Seite für "Handy-Layout" u.a. bei .hero-grid) -- ab da reicht wieder die
normale Desktop-Logik. */
@media (max-width: 760px) {
.hero-artwork {
top: 0; left: 0; right: 0; bottom: auto;
aspect-ratio: 4 / 3;
height: auto;
}
.hero-artwork::before {
background-size: cover, cover;
background-position: center 25%, center;
}
.hero-artwork::after {
background:
radial-gradient(ellipse 130% 90% at 50% 35%, rgba(0, 0, 0, .12) 0%, rgba(0, 0, 0, .5) 65%, rgba(0, 0, 0, .8) 100%),
linear-gradient(to bottom, rgba(0, 0, 0, .55) 0%, rgba(0, 0, 0, .4) 45%, rgba(0, 0, 0, .7) 78%, var(--bg) 100%);
}
}
/* ==========================================================================
CHARAKTER-SHOWCASE — die zwei Artworks groß, scharf und komplett sichtbar
========================================================================== */
.char-showcase {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: clamp(1.1rem, 4vw, 2.4rem);
max-width: 760px;
margin: 0 auto;
}
@media (max-width: 620px) {
.char-showcase { grid-template-columns: 1fr; max-width: 320px; }
}
.char-card {
position: relative;
display: block;
width: 100%;
max-width: 330px;
margin-inline: auto;
border-radius: 20px;
overflow: hidden;
text-decoration: none;
background: #080c11;
border: 1px solid rgba(255, 255, 255, .10);
box-shadow: 0 26px 60px rgba(0, 0, 0, .58);
animation: char-float 11s ease-in-out infinite;
transition: transform .38s cubic-bezier(.2, .7, .3, 1),
box-shadow .38s ease,
border-color .38s ease;
}
.char-card:nth-child(2) { animation-delay: -5.5s; }
.char-card img {
display: block;
width: 100%;
aspect-ratio: 599 / 1212; /* exaktes Seitenverhältnis der Artworks — kein Zuschnitt */
object-fit: cover;
transition: transform .55s cubic-bezier(.2, .7, .3, 1);
}
/* eigener Glow pro Welt */
.char-card.dogfather { border-color: rgba(96, 175, 255, .30); }
.char-card.dogfather:hover,
.char-card.dogfather:focus-visible {
border-color: rgba(96, 175, 255, .75);
box-shadow: 0 34px 70px rgba(0, 0, 0, .62), 0 0 70px rgba(96, 175, 255, .30);
}
.char-card.hasidog { border-color: rgba(199, 204, 209, .28); }
.char-card.hasidog:hover,
.char-card.hasidog:focus-visible {
border-color: rgba(199, 204, 209, .70);
box-shadow: 0 34px 70px rgba(0, 0, 0, .62), 0 0 70px rgba(143, 217, 234, .26);
}
.char-card:hover, .char-card:focus-visible { transform: translateY(-10px); }
.char-card:hover img, .char-card:focus-visible img { transform: scale(1.045); }
.char-meta {
position: absolute;
left: 0; right: 0; bottom: 0;
padding: 3.6rem .9rem 1.1rem;
text-align: center;
background: linear-gradient(to top,
rgba(4, 8, 12, .94) 14%, rgba(4, 8, 12, .58) 52%, transparent 100%);
}
.char-meta > span { display: block; }
.char-name {
font-family: var(--font-head);
font-weight: 800;
font-size: 1.02rem;
letter-spacing: .13em;
text-transform: uppercase;
color: #fff;
text-shadow: 0 2px 14px rgba(0, 0, 0, .85);
}
.char-sub {
font-size: .76rem;
color: rgba(255, 255, 255, .70);
margin-top: .18rem;
}
.char-go {
font-size: .74rem;
font-weight: 700;
letter-spacing: .05em;
color: var(--accent);
margin-top: .5rem;
opacity: .85;
transition: opacity .3s ease, transform .3s ease;
}
.char-card:hover .char-go,
.char-card:focus-visible .char-go { opacity: 1; transform: translateX(3px); }
@keyframes char-float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}
@media (prefers-reduced-motion: reduce) {
.char-card, .char-card img { animation: none; transition: none; }
}
/* ==========================================================================
SEITEN-HINTERGRÜNDE
Jede Seite kann ihr eigenes Artwork hinter den Kopfbereich legen. Das Bild
wird nicht fest im CSS hinterlegt, sondern pro Seite über zwei Variablen
gesetzt — so bleibt eine einzige Regel für alle Seiten:
Aufbau: Bild (::before) → Abdunkelung (::after) → Inhalt.
Die Abdunkelung sorgt dafür, dass Überschriften immer lesbar bleiben und
der Rand sauber in die Seitenfarbe ausläuft.
========================================================================== */
/* ---- 1) Das Motiv trägt die GANZE Seite ----
Liegt fest hinter allem (position:fixed), leicht weichgezeichnet und
abgedunkelt. Dadurch ist das Bild beim Scrollen überall präsent, ohne
dass Texte und Karten darunter leiden. */
body.mit-hintergrund { background-color: transparent; }
body.mit-hintergrund::before {
content: "";
position: fixed;
inset: -2%;
z-index: -3;
background-image: var(--page-bg);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
/* Weichzeichnen + abdunkeln: ruhiger Untergrund, der die Augen beim Lesen
nicht anstrengt. brightness(.45) statt vorher .62 — angepasst nach dem
BFSG/WCAG-Kontrast-Audit vom 04.08.2026 (axe-core fand color-contrast-
Verstöße auf allen Seiten mit Hintergrundfoto: helle Bildstellen
schimmerten durch die Abdunkelung, besonders im Hero-Bereich oben, wo
der ::after-Verlauf am schwächsten war). */
filter: blur(4px) brightness(.45) saturate(.95);
}
/* Abdunkelung für den Seitenkörper — bewusst kräftig, damit langes Lesen
angenehm bleibt UND Text zuverlässig AA-Kontrast erreicht (siehe oben).
Werte am 04.08.2026 zweimal nachgeschärft (80/92/95% → 90/97/99% →
94/98/99.5%, volle Deckung schon ab 30% statt erst bei 100%) — nach dem
zusätzlichen Hero-Schleier (oben) waren vereinzelt noch Elemente knapp
unterhalb des Heros betroffen (z.B. `.bewerben-side-label`,
`h2.text-center` auf team-modis.html), wo der Verlauf noch nicht voll
angekommen war. Mit axe-core auf allen betroffenen Seiten gegengeprüft. */
body.mit-hintergrund::after {
content: "";
position: fixed;
inset: 0;
z-index: -2;
pointer-events: none;
background: linear-gradient(to bottom,
color-mix(in srgb, var(--bg) 94%, transparent) 0%,
color-mix(in srgb, var(--bg) 98%, transparent) 30%,
color-mix(in srgb, var(--bg) 99.5%, transparent) 100%);
}
/* ---- 2) Kopfbereich: ECHTES
statt CSS-Hintergrund ----
Nach mehreren Anläufen mit background-size (cover schnitt Ränder ab,
contain ließ Lücken, "100% auto" schnitt oben/unten ab sobald die Box
nicht exakt im Bildseitenverhältnis war) die einzige Lösung, die IMMER
beides garantiert — volle Breite UND das komplette Bild sichtbar:
ein normales
, das seine Höhe selbst
bestimmt statt in eine vorgegebene Box gepresst zu werden. Es kann
dadurch gar nicht mehr beschnitten werden, ganz gleich welches
Seitenverhältnis das Foto hat.
Das Bild sitzt dadurch als eigener Banner OBERHALB der Überschrift
(statt als Hintergrund dahinter) — dafür garantiert zuverlässig, auf
jeder Seite, mit jedem Bild, ohne weitere Handarbeit. */
.hero-banner {
position: relative;
line-height: 0; /* verhindert einen Mini-Spalt unter dem Bild */
}
.hero-banner img {
display: block;
width: 100%;
height: auto;
}
/* Weicher Übergang unten, damit das Foto nicht hart in die Seite schneidet */
.hero-banner::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to bottom,
rgba(0, 0, 0, .05) 0%,
transparent 45%,
color-mix(in srgb, var(--bg) 55%, transparent) 82%,
var(--bg) 100%);
pointer-events: none;
}
.page-bg.hero {
padding: clamp(2.4rem, 5vw, 3.4rem) 0 clamp(3rem, 7vw, 4.5rem);
}
.page-bg.hero > .container { margin-inline: auto; }
@media (max-width: 760px) {
/* Der weichgezeichnete Grund-Layer darf ruhig den Handy-Zuschnitt nehmen —
der ist nur Stimmung im Hintergrund, wird nicht "als Bild" wahrgenommen.
Der scharfe .page-bg-Layer bleibt beim VOLLEN Original, damit auf dem
Handy garantiert nichts vom eigentlichen Motiv fehlt. */
body.mit-hintergrund::before { background-image: var(--page-bg-mobile, var(--page-bg)); }
}
/* ==========================================================================
HIERARCHIE-PYRAMIDE — Team-Mitglieder stufenweise unter VanVan
Eine zentrale Linie läuft von oben (unter VanVans großer Karte) nach
unten durch alle Ebenen. Jede Ebene ist eine eigene, zentrierte Reihe;
die Kartengröße nimmt von Stufe zu Stufe leicht ab, wodurch die
Hierarchie auch optisch spürbar wird — oben groß und wichtig, nach
unten hin kompakter. An jeder Ebene sitzt ein leuchtender Knoten auf
der Linie, wie bei einem Organigramm.
========================================================================== */
.pyramid {
position: relative;
padding-top: 2.6rem;
display: flex;
flex-direction: column;
gap: clamp(2.4rem, 5vw, 3.6rem);
}
/* Die zentrale, senkrechte Verbindungslinie */
.pyramid::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 2px;
transform: translateX(-50%);
background: linear-gradient(to bottom,
color-mix(in srgb, var(--accent) 70%, transparent),
color-mix(in srgb, var(--accent-2) 55%, transparent) 55%,
transparent 100%);
box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 45%, transparent);
}
.pyramid-tier {
position: relative;
display: flex;
flex-wrap: wrap;
justify-content: center;
/* stretch statt flex-start: alle Karten einer Ebene werden gleich hoch,
egal ob der Name/die Rolle bei der einen Person länger ist als bei
der anderen (z.B. Diene/Funny) — Wunsch von Dogi. */
align-items: stretch;
gap: clamp(1rem, 3vw, 2rem);
}
/* Leuchtender Knoten pro Ebene, sitzt genau auf der Linie */
.pyramid-tier::before {
content: "";
position: absolute;
top: -1.5rem;
left: 50%;
width: 12px;
height: 12px;
border-radius: 50%;
transform: translate(-50%, -50%);
background: var(--accent);
box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 18%, transparent),
0 0 18px color-mix(in srgb, var(--accent) 65%, transparent);
z-index: 2;
}
.pyramid-tier .profile-card {
width: 100%;
/* Flex-Spalte, damit der "Profil ansehen"-Button per margin-top:auto immer
ganz unten sitzt — dadurch wirken alle Karten einer Ebene gleich hoch
und gleich aufgebaut, auch wenn Name/Rolle unterschiedlich lang sind. */
display: flex;
flex-direction: column;
align-items: center;
transition: transform .3s cubic-bezier(.2,.7,.3,1), box-shadow .3s ease, border-color .3s ease;
}
.pyramid-tier .profile-card .btn { margin-top: auto; }
.pyramid-tier .profile-card:hover { transform: translateY(-6px) scale(1.02); }
/* Fünf Größenstufen — je tiefer, desto kompakter */
.pyramid-tier[data-tier="1"] .profile-card { max-width: 260px; }
.pyramid-tier[data-tier="2"] .profile-card { max-width: 240px; }
.pyramid-tier[data-tier="3"] .profile-card { max-width: 222px; }
.pyramid-tier[data-tier="4"] .profile-card { max-width: 206px; }
.pyramid-tier[data-tier="5"] .profile-card { max-width: 192px; }
.pyramid-tier[data-tier="1"] .avatar { width: 108px; height: 108px; }
.pyramid-tier[data-tier="2"] .avatar { width: 98px; height: 98px; }
.pyramid-tier[data-tier="3"] .avatar { width: 90px; height: 90px; }
.pyramid-tier[data-tier="4"] .avatar { width: 82px; height: 82px; }
.pyramid-tier[data-tier="5"] .avatar { width: 76px; height: 76px; }
.pyramid-tier[data-tier="3"] .profile-card h3,
.pyramid-tier[data-tier="4"] .profile-card h3,
.pyramid-tier[data-tier="5"] .profile-card h3 { font-size: 1.02rem; }
.pyramid-tier[data-tier="4"] .role,
.pyramid-tier[data-tier="5"] .role { font-size: .78rem; }
@media (max-width: 700px) {
.pyramid-tier { gap: 1rem; }
.pyramid-tier .profile-card { max-width: min(78vw, 240px) !important; }
}
/* ==========================================================================
BEWERBEN-SHOWCASE — die beiden Kampagnen-Poster (Dogfather/Team-Dogi
links, Spicy Media rechts) flankieren die Bewerbungs-Spalten wie
Kinoplakate. Bewusst NICHT als verwaschener Hintergrund HINTER den
Karten (das hätte Lesbarkeit gekostet), sondern als eigene, scharfe
Bildspalten DANEBEN — dadurch bleiben die Poster in voller Qualität
sichtbar UND die Bewerbungs-Karten bleiben ungestört lesbar. Jedes
Poster fasst farblich zur jeweiligen Seite (blau/rot) und blendet nach
unten sanft aus, damit es nicht wie ein hart abgeschnittenes Rechteck
wirkt, sondern organisch in die Seite übergeht. */
.bewerben-showcase {
display: flex;
align-items: center;
justify-content: center;
gap: clamp(1rem, 3vw, 2.2rem);
}
.bewerben-poster {
flex: 0 0 auto;
width: clamp(120px, 15vw, 220px);
aspect-ratio: 2 / 3;
border-radius: var(--radius);
overflow: hidden;
position: relative;
align-self: center;
-webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent 100%);
mask-image: linear-gradient(to bottom, #000 78%, transparent 100%);
transition: transform .25s ease, filter .25s ease;
}
.bewerben-poster img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: top center;
display: block;
}
.bewerben-poster::after {
content: "";
position: absolute;
inset: 0;
border-radius: var(--radius);
pointer-events: none;
}
.bewerben-poster-blau {
box-shadow: 0 18px 46px rgba(0, 0, 0, .55), 0 0 30px rgba(143, 217, 234, .22);
transform: rotate(-2.5deg);
}
.bewerben-poster-blau::after { box-shadow: inset 0 0 0 1px rgba(143, 217, 234, .35); }
.bewerben-poster-rot {
box-shadow: 0 18px 46px rgba(0, 0, 0, .55), 0 0 30px rgba(217, 74, 92, .22);
transform: rotate(2.5deg);
}
.bewerben-poster-rot::after { box-shadow: inset 0 0 0 1px rgba(217, 74, 92, .35); }
.bewerben-poster:hover { transform: rotate(0deg) translateY(-4px) scale(1.03); filter: brightness(1.08); }
@media (max-width: 1080px) {
.bewerben-poster { display: none; }
}
/* ==========================================================================
BEWERBEN-SPLIT — zwei Welten, zwei Spalten, kleine Trennwand in der Mitte
Passend zum Hintergrundbild: Community/Team Dogi (blau) links,
Agentur/Spicy Media (rot) rechts.
========================================================================== */
.bewerben-split {
display: flex;
align-items: stretch;
gap: clamp(1.4rem, 4vw, 3.2rem);
max-width: 980px;
margin: 0 auto;
}
.bewerben-side {
flex: 1 1 0;
min-width: 0;
display: flex;
flex-direction: column;
gap: 1.2rem;
}
.bewerben-side-label {
text-align: center;
font-family: var(--font-head);
font-weight: 800;
font-size: .74rem;
letter-spacing: .1em;
text-transform: uppercase;
margin-bottom: .2rem;
}
.bewerben-side-blau .bewerben-side-label { color: #8fd9ea; text-shadow: 0 0 14px rgba(143, 217, 234, .5); }
.bewerben-side-rot .bewerben-side-label { color: #d94a5c; text-shadow: 0 0 14px rgba(217, 74, 92, .5); }
.bewerben-side .card { height: auto; }
/* Die kleine Trennungswand: ein leuchtender Steg von blau nach rot,
mit einem Blitz-Knoten in der Mitte — passend zur Lichtgrenze im Bild. */
.bewerben-wall {
flex: none;
width: 3px;
align-self: stretch;
position: relative;
border-radius: 3px;
background: linear-gradient(to bottom,
transparent 0%,
#8fd9ea 18%,
#b285c9 50%,
#d94a5c 82%,
transparent 100%);
box-shadow: 0 0 16px rgba(143, 217, 234, .35), 0 0 16px rgba(217, 74, 92, .3);
}
/* "Reaktorkern"-Emblem: dunkle Mitte mit statischem Blitz, dahinter ein
EIGENER, separat rotierender Farbring (::before) — dadurch dreht sich
der Farbschein, ohne dass der Blitz selbst mitdreht/schief steht. */
.bewerben-wall span {
position: relative;
isolation: isolate;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.65rem;
background: radial-gradient(circle at 34% 28%, #232830, #0a0c10 72%);
border: 1px solid rgba(255, 255, 255, .2);
text-shadow: 0 0 10px rgba(255, 214, 140, .9), 0 0 4px rgba(0, 0, 0, .6);
box-shadow: 0 0 0 4px rgba(10, 12, 16, .85),
0 0 0 6px rgba(255, 255, 255, .14),
0 0 26px rgba(143, 217, 234, .45),
0 0 26px rgba(217, 74, 92, .4);
}
.bewerben-wall span::before {
content: "";
position: absolute;
inset: -5px;
z-index: -1;
border-radius: 50%;
background: conic-gradient(from 0deg,
#8fd9ea 0%, #b285c9 25%, #d94a5c 50%, #b285c9 75%, #8fd9ea 100%);
filter: blur(2px) saturate(1.3);
animation: bewerben-emblem-spin 5s linear infinite;
}
@keyframes bewerben-emblem-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.bewerben-wall span::before { animation: none; }
}
@media (max-width: 760px) {
.bewerben-split { flex-direction: column; gap: 2.2rem; width: 100%; }
.bewerben-side { width: 100%; }
.bewerben-side .card { width: 100%; box-sizing: border-box; }
.bewerben-wall {
width: 100%;
height: 3px;
background: linear-gradient(to right, transparent 0%, #8fd9ea 18%, #b285c9 50%, #d94a5c 82%, transparent 100%);
}
}
/* ==========================================================================
.card-duel — "Ultra"-Überarbeitung der vier Bewerbungs-Karten auf
bewerben.html (03.08.2026, auf Wunsch: "extrem geil, ultra von ultra,
trotzdem professionell", Farben MÜSSEN gleich bleiben). Nutzt bewusst
dieselben --accent/--accent-2-Variablen, die pro Karte schon gesetzt
sind (Community-Karten inline babyblau/lila, Agentur-Karten automatisch
rot/orange vom Spicy-Media-Theme) — dadurch bleibt die Farbwelt exakt
erhalten, nur die Machart wird komplett neu: rotierender Farbring um
die Karte, driftender Aurora-Glow im Hintergrund, leuchtendes Icon-
Badge statt schlichtem Rahmen-Tag, dramatischer Hover-Lift mit
Farbexplosion. ========================================================================== */
.card-duel {
position: relative;
isolation: isolate;
overflow: hidden;
background:
radial-gradient(140% 120% at 12% -15%, color-mix(in srgb, var(--accent) 20%, transparent), transparent 55%),
var(--card-bg);
border: 1px solid rgba(255, 255, 255, .14);
border-radius: calc(var(--radius) + 6px);
padding: 2.1rem 1.9rem 2.3rem;
transition: transform .35s cubic-bezier(.2, .8, .2, 1.25), box-shadow .35s ease, border-color .3s ease;
box-shadow: 0 14px 34px rgba(0, 0, 0, .5);
}
/* Rotierender, dünner Farbring exakt am Kartenrand entlang */
.card-duel::before {
content: "";
position: absolute;
inset: -1.5px;
z-index: 0;
border-radius: inherit;
padding: 2px;
background: conic-gradient(from 0deg,
var(--accent) 0deg, var(--accent-2) 90deg, transparent 150deg, transparent 210deg, var(--accent) 270deg, var(--accent) 360deg);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: .6;
animation: card-duel-rotate 7s linear infinite;
}
/* Driftender Farbschein-Nebel im Hintergrund, hinter dem Text */
.card-duel::after {
content: "";
position: absolute;
inset: -45%;
z-index: 0;
background:
radial-gradient(circle at 20% 22%, color-mix(in srgb, var(--accent) 55%, transparent), transparent 55%),
radial-gradient(circle at 85% 85%, color-mix(in srgb, var(--accent-2) 50%, transparent), transparent 58%);
filter: blur(26px) saturate(1.35);
opacity: .45;
animation: nav-cta-aurora 8s ease-in-out infinite alternate;
pointer-events: none;
}
.card-duel > * { position: relative; z-index: 2; }
.card-duel .tag {
display: inline-flex;
align-items: center;
gap: .35rem;
background: color-mix(in srgb, var(--accent) 20%, transparent);
border: 1px solid color-mix(in srgb, var(--accent) 65%, transparent);
color: #fff;
font-weight: 700;
text-shadow: 0 0 8px color-mix(in srgb, var(--accent) 70%, black 20%);
box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 40%, transparent);
}
.card-duel h3 {
font-size: 1.55rem;
text-shadow: 0 2px 12px rgba(0, 0, 0, .5);
}
.card-duel p { font-size: 1.04rem; }
.card-duel:hover {
transform: translateY(-9px) scale(1.025);
border-color: color-mix(in srgb, var(--accent) 70%, transparent);
box-shadow: 0 26px 54px rgba(0, 0, 0, .6),
0 0 44px color-mix(in srgb, var(--accent) 50%, transparent),
0 0 44px color-mix(in srgb, var(--accent-2) 40%, transparent);
}
@keyframes card-duel-rotate { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
.card-duel::before, .card-duel::after { animation: none; }
}
/* Trennwand + Emblem: von schlichtem Steg zu einem pulsierenden
"Energiekern" mit Doppelring und fließendem Lichtstrom aufgewertet. */
.bewerben-wall {
background-size: 100% 220%;
animation: bewerben-wall-flow 3.4s linear infinite;
}
@keyframes bewerben-wall-flow {
0% { background-position: 0 20%; }
100% { background-position: 0 -180%; }
}
.bewerben-wall span {
animation: bewerben-emblem-pulse 2.4s ease-in-out infinite;
}
@keyframes bewerben-emblem-pulse {
0%, 100% {
transform: translate(-50%, -50%) scale(1);
box-shadow: 0 0 0 4px rgba(10, 12, 16, .85), 0 0 0 6px rgba(255, 255, 255, .14),
0 0 26px rgba(143, 217, 234, .45), 0 0 26px rgba(217, 74, 92, .4);
}
50% {
transform: translate(-50%, -50%) scale(1.08);
box-shadow: 0 0 0 4px rgba(10, 12, 16, .85), 0 0 0 7px rgba(255, 255, 255, .26),
0 0 42px rgba(143, 217, 234, .7), 0 0 42px rgba(217, 74, 92, .6);
}
}
@media (prefers-reduced-motion: reduce) {
.bewerben-wall, .bewerben-wall span { animation: none; }
}
/* Seitenlabels: leuchtender Unterstrich statt schlichtem Text */
.bewerben-side-label {
position: relative;
padding-bottom: .55rem;
font-size: .8rem;
}
.bewerben-side-label::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 64px;
height: 2px;
border-radius: 2px;
}
.bewerben-side-blau .bewerben-side-label::after {
background: linear-gradient(90deg, transparent, #8fd9ea, transparent);
box-shadow: 0 0 10px rgba(143, 217, 234, .6);
}
.bewerben-side-rot .bewerben-side-label::after {
background: linear-gradient(90deg, transparent, #d94a5c, transparent);
box-shadow: 0 0 10px rgba(217, 74, 92, .6);
}
/* ==========================================================================
TEAM-DOGI-HINTERGRUND — die große Team-Collage hinter dem Team-Abschnitt
========================================================================== */
.team-bg {
position: relative;
isolation: isolate;
overflow: hidden;
}
.team-bg::before {
content: "";
position: absolute;
inset: 0;
z-index: -2;
background-image: url("../img/team-dogi-bg.jpg");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
/* Abdunkelung, damit Text und Avatare klar davor stehen und die Ränder
sauber in die Seite auslaufen */
.team-bg::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
background:
radial-gradient(ellipse 110% 80% at 50% 50%,
rgba(0, 0, 0, .58) 0%, rgba(0, 0, 0, .80) 65%, rgba(0, 0, 0, .93) 100%),
linear-gradient(to bottom, var(--bg) 0%, transparent 14%, transparent 86%, var(--bg) 100%);
}
@media (max-width: 760px) {
.team-bg::before {
background-image: url("../img/team-dogi-bg-mobile.jpg");
}
}
/* Kurzes, dezentes Abblenden während ein Seitenwechsel geholt wird */
body.seite-laedt main { opacity: .55; transition: opacity .15s ease; }
/* ==========================================================================
MUSIK-KNOPF — kleiner schwebender Knopf unten rechts, auf jeder Seite
Klick öffnet ein Feld mit den Spotify-Playern von Hasidog und Van-Van.
Bewusst schwebend (position:fixed) statt als eigener Seitenabschnitt:
so ist die Musik überall mit einem Klick erreichbar, nimmt aber nirgends
Platz weg. Die Player werden erst beim ersten Öffnen geladen.
========================================================================== */
.music-widget {
position: fixed;
right: 22px;
bottom: 22px;
z-index: 120;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 12px;
}
/* Musik-Knopf: gleicher STIL wie der "Bewerben"-Knopf oben in der Leiste
(dunkler Grund + wandernde, weichgezeichnete Farbwolken + durchlaufender
Lichtschimmer) — aber mit den Chamäleon-Farben der jeweiligen Seite statt
der festen Regenbogen-Palette. "Chamäleon" heißt: main.js
(musikKnopfFarbenAnpassen) liest per Canvas das tatsächliche Bild der
Seite aus (Durchschnitts- + kräftigste Farbe daraus) und setzt
--music-c1/--music-c2 live. Ohne Bild (oder solange JS noch lädt) fällt
der Knopf sauber auf die normale Weltfarbe --accent/--accent-2 zurück.
Auf der Startseite und den Bewerben-Seiten überschreibt ein eigener Block
weiter unten die Farben fest auf die Bewerben-Palette (siehe dort). */
.music-toggle {
position: relative;
isolation: isolate;
overflow: hidden;
width: 54px;
height: 54px;
flex: none;
border-radius: 999px;
font-size: 1.45rem;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #fff;
text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
background: #0b0e14;
border: 1px solid color-mix(in srgb, var(--music-c1, var(--accent)) 55%, transparent);
box-shadow: 0 12px 30px rgba(0, 0, 0, .45),
0 0 24px color-mix(in srgb, var(--music-c1, var(--accent)) 35%, transparent);
transition: transform .25s ease, filter .25s ease, box-shadow .25s ease, border-color 1.1s ease;
}
.music-toggle::before {
content: "";
position: absolute;
inset: -50%;
z-index: 0;
background:
radial-gradient(circle at 25% 30%, color-mix(in srgb, var(--music-c1, var(--accent)) 92%, transparent), transparent 58%),
radial-gradient(circle at 75% 72%, color-mix(in srgb, var(--music-c2, var(--accent-2)) 92%, transparent), transparent 58%);
filter: blur(7px) saturate(1.3);
animation: btn-aurora 10s ease-in-out infinite alternate;
transition: background 1.1s ease;
}
.music-toggle::after {
content: "";
position: absolute;
inset: 0;
z-index: 1;
border-radius: 999px;
background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, .35) 49%, transparent 63%);
background-size: 240% 100%;
mix-blend-mode: overlay;
animation: btn-shimmer 5s linear infinite;
pointer-events: none;
}
.music-toggle:hover,
.music-toggle:focus-visible {
transform: translateY(-2px) scale(1.05);
filter: brightness(1.12);
box-shadow: 0 16px 38px rgba(0, 0, 0, .5),
0 0 34px color-mix(in srgb, var(--music-c1, var(--accent)) 55%, transparent);
}
.music-widget.open .music-toggle { transform: rotate(12deg); }
.music-toggle span { position: relative; z-index: 2; }
@media (prefers-reduced-motion: reduce) {
.music-toggle::before, .music-toggle::after { animation: none; }
}
/* Auf der Startseite UND den Bewerben-Seiten bekommt der Musik-Knopf
dieselbe Polarlicht-Farbe wie der "Bewerben"-Knopf oben in der Leiste
(statt der Chamäleon-Farben vom Seitenbild) — das sind die beiden
Stellen, an denen bewusst "alle Welten auf einmal" gezeigt werden. */
body.bewerben-seite .music-toggle,
body.start-seite .music-toggle {
position: relative;
isolation: isolate;
overflow: hidden;
background: #0b0e14;
border-color: rgba(255, 255, 255, .18);
color: #fff;
}
body.bewerben-seite .music-toggle::before,
body.start-seite .music-toggle::before {
content: "";
position: absolute;
inset: -40%;
z-index: 0;
background:
radial-gradient(circle at 20% 25%, rgba(143, 217, 234, .95), transparent 55%),
radial-gradient(circle at 45% 75%, rgba(139, 92, 246, .9), transparent 58%),
radial-gradient(circle at 80% 30%, rgba(217, 74, 92, .95), transparent 55%),
radial-gradient(circle at 60% 85%, rgba(232, 147, 58, .55), transparent 55%);
filter: blur(6px) saturate(1.35);
animation: nav-cta-aurora 9s ease-in-out infinite alternate;
}
body.bewerben-seite .music-toggle::after,
body.start-seite .music-toggle::after {
content: "";
position: absolute;
inset: 0;
z-index: 1;
border-radius: 999px;
background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, .4) 49%, transparent 63%);
background-size: 240% 100%;
mix-blend-mode: overlay;
animation: nav-cta-shimmer 4.5s linear infinite;
pointer-events: none;
}
body.bewerben-seite .music-toggle:hover,
body.bewerben-seite .music-toggle:focus-visible,
body.start-seite .music-toggle:hover,
body.start-seite .music-toggle:focus-visible {
box-shadow: 0 16px 38px rgba(0, 0, 0, .5),
0 0 22px rgba(143, 217, 234, .3),
0 0 22px rgba(217, 74, 92, .28);
}
@media (prefers-reduced-motion: reduce) {
body.bewerben-seite .music-toggle::before,
body.bewerben-seite .music-toggle::after,
body.start-seite .music-toggle::before,
body.start-seite .music-toggle::after { animation: none; }
}
.music-panel {
width: min(330px, calc(100vw - 44px));
max-height: min(74vh, 640px);
overflow-y: auto;
padding: 1rem 1.1rem 1.2rem;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card-bg);
box-shadow: 0 24px 60px rgba(0, 0, 0, .6);
animation: music-panel-in .22s ease-out;
}
.music-panel[hidden] { display: none; }
@keyframes music-panel-in {
from { opacity: 0; transform: translateY(10px) scale(.97); }
to { opacity: 1; transform: none; }
}
.music-panel-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: .6rem;
}
.music-panel-head strong { font-size: .95rem; }
.music-close {
background: none;
border: 0;
color: var(--text-muted);
font-size: 1rem;
line-height: 1;
padding: .2rem .3rem;
cursor: pointer;
border-radius: 6px;
}
.music-close:hover { color: var(--accent); }
.music-artist-label {
margin: .9rem 0 .4rem;
font-size: .7rem;
font-weight: 800;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--text-muted);
}
/* Spotify bringt seinen eigenen abgerundeten Rahmen mit — hier nur Größe setzen. */
.music-panel iframe {
display: block;
width: 100%;
border: 0;
border-radius: 12px;
}
@media (max-width: 620px) {
.music-widget { right: 14px; bottom: 14px; }
.music-toggle { width: 48px; height: 48px; font-size: 1.25rem; }
}
@media print { .music-widget { display: none !important; } }
@media (prefers-reduced-motion: reduce) {
.music-panel { animation: none; }
.music-toggle { transition: none; }
}
/* =========================================================================
Vorschau-Umschalter (nur für Dogi/VanVan, siehe main.js
renderVorschauSchalter/gate-worker.js) — unten LINKS, spiegelbildlich zum
Musik-Knopf unten rechts, exakt dieselbe Bauart (Kreisknopf mit
wandernden Farbwolken + Lichtschimmer, aufklappbares Panel). Eigenes,
festes Farbpaar (Gold/Lila, das Supporter-Abo-Motiv) statt der
Chamäleon-Farben des Musik-Knopfs — dieser Knopf soll bewusst IMMER
gleich aussehen, unabhängig vom Seitenbild. Symbol: 🎭 (Theatermasken —
"als jemand anderes ansehen", passt zum Rollen-Vorschau-Zweck). Nutzer-
Feedback 03.08.2026: statt einer dauerhaft sichtbaren Text-Knopfleiste
sollte es "so ein Button wie bei VanVan" sein, der sich erst bei Klick
öffnet. ========================================================== */
.vorschau-widget {
position: fixed;
left: 22px;
bottom: 22px;
z-index: 120;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.vorschau-toggle {
position: relative;
isolation: isolate;
overflow: hidden;
width: 54px;
height: 54px;
flex: none;
border-radius: 999px;
font-size: 1.45rem;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #fff;
text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
background: #0b0e14;
border: 1px solid rgba(212, 175, 55, .55);
box-shadow: 0 12px 30px rgba(0, 0, 0, .45), 0 0 24px rgba(212, 175, 55, .3);
transition: transform .25s ease, filter .25s ease, box-shadow .25s ease;
}
.vorschau-toggle::before {
content: "";
position: absolute;
inset: -50%;
z-index: 0;
background:
radial-gradient(circle at 25% 30%, rgba(255, 214, 102, .95), transparent 58%),
radial-gradient(circle at 75% 72%, rgba(139, 92, 246, .9), transparent 58%);
filter: blur(7px) saturate(1.3);
animation: btn-aurora 10s ease-in-out infinite alternate;
}
.vorschau-toggle::after {
content: "";
position: absolute;
inset: 0;
z-index: 1;
border-radius: 999px;
background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, .35) 49%, transparent 63%);
background-size: 240% 100%;
mix-blend-mode: overlay;
animation: btn-shimmer 5s linear infinite;
pointer-events: none;
}
.vorschau-toggle:hover, .vorschau-toggle:focus-visible {
transform: translateY(-2px) scale(1.05);
filter: brightness(1.12);
box-shadow: 0 16px 38px rgba(0, 0, 0, .5), 0 0 34px rgba(212, 175, 55, .5);
}
.vorschau-widget.open .vorschau-toggle { transform: rotate(-12deg); }
.vorschau-toggle span { position: relative; z-index: 2; }
@media (prefers-reduced-motion: reduce) { .vorschau-toggle::before, .vorschau-toggle::after { animation: none; } }
.vorschau-panel {
width: min(260px, calc(100vw - 44px));
padding: 1rem 1.1rem 1.1rem;
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--card-bg);
box-shadow: 0 24px 60px rgba(0, 0, 0, .6);
animation: music-panel-in .22s ease-out;
}
.vorschau-panel[hidden] { display: none; }
.vorschau-panel-head {
display: flex; align-items: center; justify-content: space-between; gap: .6rem;
margin-bottom: .8rem;
}
.vorschau-panel-head strong { font-size: .92rem; color: #ffe9a8; }
.vorschau-close {
background: none; border: 0; color: var(--text-muted); font-size: 1rem;
line-height: 1; padding: .2rem .3rem; cursor: pointer; border-radius: 6px;
}
.vorschau-close:hover { color: var(--accent); }
.vorschau-optionen { display: flex; flex-direction: column; gap: .4rem; }
.vorschau-optionen button {
display: block; width: 100%; text-align: left; font-size: .88rem; font-weight: 600;
padding: .6rem .8rem; border-radius: 9px; cursor: pointer;
background: transparent; border: 1px solid transparent; color: var(--text-muted);
transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.vorschau-optionen button:hover { border-color: var(--border); color: var(--text); }
.vorschau-optionen button.aktiv {
border-color: rgba(212, 175, 55, .6); color: #ffe9a8; background: rgba(212, 175, 55, .1);
}
@media (max-width: 620px) {
.vorschau-widget { left: 14px; bottom: 14px; }
.vorschau-toggle { width: 48px; height: 48px; font-size: 1.25rem; }
}
@media print { .vorschau-widget { display: none !important; } }
@media (prefers-reduced-motion: reduce) { .vorschau-panel { animation: none; } }
/* ---------- Live-Status-Punkt ---------- */
.live-dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background: #e05260; /* rot = offline (Standard) */
box-shadow: 0 0 8px rgba(224, 82, 96, .55);
margin-right: .45rem;
vertical-align: middle;
transition: background .3s ease, box-shadow .3s ease;
}
.live-dot.is-live {
background: #22c55e; /* grün = live */
animation: live-pulse 1.6s infinite;
}
/* Solange der Status noch geladen wird: neutral grau, damit nie kurz
fälschlich "offline" aufblitzt. */
.live-dot.is-unknown {
background: #6b7280;
box-shadow: none;
}
@keyframes live-pulse {
0% { box-shadow: 0 0 0 0 rgba(34, 197, 94, .55); }
70% { box-shadow: 0 0 0 10px rgba(34, 197, 94, 0); }
100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); }
}
@media (prefers-reduced-motion: reduce) {
.live-dot.is-live { animation: none; }
}
/* ---------- Badges / Hierarchy ---------- */
.badge { display: inline-block; font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; padding: .2rem .6rem; border-radius: 999px; background: var(--bg-alt); border: 1px solid var(--border); color: var(--text-muted); }
.badge.rank-1 { border-color: var(--accent); color: var(--accent); }
/* ---------- QR ---------- */
.qr-card { text-align: center; }
.qr-card .img-placeholder { width: 160px; height: 160px; margin: 0 auto 1rem; aspect-ratio: auto; }
/* ---------- Utility ---------- */
.text-center { text-align: center; }
.mt-0 { margin-top: 0; }
.muted { color: var(--text-muted); }
.small { font-size: .85rem; }
.todo-note {
border: 1px dashed var(--accent-2);
background: rgba(139,92,246,.08);
padding: 1rem 1.2rem;
border-radius: 10px;
font-size: .85rem;
color: var(--text-muted);
margin: 1.5rem 0;
}
.todo-note strong { color: var(--accent-2); }
/* ===================================================================
Streamplan — "Live-Radar" (20.08.2026, Nutzer-Wunsch: "soll viel
geiler und spezieller sein, überrasch mich"). Ein 24-Stunden-Ziffernblatt
als SVG: der feste 20-Uhr-Termin leuchtet dauerhaft als Fixpunkt, ein
"Jetzt"-Zeiger bewegt sich in Echtzeit mit der tatsächlichen Uhrzeit,
ein sanft rotierender Lichtschein sorgt für Atmosphäre. Schaltet live
auf Rot/Puls um, sobald DogFather laut /live-status wirklich sendet —
sonst zählt ein echter Sekunden-Countdown zum nächsten 20-Uhr-Termin
runter. Bewusst augenschonend: gedeckte Farben, langsame, sanfte
Animation, kompletter Stillstand bei prefers-reduced-motion. ================================================================= */
/* Reihe für 1-2 Uhren nebeneinander (20.08.2026: zweite Uhr für ein
"spezielles Live-Event", siehe assets/js/streamplan.js) — bricht auf
schmalen Bildschirmen automatisch untereinander um. */
.stream-radar-reihe {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: flex-start;
gap: 2.4rem;
margin-top: 1.4rem;
}
/* .stream-radar-wrap setzt selbst "display", das schlägt bei gleicher
Spezifität die eingebaute [hidden]-Regel des Browsers (identisches,
inzwischen mehrfach gefundenes Muster auf dieser Seite) — deshalb hier
explizit VOR der Klassenregel. */
.stream-radar-wrap[hidden] { display: none; }
.stream-radar-wrap { display: flex; flex-direction: column; align-items: center; margin: 0 auto; }
.stream-radar {
position: relative;
width: min(300px, 70vw);
aspect-ratio: 1;
margin: 0 auto;
}
.stream-radar-sweep {
position: absolute;
inset: -6%;
border-radius: 50%;
background: conic-gradient(from 0deg,
transparent 0deg, rgba(143, 217, 234, .28) 40deg, transparent 90deg,
transparent 200deg, rgba(232, 196, 101, .22) 250deg, transparent 300deg,
transparent 320deg, rgba(139, 92, 246, .24) 350deg, transparent 360deg);
animation: stream-radar-rotate 16s linear infinite;
pointer-events: none;
}
/* Farbvariante fürs spezielle Live-Event (Nutzer-Wunsch "bissl Farbe") —
Magenta/Violett/Gold statt Cyan/Violett/Gold, damit die zweite Uhr auch
auf den ersten Blick als "etwas Besonderes" erkennbar ist. */
.stream-radar.event-spezial .stream-radar-sweep {
background: conic-gradient(from 0deg,
transparent 0deg, rgba(255, 92, 180, .26) 40deg, transparent 90deg,
transparent 200deg, rgba(232, 196, 101, .22) 250deg, transparent 300deg,
transparent 320deg, rgba(139, 92, 246, .28) 350deg, transparent 360deg);
}
@keyframes stream-radar-rotate { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .stream-radar-sweep { animation: none; } }
.stream-radar-dial { position: relative; width: 100%; height: 100%; display: block; }
/* Bunter Verlauf statt reinem Grau-Ton auf dem äußeren Ring (Nutzer-Wunsch
"bissl Farbe") — Farbverlauf steckt als direkt im SVG
jeder Uhr (siehe streamplan.html), hier nur die Basiswerte/Deckkraft. */
.radar-ring-outer { fill: none; stroke-width: 2; opacity: .8; }
.radar-ring-inner { fill: rgba(255, 255, 255, .02); stroke: rgba(255, 255, 255, .07); stroke-width: 1; }
.radar-tick { stroke: rgba(255, 255, 255, .22); stroke-width: 1.5; }
.radar-tick-major { stroke: rgba(255, 255, 255, .5); stroke-width: 2.2; }
.radar-tick-label { fill: var(--text-muted); font-size: 11px; font-family: var(--font-body, inherit); }
.radar-fixmarker-dot {
fill: #e8c465;
filter: drop-shadow(0 0 6px rgba(232, 196, 101, .9)) drop-shadow(0 0 14px rgba(232, 196, 101, .5));
animation: stream-radar-fixpuls 3.2s ease-in-out infinite;
}
@keyframes stream-radar-fixpuls { 0%, 100% { opacity: .75; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .radar-fixmarker-dot { animation: none; opacity: .9; } }
.radar-now-hand {
stroke: var(--accent);
stroke-width: 2.5;
stroke-linecap: round;
filter: drop-shadow(0 0 4px var(--accent));
transition: x2 .6s ease, y2 .6s ease;
}
.radar-now-dot {
fill: var(--accent);
filter: drop-shadow(0 0 6px var(--accent));
transition: cx .6s ease, cy .6s ease;
}
.stream-radar.ist-live .radar-now-hand,
.stream-radar.ist-live .radar-now-dot { stroke: #ff5c72; fill: #ff5c72; filter: drop-shadow(0 0 8px rgba(255, 92, 114, .8)); }
.radar-center-dot { fill: var(--text); opacity: .8; }
.stream-radar-center {
position: absolute;
inset: 24%;
border-radius: 50%;
background: rgba(8, 10, 14, .82);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: .5rem;
gap: .25rem;
}
.stream-radar-dot {
width: 10px; height: 10px;
border-radius: 50%;
background: var(--text-muted);
margin-bottom: .2rem;
}
.stream-radar.ist-live .stream-radar-dot { background: #ff5c72; box-shadow: 0 0 10px rgba(255, 92, 114, .8); animation: stream-radar-live-puls 1.4s ease-in-out infinite; }
@keyframes stream-radar-live-puls { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.35); opacity: .75; } }
@media (prefers-reduced-motion: reduce) { .stream-radar.ist-live .stream-radar-dot { animation: none; } }
.stream-radar-status { font-size: 1rem; font-weight: 800; color: var(--text); line-height: 1.25; }
.stream-radar-countdown {
font-variant-numeric: tabular-nums;
font-size: 1.55rem;
font-weight: 900;
letter-spacing: .02em;
color: var(--accent);
}
.stream-radar.ist-live .stream-radar-countdown { color: #ff5c72; }
.stream-radar-sub { font-size: .74rem; color: var(--text-muted); }
/* Farbvariante fürs spezielle Live-Event: der Fixpunkt ist hier nicht der
tägliche 20-Uhr-Termin, sondern der eigene Zieltermin -- Magenta statt
Gold, damit man beide Uhren auf einen Blick unterscheidet. */
.stream-radar.event-spezial .radar-fixmarker-dot {
fill: #ff5cb8;
filter: drop-shadow(0 0 6px rgba(255, 92, 184, .9)) drop-shadow(0 0 14px rgba(255, 92, 184, .5));
}
.stream-radar.event-spezial:not(.ist-live) .radar-now-hand,
.stream-radar.event-spezial:not(.ist-live) .radar-now-dot { stroke: #c9a6ff; fill: #c9a6ff; filter: drop-shadow(0 0 5px rgba(201, 166, 255, .8)); }
.stream-radar.event-spezial:not(.ist-live) .stream-radar-countdown { color: #ff5cb8; }
.stream-radar-titel { font-size: .95rem; font-weight: 800; color: #ff9ed4; margin-bottom: .3rem; }
/* .btn setzt selbst "display", das schlägt bei gleicher Spezifität die
eingebaute [hidden]-Regel des Browsers (identisches Muster wie bei
.jahres-event-card weiter oben) — deshalb hier explizit. */
.stream-radar-watch-btn[hidden] { display: none; }
.stream-radar-watch-btn { margin-top: 1.1rem; }
.stream-radar-hinweis { margin-top: 1rem; opacity: .8; }
/* ===================================================================
"Stimmen" — eigene Nachricht einreichen (20.08.2026, Nutzer-Wunsch:
"eine richtig geile kachel ... das wird mega persoenlich zu den fans,
bitte wirklich krass geil speziell"). Warmer Babyblau/Rosé/Lila-
Farbverlauf statt der neutralen Standardkarte, wandernder Lichtschein
am Rand (dieselbe Zwei-Ebenen-Technik wie schon an mehreren Stellen
dieses Projekts, siehe .supp-card::before) — bewusst augenschonend
(gedeckte Farben, sanfte Bewegung, respektiert reduzierte Bewegung). ================================================================= */
/* Nutzer-Wunsch 20.08.2026 (2. Runde): "die kachel soll noch spezieller und
geiler aussehen". Deutlich aufgewertet gegenüber der ersten Fassung:
wandernder Farbverlauf-Rahmen rundherum (Zwei-Ebenen-Technik mit
background-position statt eines rotierenden Rings — siehe dokumentierte
Projekt-Lektion: rotierende Masken verzerren auf eckigen Flächen),
schwebende Herz-Partikel im Hintergrund, Medaillon statt nacktem Emoji,
Farbverlauf-Überschrift und Eingabefelder, die beim Tippen aufleuchten.
Bleibt trotzdem augenschonend: gedeckte Töne, langsame Bewegungen,
vollständiger Stillstand bei prefers-reduced-motion. */
.stimmen-einreichen-kachel {
position: relative;
isolation: isolate;
overflow: hidden;
max-width: 580px;
margin: 0 auto;
padding: 2.4rem 2.4rem 2.6rem;
border-radius: calc(var(--radius) + 4px);
background:
radial-gradient(ellipse at 12% 0%, rgba(255, 154, 208, .13), transparent 58%),
radial-gradient(ellipse at 88% 100%, rgba(143, 217, 234, .13), transparent 58%),
linear-gradient(180deg, rgba(24, 34, 51, .96), rgba(14, 20, 32, .98));
box-shadow: 0 30px 70px rgba(0, 0, 0, .45), 0 0 50px rgba(143, 217, 234, .06);
}
/* Farbverlauf-Rahmen: zwei Ebenen, nur die Hintergrundposition wandert. */
.stimmen-einreichen-kachel::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
padding: 1.5px;
background: linear-gradient(115deg, rgba(255,154,208,.75), rgba(143,217,234,.75), rgba(199,204,209,.5), rgba(255,154,208,.75));
background-size: 300% 100%;
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask-composite: exclude;
animation: stimmen-rahmen-wandert 9s linear infinite;
}
@keyframes stimmen-rahmen-wandert { to { background-position: 300% 0; } }
/* Schwebende Herz-Partikel — reines CSS, keine zusätzlichen Elemente nötig. */
.stimmen-einreichen-glanz {
position: absolute;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
radial-gradient(circle, rgba(255,154,208,.5) 2px, transparent 3px),
radial-gradient(circle, rgba(143,217,234,.45) 2px, transparent 3px),
radial-gradient(circle, rgba(255,154,208,.35) 1.5px, transparent 3px);
background-size: 190px 190px, 260px 260px, 140px 140px;
background-position: 12% 18%, 78% 62%, 44% 88%;
animation: stimmen-partikel-treiben 16s ease-in-out infinite alternate;
}
@keyframes stimmen-partikel-treiben {
from { background-position: 12% 18%, 78% 62%, 44% 88%; opacity: .55; }
to { background-position: 18% 26%, 71% 54%, 50% 79%; opacity: .95; }
}
@media (prefers-reduced-motion: reduce) {
.stimmen-einreichen-kachel::before, .stimmen-einreichen-glanz { animation: none; }
}
.stimmen-einreichen-kopf { text-align: center; margin-bottom: 1.8rem; }
/* Medaillon statt nacktem Emoji: Kreis mit Farbschein und sanftem Puls. */
.stimmen-einreichen-herz {
display: inline-flex;
align-items: center;
justify-content: center;
width: 74px; height: 74px;
border-radius: 50%;
font-size: 2.1rem;
background: radial-gradient(circle at 35% 30%, rgba(255,154,208,.28), rgba(143,217,234,.12) 70%);
border: 1.5px solid rgba(255, 154, 208, .45);
box-shadow: 0 0 26px rgba(255, 154, 208, .3), inset 0 0 22px rgba(255, 154, 208, .12);
animation: stimmen-herz-puls 3.4s ease-in-out infinite;
}
@keyframes stimmen-herz-puls {
0%, 100% { transform: scale(1); box-shadow: 0 0 22px rgba(255,154,208,.22), inset 0 0 20px rgba(255,154,208,.1); }
50% { transform: scale(1.06); box-shadow: 0 0 40px rgba(255,154,208,.45), inset 0 0 26px rgba(255,154,208,.18); }
}
@media (prefers-reduced-motion: reduce) { .stimmen-einreichen-herz { animation: none; } }
.stimmen-einreichen-kopf h2 {
margin: .9rem 0 .6rem;
background: linear-gradient(100deg, #ffd0e8, #ffffff 40%, #a8e4f2);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.stimmen-einreichen-kopf p { color: var(--text-muted); }
#stimmen-formular .field { margin-bottom: 1.1rem; }
/* Eingabefelder leuchten beim Tippen in der Kachel-Farbwelt auf. */
#stimmen-formular .field input,
#stimmen-formular .field textarea {
transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
#stimmen-formular .field input:focus,
#stimmen-formular .field textarea:focus {
outline: none;
border-color: rgba(255, 154, 208, .75);
box-shadow: 0 0 0 3px rgba(255, 154, 208, .14), 0 0 22px rgba(255, 154, 208, .18);
background: rgba(255, 255, 255, .06);
}
.stimmen-erfolg { color: #baf7d6; font-size: .9rem; margin-top: 1rem; display: none; text-align: center; }
.stimmen-erfolg.zeige { display: block; }
.stimmen-fehler { color: #ff9a9a; font-size: .88rem; margin-top: 1rem; display: none; text-align: center; }
.stimmen-fehler.zeige { display: block; }
/* Freigegebene Stimmen (20.08.2026, 2. Runde: "und auch die die danach
kommen wenn ich sie eingebe die sollen viel geiler sein"): echte
Präsentationskarten statt schlichter Kästen — Farbschein-Bloom in der
Ecke, großes Anführungszeichen als Wasserzeichen, farbige Akzentlinie
oben, Avatar-Medaillon mit dem Anfangsbuchstaben, TikTok-Handle als
eigener Chip. Beim Überfahren hebt sich die Karte leicht an. */
.stimmen-karte {
position: relative;
isolation: isolate;
overflow: hidden;
display: flex;
flex-direction: column;
padding: 2rem 1.8rem 1.6rem;
border-radius: calc(var(--radius) - 2px);
border: 1px solid rgba(143, 217, 234, .22);
background:
radial-gradient(ellipse at 100% 0%, rgba(255, 154, 208, .1), transparent 55%),
linear-gradient(180deg, rgba(24, 34, 51, .9), rgba(15, 21, 33, .95));
box-shadow: 0 16px 40px rgba(0, 0, 0, .32);
transition: transform .25s ease, border-color .25s ease, box-shadow .25s ease;
}
.stimmen-karte:hover {
transform: translateY(-4px);
border-color: rgba(255, 154, 208, .5);
box-shadow: 0 22px 52px rgba(0, 0, 0, .42), 0 0 30px rgba(255, 154, 208, .14);
}
/* Farbige Akzentlinie oben — greift die Farbwelt der Einreich-Kachel auf. */
.stimmen-karte::after {
content: "";
position: absolute;
top: 0; left: 0; right: 0;
height: 2.5px;
background: linear-gradient(90deg, rgba(255,154,208,.9), rgba(143,217,234,.9));
}
/* Großes Anführungszeichen als dezentes Wasserzeichen im Hintergrund. */
.stimmen-karte::before {
content: "„";
position: absolute;
top: -.9rem; right: .6rem;
z-index: -1;
font-size: 8rem;
font-family: Georgia, serif;
color: rgba(143, 217, 234, .09);
line-height: 1;
pointer-events: none;
}
.stimmen-karte-text {
position: relative;
z-index: 1;
flex: 1;
margin: 0 0 1.3rem;
line-height: 1.75;
font-size: 1.02rem;
color: var(--text);
}
.stimmen-karte-fuss {
display: flex;
align-items: center;
gap: .7rem;
padding-top: 1rem;
border-top: 1px solid rgba(255, 255, 255, .07);
}
/* Avatar-Medaillon mit dem Anfangsbuchstaben (wird in stimmen.js gefüllt). */
.stimmen-karte-avatar {
display: flex;
align-items: center;
justify-content: center;
width: 40px; height: 40px;
flex-shrink: 0;
border-radius: 50%;
font-weight: 800;
font-size: 1rem;
color: #0d1420;
background: linear-gradient(135deg, #ffd0e8, #a8e4f2);
box-shadow: 0 0 16px rgba(255, 154, 208, .3);
}
/* Gewähltes Profilbild statt Anfangsbuchstabe (21.08.2026). Erbt Größe und
runde Form von .stimmen-karte-avatar oben, ersetzt nur Füllung/Farbe. */
.stimmen-karte-avatar-bild {
padding: 0;
overflow: hidden;
background: rgba(255, 255, 255, .05);
box-shadow: 0 0 14px rgba(212, 175, 55, .25);
}
.stimmen-karte-avatar-bild img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* ---------- Profilbild-Auswahl im Einreichen-Formular (21.08.2026) ----------
Nutzer-Wunsch: "paar geile bilder zum aussuchen ... das soll denen auch
als möglichkeit gegeben sein". Kachelraster, das sich der Breite anpasst;
die getroffene Wahl bekommt einen goldenen Ring statt nur einer leichten
Aufhellung — sonst ist auf dunklem Grund kaum erkennbar, was gewählt ist. */
.stimmen-avatar-titel {
display: block;
font-size: .82rem; font-weight: 700; letter-spacing: .04em;
text-transform: uppercase; color: var(--text-muted);
margin-bottom: .25rem;
}
.stimmen-avatar-hinweis { margin: 0 0 .7rem; }
.stimmen-avatar-wahl {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
gap: .6rem;
}
.stimmen-avatar-kachel {
position: relative;
aspect-ratio: 1;
padding: 0;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
background: rgba(255, 255, 255, .04);
border: 2px solid rgba(255, 255, 255, .12);
transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.stimmen-avatar-kachel img { width: 100%; height: 100%; object-fit: cover; display: block; }
.stimmen-avatar-keins {
display: flex; align-items: center; justify-content: center;
width: 100%; height: 100%;
font-size: 1.15rem; color: var(--text-muted);
}
.stimmen-avatar-kachel:hover { transform: translateY(-2px); border-color: rgba(255, 233, 168, .6); }
.stimmen-avatar-kachel.aktiv {
border-color: #ffe9a8;
box-shadow: 0 0 0 2px rgba(212, 175, 55, .45), 0 0 18px rgba(212, 175, 55, .4);
}
.stimmen-avatar-kachel:focus-visible { outline: 2px solid #ffe9a8; outline-offset: 3px; }
/* "Eigenes Bild"-Kachel (21.08.2026): gestrichelter Rand, damit sofort
erkennbar ist, dass hier noch nichts drin ist und etwas hinzugefügt
werden kann -- im Unterschied zu den fertigen Auswahlbildern daneben.
Sobald ein Bild hochgeladen wurde, ersetzt das
das Plus-Zeichen
und die Kachel sieht aus wie die anderen. */
.stimmen-avatar-eigenes { border-style: dashed; border-color: rgba(255, 233, 168, .45); }
.stimmen-avatar-eigenes:has(img) { border-style: solid; }
.stimmen-avatar-plus {
display: flex; align-items: center; justify-content: center;
width: 100%; height: 100%;
font-size: 1.3rem; line-height: 1; color: #ffe9a8;
}
/* Während des Hochladens: kurz gedimmt, damit klar ist, dass etwas läuft. */
.stimmen-avatar-eigenes.laedt { opacity: .5; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
.stimmen-avatar-kachel { transition: none; }
.stimmen-avatar-kachel:hover { transform: none; }
}
.stimmen-karte-namen { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.stimmen-karte-name { font-weight: 700; color: var(--text); font-size: .95rem; }
.stimmen-karte-tiktok {
align-self: flex-start;
font-size: .76rem;
font-weight: 600;
color: #a8e4f2;
padding: .1rem .5rem;
border-radius: 999px;
background: rgba(143, 217, 234, .12);
border: 1px solid rgba(143, 217, 234, .28);
}
/* =====================================================================
MATERIAL — dieselbe Sprache wie im Workspace (03.09.2026)
Drei Regeln, für jedes Bauteil dieselben:
1. Licht von oben -- eine helle Kante an der Oberkante
2. Tiefe nach unten -- ein Schatten, versetzt, wie bei jedem
Gegenstand, der auf etwas liegt
3. Verlauf statt Fläche -- oben eine Spur heller als unten
Und für alles Bedienbare eine vierte: Was man drückt, geht hinein.
Beim Klick kehrt sich die Wölbung um. Das ist der Unterschied
zwischen "es passiert etwas" und "ich habe etwas gedrückt".
Gedeckt gehalten -- diese Bauteile stehen zu Dutzenden auf einer
Seite, und was einzeln beeindruckt, blendet im Dutzend.
===================================================================== */
.btn, .btn-primary, .btn-outline {
position: relative;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .12),
inset 0 -2px 6px -4px rgba(0, 0, 0, .65),
0 4px 10px -6px rgba(0, 0, 0, .8);
transition: transform .15s ease, box-shadow .15s ease, background .15s ease,
border-color .15s ease;
}
/* Die geschliffene Kante: in der Mitte am hellsten, nach aussen aus-
laufend. Eine durchgehend gleich helle Linie ist ein Strich, kein
Licht. */
.btn::after, .btn-primary::after, .btn-outline::after {
content: "";
position: absolute; top: 1px; left: 14%; right: 14%; height: 1px;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .45), transparent);
pointer-events: none; opacity: .8;
border-radius: 1px;
}
.btn:hover, .btn-primary:hover, .btn-outline:hover {
transform: translateY(-1px);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .18),
inset 0 -2px 6px -4px rgba(0, 0, 0, .65),
0 10px 22px -10px color-mix(in srgb, var(--accent) 75%, transparent);
}
.btn:active, .btn-primary:active, .btn-outline:active {
transform: translateY(1px);
box-shadow:
inset 0 2px 6px -2px rgba(0, 0, 0, .7),
inset 0 -1px 0 rgba(255, 255, 255, .08);
}
/* Marken und Abzeichen: kleine Plaketten, keine Aufkleber. */
.tag, .badge {
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .12),
0 2px 5px -4px rgba(0, 0, 0, .9);
}
/* Überschriften bekommen eine Kante gegen den Hintergrund. Der Schatten
ändert die FARBE nicht -- die Kontrastprüfung misst weiter dasselbe --,
legt den Text aber auf die Seite, statt ihn hineinzumischen. */
h1, h2, h3 { text-shadow: 0 1px 2px rgba(0, 0, 0, .45); }
@media (prefers-reduced-motion: reduce) {
.btn, .btn-primary, .btn-outline,
.btn:hover, .btn:active { transition: none; transform: none; }
}
@media (forced-colors: active) {
.btn, .btn-primary, .btn-outline, .tag, .badge { box-shadow: none; }
.btn::after, .btn-primary::after, .btn-outline::after { display: none; }
h1, h2, h3 { text-shadow: none; }
}
/* Eine Kachel, die noch nichts dahinter hat (03.09.2026).
Sie sieht aus wie die anderen, verspricht aber nichts: kein Zeiger,
kein Anheben beim Ueberfahren. Der Unterschied ist klein und genau
deshalb richtig -- man merkt ihn erst, wenn man darauf zeigt, und
dann weiss man Bescheid, ohne dass es jemand hinschreiben muss. */
.karte--bald { cursor: default; }
.karte--bald:hover { transform: none; border-color: var(--border); box-shadow: var(--shadow); }