Gefunden beim Nachgehen des letzten roten Pruefstand-Eintrags. Eine
Kette aus drei Funden, und der dritte wiegt am schwersten.
=====================================================================
1. EINE ENDLOSE BEWEGUNG AUF ETWAS UNSICHTBAREM
=====================================================================
`pruef-browser` scheiterte in WebKit daran, dass der Anmeldeknopf nie
ruhig wurde. Eine der zwei laufenden Bewegungen war:
.knopf__laden { opacity: 0; animation: dreh .8s linear infinite; }
Dieselbe Suche, ueber ALLE 42 Stilvorlagen beider Haeuser und der
Website, fand einen zweiten: An jedem Navigationspunkt der
oeffentlichen Seite lief eine elf Sekunden lange Aurora -- unsichtbar
bis zum Ueberfahren, auf jeder Seite, fuer immer.
Beides faellt niemandem auf: Nichts stuerzt ab, nichts sieht falsch
aus. Es kostet nur Rechenzeit und Akku.
NEU: `server/pruef-bewegung.mjs` mit sechs Gegenproben -- darunter
die wichtigste, dass ein Beispiel IM KOMMENTAR nicht zaehlt (genau
diese Falle hat am 29.09. eine andere Pruefung dreimal getroffen).
Der Gesamtlauf findet sie von selbst, sie laeuft ab heute Nacht mit.
=====================================================================
2. DIE WEBSITE HATTE KEINEN STEMPLER
=====================================================================
Fuer den Workspace gibt es `workspace-stempel.mjs` seit Langem. Die
oeffentliche Website hatte nichts -- dort stand ein VON HAND
gepflegter Stempel, und der ist gealtert wie jede von Hand gepflegte
Liste.
NEU: `tools/seiten-stempel.mjs`, 447 Verweise in 35 Seiten. Er kennt
beide Schreibweisen (mit und ohne fuehrenden Schraegstrich) UND die,
die in einem `style="…url(…)"` stehen -- zwei Hintergrundbilder auf
streamplan.html waeren sonst ein Jahr lang die alten geblieben.
Dieselbe Luecke gab es im Workspace-Stempler schon einmal, dort bei
den App-Symbolen.
=====================================================================
3. UND DESHALB KAM SEIT DEM 27.08. NICHTS MEHR AN
=====================================================================
Stempel in allen 35 Seiten: ?v=20260828e (zuletzt 27.08.)
Aenderungen an assets/ seither: 6 Commits
Der Server dazu: Cache-Control: max-age=31536000, immutable
`immutable` heisst: Der Browser fragt nicht einmal nach. Wer die
Seite einmal geladen hatte, behielt Stilvorlagen und Skripte bis zu
EINEM JAHR.
Darunter der Partnercode DOGI10 auf der gepraegten Muenze und der
komplette Sprachumbau der Oberflaeche. Sie lagen auf dem Server, sie
waren ausgeliefert, und niemand sah sie.
Dieselbe Sorte Fehler wie am 09.09. im Workspace („eine Aenderung ist
nicht gemacht" -- sie war es, nur unsichtbar) und dieselbe wie bei
VanVans Shop: Eine Aenderung ist erst fertig, wenn sie auf der
Adresse ankommt, die der Nutzer benutzt.
`pruef-zwischenspeicher` fragt jetzt nicht mehr nur, OB ein Stempel
dasteht, sondern ob er NEUER ist als die Dateien, auf die er zeigt.
Gegenprobe gemacht: eine Datei zwei Stunden in die Zukunft gesetzt ->
rot, Zeit zurueck -> gruen. Eine Stunde Nachsicht, damit die Wache
nicht bei zwei Minuten anschlaegt und weggeklickt wird.
DEPLOY.md hat jetzt einen Schritt 0 mit beiden Stemplern und dem
Grund dafuer -- der Befund steht im Wortlaut daneben.
Gemessen: pruef-bewegung 9/0, pruef-zwischenspeicher 30/0,
pruef-browser 17/0, pruef-css-klassen 37/0, pruef-struktur 44/0,
pruef-workspace-umzug 3/0.
Co-Authored-By: Claude Opus 5 <[email protected]>
4757 lines
186 KiB
CSS
4757 lines
186 KiB
CSS
/* =====================================================================
|
||
DOGFATHER UNIVERSE — main.css
|
||
Gemeinsames Design-System für alle drei Welten (Dogfather / HasiDog /
|
||
Manager Dogfather). Farben kommen aus den theme-*.css Dateien über
|
||
CSS-Variablen — dieses File ist bewusst themen-neutral.
|
||
===================================================================== */
|
||
|
||
/* ---------- Reset ---------- */
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
/* overflow-x:hidden gehört auf BEIDE Elemente: <html> ist im Standards-Modus
|
||
das tatsächliche Scroll-Element des Dokuments, nicht <body> — nur auf body
|
||
gesetzt, ließ sich die Seite auf schmalen Bildschirmen (Handy-Breiten wie
|
||
320-414px) trotzdem ca. 50px horizontal wegwischen und zeigte Leerraum
|
||
hinter den absichtlich überbreiten Deko-Elementen (Nebel/Aurora-Hintergrund).
|
||
Tagescheck-Fund vom 02.08.2026, siehe DogFather Website.md. */
|
||
html { overflow-x: hidden; }
|
||
html, body { margin: 0; padding: 0; }
|
||
img, svg { max-width: 100%; display: block; }
|
||
a { color: inherit; text-decoration: none; }
|
||
button { font: inherit; }
|
||
ul { list-style: none; margin: 0; padding: 0; }
|
||
|
||
/* ---------- Fallback-Theme (Dogfather) — wird von theme-*.css überschrieben ---------- */
|
||
:root {
|
||
--bg: #0b0d10;
|
||
--bg-alt: #12151a;
|
||
--card-bg: #171b21;
|
||
--text: #f3f5f7;
|
||
--text-muted: #9aa4b2;
|
||
--border: #262c35;
|
||
--accent: #8fd9ea; /* Babyblau */
|
||
--accent-2: #8b5cf6; /* Lila */
|
||
--accent-contrast: #0b0d10;
|
||
--radius: 14px;
|
||
--font-head: "Poppins", "Segoe UI", system-ui, sans-serif;
|
||
--font-body: "Inter", "Segoe UI", system-ui, sans-serif;
|
||
--shadow: 0 10px 30px rgba(0,0,0,.35);
|
||
}
|
||
|
||
/* ---------------------------------------------------------------------
|
||
Sprung zum Inhalt (Tastaturbedienung, WCAG 2.4.1)
|
||
|
||
Der Link ist das erste Element der Seite und für Mausnutzer unsichtbar.
|
||
Er darf aber NICHT mit display:none oder visibility:hidden versteckt
|
||
werden -- damit wäre er auch für die Tastatur verschwunden, und genau
|
||
die soll ihn ja erreichen. Deshalb wird er aus dem Bild geschoben und
|
||
kehrt zurück, sobald er den Fokus bekommt.
|
||
|
||
:focus statt :focus-visible -- ein Sprunglink wird ausschließlich per
|
||
Tastatur angesteuert, und ältere Browser kennen :focus-visible nicht;
|
||
die würden ihn dann nie zeigen.
|
||
|
||
Farbe bewusst der Akzentton auf dunklem Text (nicht umgekehrt): Das
|
||
ergibt rund 12:1 Kontrast, ohne dass ein greller Kasten aufblitzt.
|
||
--------------------------------------------------------------------- */
|
||
.site-skip {
|
||
position: absolute;
|
||
left: -9999px;
|
||
top: 0;
|
||
z-index: 3000;
|
||
background: var(--accent);
|
||
color: var(--accent-contrast);
|
||
font-family: var(--font-head);
|
||
font-weight: 700;
|
||
text-decoration: none;
|
||
padding: .85rem 1.4rem;
|
||
border-radius: 0 0 var(--radius) 0;
|
||
box-shadow: var(--shadow);
|
||
}
|
||
.site-skip:focus { left: 0; }
|
||
|
||
/* Nur für Bildschirmleser: sichtbar für die Vorlesesoftware, unsichtbar
|
||
für das Auge. NICHT display:none oder visibility:hidden -- das würde
|
||
auch den Bildschirmleser aussperren. Wird verwendet, um auf Seiten mit
|
||
optisch gestalteten Kachelgruppen die Überschriftenordnung zu vervoll-
|
||
ständigen (eine Gruppenüberschrift zwischen h1 und den Kachel-h3), ohne
|
||
das Design zu verändern. */
|
||
.sr-only {
|
||
position: absolute;
|
||
width: 1px; height: 1px;
|
||
padding: 0; margin: -1px;
|
||
overflow: hidden;
|
||
clip: rect(0, 0, 0, 0);
|
||
white-space: nowrap;
|
||
border: 0;
|
||
}
|
||
|
||
/* Das Sprungziel bekommt tabindex="-1" (siehe main.js). Ohne diese Regel
|
||
malt der Browser dann einen Fokusrahmen um den halben Bildschirm. */
|
||
main[tabindex="-1"]:focus { outline: none; }
|
||
|
||
body {
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
font-family: var(--font-body);
|
||
line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
min-height: 100vh;
|
||
position: relative;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
h1, h2, h3, h4 {
|
||
font-family: var(--font-head);
|
||
line-height: 1.2;
|
||
margin: 0 0 .5em;
|
||
font-weight: 700;
|
||
}
|
||
h1 { font-size: clamp(2.2rem, 5.4vw, 3.5rem); }
|
||
h2 { font-size: clamp(1.95rem, 4.3vw, 2.95rem); }
|
||
h3 { font-size: 1.62rem; }
|
||
p { margin: 0 0 1em; color: var(--text-muted); font-size: 1.32rem; line-height: 1.85; }
|
||
.lead { font-size: 1.5rem; color: var(--text); }
|
||
.quote { font-size: 1.4rem; }
|
||
|
||
.container {
|
||
width: min(1180px, 92vw);
|
||
margin: 0 auto;
|
||
}
|
||
|
||
section { padding: clamp(3rem, 6vw, 5.5rem) 0; }
|
||
.section-tight { padding: clamp(1.5rem, 3vw, 2.5rem) 0; }
|
||
|
||
.eyebrow {
|
||
display: inline-block;
|
||
font-size: .78rem;
|
||
letter-spacing: .14em;
|
||
text-transform: uppercase;
|
||
color: var(--accent);
|
||
font-weight: 700;
|
||
margin-bottom: .8em;
|
||
}
|
||
|
||
/* ---------- Nebel/Partikel Hintergrund ---------- */
|
||
.fog-layer {
|
||
position: fixed;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
overflow: hidden;
|
||
}
|
||
.fog-layer span {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, var(--accent) 0%, transparent 70%);
|
||
opacity: .08;
|
||
filter: blur(4px);
|
||
animation: drift 26s linear infinite;
|
||
}
|
||
@keyframes drift {
|
||
0% { transform: translateY(0) translateX(0); }
|
||
50% { transform: translateY(-40px) translateX(20px); }
|
||
100% { transform: translateY(0) translateX(0); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.fog-layer span { animation: none; }
|
||
}
|
||
|
||
/* ---------- Header / Navigation ---------- */
|
||
header.site-header {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 50;
|
||
/* Kräftig deckend statt Weichzeichnen durch das Bild dahinter — die
|
||
Kombination aus backdrop-filter + fest positionierter Kopfzeile führte
|
||
bei Chromium-Rendern zu Darstellungsfehlern (Logo/Menü teils unsichtbar).
|
||
Deckende Farbe braucht keinen Weichzeichner und ist zusätzlich schneller. */
|
||
background: var(--bg);
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.nav-bar {
|
||
/* Eigene, etwas breitere Kappung als .container (1180px) — die Nav
|
||
braucht durch größere Schrift + mehr Abstand + Polarlicht-Padding
|
||
spürbar mehr Platz, ohne dass der restliche Seiteninhalt breiter
|
||
werden soll.
|
||
Bugfix 04.08.2026: 1400px -> 1440px angehoben (siehe damalige Analyse).
|
||
Bugfix 20.08.2026: reichte seither wieder nicht mehr — die Nav braucht
|
||
inzwischen (Nav-Punkt "DogiCrew" + "BALD"-Badge dazugekommen) real ca.
|
||
1491px, der Deckel blieb bei 1440px. 1440px -> 1560px, zusammen mit der
|
||
auf 1650px angehobenen Hamburger-Schwelle weiter unten (siehe Kommentar
|
||
dort) — diesmal mit echtem Sicherheitsabstand statt wieder nur knapp
|
||
genug für den aktuellen Stand. */
|
||
width: min(1560px, 94vw);
|
||
margin: 0 auto;
|
||
display: flex;
|
||
align-items: center;
|
||
/* Bewusst NICHT space-between: sonst landet der ganze freie Platz auf
|
||
großen Bildschirmen als große Lücke zwischen Logo und "Start", und
|
||
das Menü wirkt an die rechte Kante gepresst. Stattdessen rückt das
|
||
Menü mit festem Abstand direkt ans Logo heran, der übrige Platz
|
||
bleibt rechts nach dem Bewerben-Knopf. */
|
||
justify-content: flex-start;
|
||
gap: 2rem;
|
||
padding: .9rem 0;
|
||
flex-wrap: nowrap;
|
||
}
|
||
/* Logo und Menü-Knopf dürfen NIE zusammengequetscht werden — auch nicht,
|
||
wenn .nav-links (das ausgeklappte Menü) aus irgendeinem Grund kurzzeitig
|
||
noch normal mitgerechnet wird, bevor die Klappt-Logik greift. */
|
||
.brand, .nav-toggle { flex-shrink: 0; }
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .65rem;
|
||
font-family: var(--font-head);
|
||
font-weight: 800;
|
||
font-size: 1.32rem;
|
||
letter-spacing: .02em;
|
||
}
|
||
.brand .heart { color: var(--accent); }
|
||
.brand-logo {
|
||
width: 42px;
|
||
height: 42px;
|
||
border-radius: 9px;
|
||
object-fit: cover;
|
||
flex-shrink: 0;
|
||
}
|
||
.brand small {
|
||
display: block;
|
||
font-size: .7rem;
|
||
font-weight: 500;
|
||
letter-spacing: .1em;
|
||
color: var(--text-muted);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.nav-links {
|
||
display: flex;
|
||
align-items: center;
|
||
/* Seit die Kategorien eigene farbige Pillen (Polarlicht-Hintergrund)
|
||
haben, trennt schon die Farbfläche selbst optisch — ein kleinerer
|
||
Lücken-Abstand wirkt dadurch aufgeräumter/professioneller als der
|
||
vorherige große Abstand. */
|
||
gap: .7rem;
|
||
}
|
||
.nav-group { position: relative; }
|
||
.nav-group > button {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
background: none;
|
||
border: none;
|
||
border-radius: 999px;
|
||
color: var(--text);
|
||
font-weight: 600;
|
||
font-size: 1.14rem;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .3rem;
|
||
padding: .5rem .55rem;
|
||
transition: color .2s ease;
|
||
}
|
||
.nav-group > button:hover, .nav-group.open > button { color: var(--accent); }
|
||
.nav-flat {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
border-radius: 999px;
|
||
font-weight: 600;
|
||
font-size: 1.14rem;
|
||
padding: .5rem .55rem;
|
||
transition: color .2s ease;
|
||
}
|
||
.nav-flat:hover, .nav-flat.active { color: var(--accent); }
|
||
|
||
/* Kein Button-/Pillen-Look im Ruhezustand mehr (0% Deckkraft) — die
|
||
Kategorien sehen bei Dogi so aus wie normale Textlinks. Der Farbschein
|
||
in den echten Farben der jeweiligen Welt (siehe theme-dogfather/
|
||
-hasidog/-spicymedia.css) taucht NUR bei Hover/offenem Dropdown ganz
|
||
dezent auf, als kleiner Hinweis statt als ständige Box. */
|
||
.nav-group > button::before, .nav-flat::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -70% -35%;
|
||
z-index: -1;
|
||
background:
|
||
radial-gradient(circle at 28% 30%, var(--brand-1, transparent), transparent 62%),
|
||
radial-gradient(circle at 74% 72%, var(--brand-2, transparent), transparent 62%);
|
||
filter: blur(9px) saturate(1.25);
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity .3s ease;
|
||
}
|
||
/* DIE BEWEGUNG GEHOERT DORTHIN, WO DAS DING SICHTBAR WIRD
|
||
(30.09.2026).
|
||
|
||
Sie stand im Block darueber -- also lief sie ab dem Laden der
|
||
Seite, an JEDEM Navigationspunkt, endlos, und zu sehen war sie
|
||
erst beim Ueberfahren. Elf Sekunden Farbverlauf mal sechs
|
||
Navigationspunkte, auf jeder Seite der Website, fuer nichts.
|
||
|
||
Gefunden mit `pruef-bewegung` -- derselben Suche, die am selben
|
||
Tag den unsichtbaren Ladekreisel auf der Zugangswand gefunden hat.
|
||
Es faellt niemandem auf: Nichts stuerzt ab, nichts sieht falsch
|
||
aus. Es kostet nur Rechenzeit und Akku. */
|
||
.nav-group:hover > button::before,
|
||
.nav-group.open > button::before,
|
||
.nav-flat:hover::before,
|
||
.nav-flat.active::before {
|
||
opacity: .32;
|
||
animation: nav-cta-aurora 11s ease-in-out infinite alternate;
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.nav-group > button::before, .nav-flat::before { animation: none; }
|
||
}
|
||
|
||
.nav-item-dogfather { --brand-1: rgba(143, 217, 234, .9); --brand-2: rgba(139, 92, 246, .85); }
|
||
.nav-item-hasidog { --brand-1: rgba(143, 217, 234, .9); --brand-2: rgba(199, 204, 209, .8); }
|
||
.nav-item-manager { --brand-1: rgba(217, 74, 92, .85); --brand-2: rgba(232, 147, 58, .8); }
|
||
.nav-item-medien { --brand-1: rgba(143, 217, 234, .7); --brand-2: rgba(217, 74, 92, .6); }
|
||
.nav-item-start { --brand-1: rgba(143, 217, 234, .85); --brand-2: rgba(139, 92, 246, .5); }
|
||
.nav-item-links { --brand-1: rgba(143, 217, 234, .85); --brand-2: rgba(212, 175, 55, .7); }
|
||
/* Aufgeklapptes Kategorie-Menü: gleiche "gläserne, dunkle Karte mit
|
||
farbigem Schein"-Machart wie beim Sprachschalter-Dropdown, aber im
|
||
Farbton DIESER Kategorie (--brand-1/--brand-2, vom umschließenden
|
||
.nav-group geerbt) statt neutral silbern — sorgt für einen klaren,
|
||
ruhigen Look statt der vorherigen schlichten grauen Box. */
|
||
.nav-dropdown {
|
||
position: absolute;
|
||
/* WICHTIG: KEIN margin-top/Lücke zum Knopf — sonst verliert die Maus
|
||
beim Runterfahren zur Box kurz den Hover auf .nav-group, und das
|
||
Menü klappt zu, bevor man einen Punkt anklicken kann (Bug gefunden
|
||
03.08.2026, durch den Caret-Abstand selbst verursacht). Box sitzt
|
||
deshalb bewusst bündig an top:100%, der Verbindungs-Pfeil unten
|
||
pokt einfach in die Knopf-Kante hinein statt in eine echte Lücke. */
|
||
top: 100%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
min-width: 230px;
|
||
background: rgba(4, 5, 8, .96);
|
||
border: 1px solid rgba(255, 255, 255, .14);
|
||
border-radius: 14px;
|
||
padding: .45rem;
|
||
box-shadow:
|
||
0 14px 34px rgba(0, 0, 0, .6),
|
||
0 0 16px var(--brand-1, rgba(220, 226, 235, .3)),
|
||
0 0 32px var(--brand-2, rgba(190, 200, 215, .15));
|
||
display: none;
|
||
flex-direction: column;
|
||
/* EIGENE Animation statt der geteilten sprach-dropdown-in: eine
|
||
@keyframes-Regel setzt "transform" als GANZES pro Frame, würde also
|
||
das zentrierende translateX(-50%) oben komplett überschreiben und
|
||
die Box nach dem Aufklappen sichtbar nach rechts verschieben (Bug
|
||
gefunden 03.08.2026 — Box wirkte "nicht mittig", war es auch nicht:
|
||
transform sprang nach der Animation auf reines translateY/scale).
|
||
Der Sprachschalter unten ist rechtsbündig (kein translateX nötig)
|
||
und behält deshalb bewusst die alte, geteilte Animation. */
|
||
animation: nav-dropdown-in .18s ease both;
|
||
}
|
||
/* Kleiner Verbindungs-Pfeil (Caret), mittig unter dem Kategorie-Knopf —
|
||
macht auch dann unmissverständlich klar, zu welcher Kategorie das
|
||
Menü gehört, wenn die Box (wegen mehr Einträgen) breiter ist als der
|
||
Knopf selbst und dadurch optisch in Nachbar-Kategorien hineinragt. */
|
||
.nav-dropdown::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: -7px;
|
||
left: 50%;
|
||
transform: translateX(-50%) rotate(45deg);
|
||
width: 14px;
|
||
height: 14px;
|
||
background: rgba(4, 5, 8, .96);
|
||
border-left: 1px solid rgba(255, 255, 255, .14);
|
||
border-top: 1px solid rgba(255, 255, 255, .14);
|
||
border-radius: 3px 0 0 0;
|
||
pointer-events: none;
|
||
}
|
||
.nav-group.open .nav-dropdown { display: flex; }
|
||
/* Auf echten Maus-Geräten (nicht Touch) öffnet sich das Menü schon beim
|
||
Drüberfahren, ohne extra Klick — auf Touch/Tablet bleibt es bewusst
|
||
beim Klick (dort gibt es kein echtes "Hover"). */
|
||
@media (hover: hover) and (pointer: fine) {
|
||
.nav-group:hover .nav-dropdown { display: flex; }
|
||
}
|
||
/* Bewusst KEIN Button-Look (kein gefüllter Hintergrund, keine Pille) —
|
||
nur schlichte Menü-Zeilen, die beim Hover die Farbe wechseln. Die
|
||
Kategorie-Knöpfe selbst (DogFather/HasiDog/Manager/...) behalten
|
||
weiterhin ihren Pillen-Stil, nur das aufgeklappte Untermenü nicht. */
|
||
.nav-dropdown a {
|
||
padding: .55rem .75rem;
|
||
font-size: 1.06rem;
|
||
color: var(--text-muted);
|
||
transition: color .2s ease;
|
||
}
|
||
/* translateX(-50%) MUSS in jedem Frame mit drinstehen, sonst hebt die
|
||
Animation die Zentrierung von .nav-dropdown auf (siehe Kommentar oben). */
|
||
@keyframes nav-dropdown-in {
|
||
from { opacity: 0; transform: translateX(-50%) translateY(-6px) scale(.96); }
|
||
to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
|
||
}
|
||
.nav-dropdown a:hover, .nav-dropdown a.active {
|
||
color: var(--brand-1, var(--accent));
|
||
}
|
||
|
||
/* ===================================================================
|
||
Sprachumschalter — eigenes kleines "Schmuckstück" in der Nav-Bar statt
|
||
eines schlichten Menüpunkts: eine gläserne Pille mit Polarlicht-Schein
|
||
in der jeweiligen Sprachfarbe (--sprach-glut, von main.js gesetzt),
|
||
eine glänzende, sich sacht drehende "Mini-Planet"-Kugel und ein
|
||
Dropdown im selben Look, das beim Öffnen sanft einschwebt. */
|
||
.sprach-schalter { --sprach-glut: var(--accent); }
|
||
.sprach-schalter > button {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
font-size: 1.08rem;
|
||
font-weight: 700;
|
||
align-items: center;
|
||
gap: .5rem;
|
||
padding: .45rem 1.1rem .45rem .6rem;
|
||
border-radius: 999px;
|
||
/* Rand bewusst neutral silbern (wie beim Dropdown-Kasten) statt in der
|
||
Sprachfarbe — nur die Kugel + das Glühen dahinter sind bunt, der
|
||
Rahmen selbst bleibt für alle Sprachen gleich. */
|
||
border: 1px solid rgba(210, 216, 224, .55);
|
||
background: rgba(4, 5, 8, .94);
|
||
box-shadow:
|
||
inset 0 0 0 1px rgba(255, 255, 255, .05),
|
||
0 3px 10px rgba(0, 0, 0, .5),
|
||
0 0 10px color-mix(in srgb, var(--sprach-glut) 55%, transparent),
|
||
0 0 22px color-mix(in srgb, var(--sprach-glut) 35%, transparent);
|
||
transition: transform .2s ease, box-shadow .3s ease, border-color .3s ease;
|
||
}
|
||
.sprach-schalter > button:hover,
|
||
.sprach-schalter.open > button {
|
||
transform: translateY(-1px);
|
||
border-color: rgba(235, 239, 244, .9);
|
||
box-shadow:
|
||
inset 0 0 0 1px rgba(255, 255, 255, .08),
|
||
0 6px 16px rgba(0, 0, 0, .4),
|
||
0 0 24px color-mix(in srgb, var(--sprach-glut) 60%, transparent);
|
||
}
|
||
/* Ebene: die "Landesflagge" als weiche, wandernde Aurora-Wolke im
|
||
Hintergrund des Knopfs — mehrere Farbflecken statt nur eines Farbtons,
|
||
dieselbe Machart wie beim Bewerben-Knopf, nur mit den 2-3 echten
|
||
Farben DIESER Sprache (siehe SPRACHEN.farbstopps in main.js). */
|
||
.sprach-schalter > button::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -65%;
|
||
z-index: -2;
|
||
background: var(--sprach-aurora);
|
||
filter: blur(8px) saturate(1.3);
|
||
/* Bewusst nur ein dezenter Farbschein statt einer vollflächig bunten
|
||
Fläche — der Knopf selbst soll "leuchtend schwarz" wirken (Glow am
|
||
Rand + hinter der Kugel), nicht komplett eingefärbt. */
|
||
opacity: .32;
|
||
animation: sprach-aurora-drift 7s ease-in-out infinite alternate;
|
||
pointer-events: none;
|
||
}
|
||
.sprach-schalter > button:hover::before,
|
||
.sprach-schalter.open > button::before {
|
||
opacity: .48;
|
||
}
|
||
@keyframes sprach-aurora-drift {
|
||
from { transform: translate(-3%, -2%) rotate(0deg) scale(1); }
|
||
to { transform: translate(3%, 3%) rotate(8deg) scale(1.12); }
|
||
}
|
||
/* Ebene: ein schmales Lichtband, das einmal quer durch den Knopf läuft —
|
||
dieselbe Machart wie beim Bewerben-Knopf, nur in der Sprachfarbe. */
|
||
.sprach-schalter > button::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: -1;
|
||
background: linear-gradient(115deg, transparent 35%, color-mix(in srgb, var(--sprach-glut) 55%, white 25%) 49%, transparent 63%);
|
||
background-size: 240% 100%;
|
||
mix-blend-mode: overlay;
|
||
opacity: .8;
|
||
animation: sprach-schimmer 5s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
@keyframes sprach-schimmer {
|
||
0% { background-position: 160% 0; }
|
||
100% { background-position: -60% 0; }
|
||
}
|
||
/* Bugfix 20.08.2026 (Nutzer-Report per Screenshot-Vergleich: Kategorie-
|
||
Menüs wie "Medien" sind mittig unter dem Knopf, der Sprachschalter aber
|
||
rechtsbündig) — war bewusst rechtsbündig, seit der Sprachschalter aber
|
||
nicht mehr ganz am rechten Rand sitzt (DogiCrew-/Bewerben-Knopf daneben),
|
||
ist genug Platz für dieselbe zentrierte Ausrichtung wie überall sonst.
|
||
left/transform hier deshalb NICHT mehr überschrieben (erbt jetzt
|
||
left:50%/translateX(-50%) von der allgemeinen .nav-dropdown-Regel,
|
||
genau wie der bereits zentrierte Verbindungs-Pfeil (::before) es die
|
||
ganze Zeit schon war — vorher zeigte der Pfeil mittig, während die Box
|
||
selbst daneben saß). Eigene Animation bleibt bestehen (siehe Kommentar
|
||
der allgemeinen .nav-dropdown-Animation), jetzt aber ebenfalls mit
|
||
translateX(-50%) in jedem Frame, sonst würde sie die Zentrierung wieder
|
||
aufheben. */
|
||
.sprach-schalter .nav-dropdown {
|
||
min-width: 190px;
|
||
padding: .4rem;
|
||
border-radius: 14px;
|
||
border: 1px solid rgba(210, 216, 224, .55);
|
||
background: rgba(4, 5, 8, .96);
|
||
box-shadow:
|
||
0 14px 34px rgba(0, 0, 0, .6),
|
||
0 0 16px rgba(220, 226, 235, .35),
|
||
0 0 34px rgba(190, 200, 215, .18);
|
||
animation: sprach-dropdown-in .18s ease both, sprach-silber-puls 3.6s ease-in-out infinite;
|
||
}
|
||
@keyframes sprach-dropdown-in {
|
||
from { opacity: 0; transform: translateX(-50%) translateY(-6px) scale(.96); }
|
||
to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
|
||
}
|
||
/* Silberner Polarlicht-Schein um den Dropdown-Rand — bewusst neutral
|
||
silber statt farbig, damit sich der schwarze Kasten von der bunten
|
||
Kugel/Schrift jeder Sprache klar abhebt statt zu verschwimmen. */
|
||
@keyframes sprach-silber-puls {
|
||
0%, 100% {
|
||
border-color: rgba(210, 216, 224, .5);
|
||
box-shadow: 0 14px 34px rgba(0, 0, 0, .6), 0 0 14px rgba(220, 226, 235, .3), 0 0 30px rgba(190, 200, 215, .15);
|
||
}
|
||
50% {
|
||
border-color: rgba(235, 239, 244, .9);
|
||
box-shadow: 0 14px 34px rgba(0, 0, 0, .6), 0 0 22px rgba(230, 235, 242, .55), 0 0 46px rgba(200, 210, 224, .3);
|
||
}
|
||
}
|
||
.sprach-schalter .nav-dropdown a {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .65rem;
|
||
padding: .6rem .7rem;
|
||
border-radius: 10px;
|
||
border-left: 3px solid transparent;
|
||
transition: background .2s ease, border-color .2s ease, transform .15s ease;
|
||
}
|
||
.sprach-schalter .nav-dropdown a:hover,
|
||
.sprach-schalter .nav-dropdown a.active {
|
||
background: rgba(255, 255, 255, .09);
|
||
border-left-color: var(--sprach-glut);
|
||
transform: translateX(2px);
|
||
}
|
||
/* Kleine "Mini-Planet"-Kugel statt eines Flaggen-Emojis — Windows stellt
|
||
Flaggen-Emojis grundsätzlich nicht als Bild dar (siehe SPRACHEN oben in
|
||
main.js). Ein außermittiges Glanzlicht + langsame Drehung lassen sie
|
||
wie eine echte, beleuchtete Kugel wirken statt einer flachen Fläche. */
|
||
/* Kugel-Grundfarbe: conic-gradient aus den 2-3 echten Landesfarben
|
||
dieser Sprache (--sprach-stopps, siehe SPRACHEN.farbstopps in
|
||
main.js) — wirkt wie eine kleine, marmoriert eingefärbte Kugel statt
|
||
nur einem Farbton, plus Eigendrehung, damit die Farbmischung sichtbar
|
||
"lebt". Glanzlicht kommt separat über ::before oben drauf. */
|
||
.sprach-kugel {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
vertical-align: -4px;
|
||
overflow: hidden;
|
||
background: conic-gradient(from 0deg, var(--sprach-stopps));
|
||
box-shadow:
|
||
inset -3px -3px 5px rgba(0, 0, 0, .5),
|
||
0 0 8px 2px color-mix(in srgb, var(--sprach-glut) 75%, transparent),
|
||
0 0 20px 4px color-mix(in srgb, var(--sprach-glut) 45%, transparent);
|
||
flex-shrink: 0;
|
||
animation: sprach-glut-puls 3.2s ease-in-out infinite, sprach-kugel-dreh 7s linear infinite;
|
||
}
|
||
.sprach-kugel::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle at 32% 26%, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, .35) 16%, transparent 55%);
|
||
mix-blend-mode: overlay;
|
||
}
|
||
.sprach-schalter .nav-dropdown a .sprach-kugel { width: 16px; height: 16px; }
|
||
/* Die Sprachfarbe zieht sich auch über die Schrift — kräftiger,
|
||
leuchtender Text statt neutralem Weiß, plus ein sanft pulsierender
|
||
Schein (dieselbe "Polarlicht"-Idee wie beim Bewerben-Knopf/den
|
||
Foto-Rahmen, nur in der jeweiligen Sprachfarbe). */
|
||
.sprach-schalter > button,
|
||
.sprach-schalter .nav-dropdown a {
|
||
color: var(--sprach-glut, var(--text));
|
||
text-shadow:
|
||
0 0 6px color-mix(in srgb, var(--sprach-glut, transparent) 70%, transparent),
|
||
0 0 14px color-mix(in srgb, var(--sprach-glut, transparent) 45%, transparent);
|
||
}
|
||
.sprach-kurz { animation: sprach-glut-puls 3.2s ease-in-out infinite; display: inline-block; }
|
||
@keyframes sprach-glut-puls {
|
||
0%, 100% { filter: brightness(1) saturate(1); }
|
||
50% { filter: brightness(1.3) saturate(1.35); }
|
||
}
|
||
@keyframes sprach-kugel-dreh {
|
||
from { transform: rotate(0deg); }
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.sprach-kugel, .sprach-kurz, .sprach-schalter > button::before, .sprach-schalter > button::after, .sprach-schalter .nav-dropdown { animation: none; }
|
||
}
|
||
|
||
/* "Bewerben" ist der Treffpunkt beider Welten (Team Dogi + Spicy Media) —
|
||
deshalb bewusst FEST babyblau + rot, unabhängig vom Theme der gerade
|
||
offenen Seite. Statt einer einfachen 50/50-Teilung ein echtes
|
||
Polarlicht: mehrere weiche, wandernde Farbwolken (blau/lila/rot) plus
|
||
ein durchlaufender Lichtschimmer — soll wirken wie Licht und Nebel,
|
||
nicht wie zwei flache Farbflächen. */
|
||
.nav-cta {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
white-space: nowrap;
|
||
padding: .6rem 1.35rem;
|
||
border-radius: 999px;
|
||
color: #fff;
|
||
font-weight: 700;
|
||
font-size: .95rem;
|
||
background: #0b0e14;
|
||
border: 1px solid rgba(255, 255, 255, .16);
|
||
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
|
||
box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
|
||
}
|
||
.nav-cta span {
|
||
position: relative;
|
||
z-index: 2;
|
||
text-shadow: 0 1px 3px rgba(0, 0, 0, .6), 0 0 14px rgba(0, 0, 0, .35);
|
||
}
|
||
/* Ebene 1: die wandernden Polarlicht-Wolken selbst */
|
||
.nav-cta::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -60%;
|
||
z-index: 0;
|
||
background:
|
||
radial-gradient(circle at 18% 30%, rgba(143, 217, 234, .95), transparent 55%),
|
||
radial-gradient(circle at 45% 75%, rgba(139, 92, 246, .85), transparent 58%),
|
||
radial-gradient(circle at 82% 32%, rgba(217, 74, 92, .95), transparent 55%),
|
||
radial-gradient(circle at 62% 82%, rgba(232, 147, 58, .55), transparent 55%);
|
||
filter: blur(9px) saturate(1.35);
|
||
animation: nav-cta-aurora 9s ease-in-out infinite alternate;
|
||
}
|
||
/* Ebene 2: ein feiner Lichtschimmer, der einmal quer durchläuft */
|
||
.nav-cta::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
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;
|
||
}
|
||
@keyframes nav-cta-aurora {
|
||
from { transform: translate(-3%, -2%) rotate(0deg) scale(1); }
|
||
to { transform: translate(3%, 3%) rotate(6deg) scale(1.08); }
|
||
}
|
||
@keyframes nav-cta-shimmer {
|
||
from { background-position: 130% 0; }
|
||
to { background-position: -30% 0; }
|
||
}
|
||
.nav-cta:hover {
|
||
transform: translateY(-1px);
|
||
border-color: rgba(255, 255, 255, .32);
|
||
box-shadow: 0 10px 26px rgba(0, 0, 0, .45),
|
||
0 0 22px rgba(143, 217, 234, .3),
|
||
0 0 22px rgba(217, 74, 92, .28);
|
||
}
|
||
/* Abo-Button (Supporter-Abo) — gleicher Polarlicht-Mechanismus wie
|
||
.nav-cta, aber in Babyblau/Lila (VIP-Anmutung) statt der allgemeinen
|
||
Regenbogen-Aurora.
|
||
Bugfix 04.08.2026: war Gold/Lila (rgba(212,175,55,...)) — dieser Knopf
|
||
erscheint in der Navigationsleiste auf JEDER Seite (auch auf
|
||
verwaltung.html, siehe Screenshot-Beschwerde), wurde von der 4. Runde
|
||
"überall wo gelb ist, Babyblau benutzen" aber NICHT erfasst, weil er in
|
||
main.css/main.js liegt statt in verwaltung.html selbst. Jetzt
|
||
nachgezogen: Gold -> Babyblau (rgba(143,217,234,...), derselbe Farbwert
|
||
wie beim allgemeinen .nav-cta-Polarlicht oben), Lila unverändert. Der
|
||
separate, deutlich größere Gold-VIP-Look von abonnieren.html/
|
||
supporter.html/gate.html/links.html/rabattcodes.html ist davon NICHT
|
||
betroffen — das ist eine eigenständige, bislang nie angesprochene
|
||
Design-Entscheidung für den öffentlichen Supporter-Bereich. */
|
||
.nav-cta-abo::before {
|
||
background:
|
||
radial-gradient(circle at 20% 30%, rgba(143, 217, 234, .95), transparent 55%),
|
||
radial-gradient(circle at 78% 70%, rgba(139, 92, 246, .85), transparent 58%);
|
||
}
|
||
.nav-cta-abo:hover {
|
||
box-shadow: 0 10px 26px rgba(0, 0, 0, .45),
|
||
0 0 22px rgba(143, 217, 234, .35),
|
||
0 0 22px rgba(139, 92, 246, .3);
|
||
}
|
||
/* "Bald"-Badge auf dem Abo-Knopf, solange die Registrierung auf
|
||
abonnieren.html gesperrt ist (20.08.2026, siehe .btn-gold-locked weiter
|
||
unten + main.js renderAboButton/soonBadge). Sitzt als zweites Kind IN
|
||
der Pille (nicht als eigenes Nav-Element), bleibt dadurch Teil desselben
|
||
Klicks — der Knopf führt bewusst weiterhin ganz normal zu abonnieren.html,
|
||
nur die Registrierung selbst dort ist gesperrt. Bewusst neutral-silbern
|
||
(Wiederverwendung von .btn-silver-text/-spark, nur kleiner skaliert)
|
||
statt Gold, damit es nicht mit der babyblau/lila-Aurora dieser Pille
|
||
konkurriert — reine Status-Markierung, kein zweiter Marken-Akzent. */
|
||
.nav-cta-soon {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .22rem;
|
||
margin-left: .5rem;
|
||
padding: .15rem .5rem;
|
||
border-radius: 999px;
|
||
font-size: .64rem;
|
||
font-weight: 800;
|
||
letter-spacing: .04em;
|
||
text-transform: uppercase;
|
||
background: rgba(255, 255, 255, .07);
|
||
border: 1px solid rgba(255, 255, 255, .3);
|
||
box-shadow: 0 0 10px rgba(230, 235, 242, .3);
|
||
flex-shrink: 0;
|
||
}
|
||
.nav-cta-soon .btn-silver-spark { font-size: .85em; }
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.nav-cta::before, .nav-cta::after { animation: none; }
|
||
}
|
||
|
||
/* TikTok-Button "Glitch/Duotone" — eigener, klar erkennbarer Stil (nicht
|
||
mehr nur eine eingefärbte Kopie von .nav-cta): schwarze Pille mit einem
|
||
fließenden Cyan/Pink-Rahmen (klassischer Zwei-Layer-Background-Trick,
|
||
NICHT ein rotierender Masken-Ring — der verzerrt sich auf einer
|
||
länglichen Pillenform zu einer krummen Schlaufe statt einer sauberen
|
||
Kontur), einem dezenten Innenschimmer (KEIN nach außen strahlender
|
||
Blur-Wolken-Glow mehr — der hat vorher Text/Bilder drumherum überstrahlt,
|
||
Feedback vom 03.08.2026: "geht über den Text und das Bild"), einer
|
||
rotierenden Notenkopf-Spielmarke und einem Text mit TikToks
|
||
charakteristischem Chromatic-Aberration-/Glitch-Versatz (die Cyan/Rot-
|
||
Schattenkopien, die auch im echten TikTok-Logo stecken), der alle paar
|
||
Sekunden kurz "springt". Alle Effekte bleiben INNERHALB der Pille bzw.
|
||
direkt an ihrer Kante — die Auffälligkeit kommt vom Button selbst, nicht
|
||
von seiner Ausstrahlung. Bewusst NUR für echte TikTok-Links — die
|
||
Markenfarben (Cyan #25F4EE + Pink/Rot #FE2C55) bleiben exakt gleich. */
|
||
.btn-tiktok {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .6rem;
|
||
padding: .85rem 2.2rem;
|
||
border-radius: 999px;
|
||
color: #fff;
|
||
font-weight: 800;
|
||
font-size: 1.1rem;
|
||
letter-spacing: .01em;
|
||
border: 2px solid transparent;
|
||
background:
|
||
linear-gradient(160deg, #12151b, #05070a 55%, #14171d) padding-box,
|
||
linear-gradient(90deg, #25F4EE, #FE2C55, #25F4EE) border-box;
|
||
background-size: 100% 100%, 260% 100%;
|
||
text-decoration: none;
|
||
transition: transform .25s ease, box-shadow .25s ease;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, .4),
|
||
inset 0 0 10px rgba(37, 244, 238, .12),
|
||
inset 0 0 10px rgba(254, 44, 85, .1);
|
||
animation: btn-tiktok-border-flow 5s linear infinite;
|
||
}
|
||
.btn-tiktok-note {
|
||
position: relative;
|
||
z-index: 3;
|
||
display: inline-block;
|
||
font-size: 1.05em;
|
||
filter: drop-shadow(0 0 3px rgba(37, 244, 238, .8));
|
||
animation: btn-tiktok-spin 3.6s linear infinite;
|
||
}
|
||
.btn-tiktok-text {
|
||
/* Ruhezustand ist bewusst KLAR LESBAR (nur normaler Schlagschatten) —
|
||
der Cyan/Rot-Chromatic-Versatz von TikToks Logo erscheint nur ganz
|
||
kurz als Flicker (siehe @keyframes btn-tiktok-glitch), nicht dauerhaft,
|
||
sonst verschwimmt der Text (Feedback vom 03.08.2026: "kriegt man
|
||
TikTok nichtmal richtig gelesen"). */
|
||
position: relative;
|
||
z-index: 3;
|
||
text-shadow: 0 2px 6px rgba(0, 0, 0, .6);
|
||
animation: btn-tiktok-glitch 6s ease-in-out infinite;
|
||
}
|
||
.btn-tiktok::before {
|
||
/* Sehr dezentes Farbschimmern INNEN in der Pille — sorgt für Tiefe,
|
||
bleibt aber innerhalb der Ränder (kein overflow, kein Blur-Bleed). */
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 0;
|
||
border-radius: inherit;
|
||
background:
|
||
radial-gradient(circle at 18% 20%, rgba(37, 244, 238, .3), transparent 60%),
|
||
radial-gradient(circle at 85% 80%, rgba(254, 44, 85, .28), transparent 62%);
|
||
animation: nav-cta-aurora 9s ease-in-out infinite alternate;
|
||
pointer-events: none;
|
||
}
|
||
.btn-tiktok::after {
|
||
/* Diagonaler Lichtschimmer, wandert einmal quer über die Pille */
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
border-radius: inherit;
|
||
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;
|
||
}
|
||
.btn-tiktok:hover {
|
||
transform: translateY(-1px) scale(1.02);
|
||
box-shadow: 0 6px 16px rgba(0, 0, 0, .45),
|
||
inset 0 0 14px rgba(37, 244, 238, .2),
|
||
inset 0 0 14px rgba(254, 44, 85, .16);
|
||
}
|
||
@keyframes btn-tiktok-border-flow {
|
||
to { background-position: 0 0, -260% 0; }
|
||
}
|
||
@keyframes btn-tiktok-spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
@keyframes btn-tiktok-glitch {
|
||
/* 97% der Zeit klar lesbarer Text — der Chromatic-Versatz blitzt nur für
|
||
einen Wimpernschlag (~150ms von 6s) auf, statt dauerhaft zu "verwaschen". */
|
||
0%, 96%, 100% {
|
||
text-shadow: 0 2px 6px rgba(0, 0, 0, .6);
|
||
transform: translateX(0);
|
||
}
|
||
97% {
|
||
text-shadow: -3px 0 rgba(37, 244, 238, .95), 3px 0 rgba(254, 44, 85, .95), 0 2px 6px rgba(0, 0, 0, .6);
|
||
transform: translateX(-1px);
|
||
}
|
||
97.5% {
|
||
text-shadow: 3px 0 rgba(37, 244, 238, .95), -3px 0 rgba(254, 44, 85, .95), 0 2px 6px rgba(0, 0, 0, .6);
|
||
transform: translateX(1px);
|
||
}
|
||
98% {
|
||
text-shadow: 0 2px 6px rgba(0, 0, 0, .6);
|
||
transform: translateX(0);
|
||
}
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn-tiktok, .btn-tiktok::before, .btn-tiktok::after, .btn-tiktok-note, .btn-tiktok-text { animation: none; }
|
||
}
|
||
|
||
/* Silberner Hervorhebungs-Button: eigener, deutlich edlerer Look als
|
||
.btn-tiktok — echtes Chrome-Metallic-Textglitzern, rotierender
|
||
Metallrand-Schimmer, zwei funkelnde Sparkle-Akzente und ein sanft
|
||
pulsierender Halo-Glow. Für Dinge, die besonders auffallen sollen —
|
||
gesperrt (abonnieren.html, "Coming soon…", ohne href und mit
|
||
aria-disabled) ODER als echter Link (vanvan.html → VanVans Shop).
|
||
Der :hover-Zustand unten passt deshalb nur zur verlinkten Variante;
|
||
im gesperrten Fall fällt er mangels href kaum auf. */
|
||
.btn-silver {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: visible;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
/* Die Beschriftung bleibt in EINER Zeile. Ohne das brach "VAN´S DIY" auf
|
||
dem Handy am Apostroph mitten im Wort um ("VAN / ´S / DIY", 05.09.2026
|
||
gemessen bei 390px: Knopf 117px hoch statt 89px). Grund ist die schmale
|
||
Spalte auf vanvan.html — die Sektion bleibt dort auch auf dem Handy
|
||
zweispaltig, weil ein Inline-Style die Regel aus @media(max-width:620px)
|
||
überschreibt. nowrap macht die Knopfbreite zur Mindestbreite der Spalte,
|
||
das Gitter gibt ihm den Platz dann von selbst. */
|
||
white-space: nowrap;
|
||
gap: .55rem;
|
||
padding: .95rem 2.4rem;
|
||
border-radius: 999px;
|
||
color: #fff;
|
||
font-weight: 800;
|
||
font-size: 1.1rem;
|
||
letter-spacing: .02em;
|
||
background: linear-gradient(160deg, #14161c, #0b0e14 55%, #1a1d24);
|
||
border: 1px solid rgba(255, 255, 255, .22);
|
||
text-decoration: none;
|
||
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
|
||
box-shadow: 0 6px 18px rgba(0, 0, 0, .4),
|
||
0 0 0 1px rgba(255, 255, 255, .03) inset;
|
||
animation: btn-silver-halo 3.2s ease-in-out infinite;
|
||
}
|
||
.btn-silver-text {
|
||
position: relative;
|
||
z-index: 2;
|
||
background: linear-gradient(100deg, #9aa4b2 0%, #ffffff 28%, #e6ebf2 42%, #c7ccd1 58%, #ffffff 76%, #9aa4b2 100%);
|
||
background-size: 260% 100%;
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6));
|
||
animation: btn-silver-text-shine 3.6s linear infinite;
|
||
}
|
||
.btn-silver-spark {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: inline-block;
|
||
font-size: .9em;
|
||
filter: drop-shadow(0 0 4px rgba(255, 255, 255, .8));
|
||
animation: btn-silver-twinkle 1.8s ease-in-out infinite;
|
||
}
|
||
.btn-silver-spark:last-child { animation-delay: .9s; }
|
||
.btn-silver::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -1px;
|
||
z-index: 0;
|
||
border-radius: inherit;
|
||
padding: 1.5px;
|
||
background: conic-gradient(from 0deg, #eef1f5, #9aa4b2, #ffffff, #c7ccd1, #7d8794, #eef1f5);
|
||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||
-webkit-mask-composite: xor;
|
||
mask-composite: exclude;
|
||
animation: btn-silver-shine-rotate 5s linear infinite;
|
||
}
|
||
.btn-silver::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
border-radius: inherit;
|
||
background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, .5) 49%, transparent 63%);
|
||
background-size: 240% 100%;
|
||
mix-blend-mode: overlay;
|
||
animation: nav-cta-shimmer 4.5s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
.btn-silver:hover {
|
||
transform: translateY(-1px) scale(1.02);
|
||
border-color: rgba(255, 255, 255, .4);
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, .5),
|
||
0 0 26px rgba(230, 235, 242, .45),
|
||
0 0 26px rgba(190, 200, 215, .35);
|
||
}
|
||
@keyframes btn-silver-shine-rotate {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
@keyframes btn-silver-text-shine {
|
||
0% { background-position: 0% 50%; }
|
||
100% { background-position: 260% 50%; }
|
||
}
|
||
@keyframes btn-silver-twinkle {
|
||
0%, 100% { opacity: .45; transform: scale(.85) rotate(0deg); }
|
||
50% { opacity: 1; transform: scale(1.15) rotate(15deg); }
|
||
}
|
||
@keyframes btn-silver-halo {
|
||
0%, 100% { box-shadow: 0 6px 18px rgba(0, 0, 0, .4), 0 0 14px rgba(200, 208, 220, .18); }
|
||
50% { box-shadow: 0 6px 18px rgba(0, 0, 0, .4), 0 0 26px rgba(230, 235, 242, .4); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn-silver, .btn-silver::before, .btn-silver::after, .btn-silver-text, .btn-silver-spark {
|
||
animation: none;
|
||
}
|
||
}
|
||
|
||
/* "Legendärer" Button (z.B. Casperlino-Link auf streamer.html): babyblau
|
||
+ Silber, gleiche edle Machart wie .btn-silver (Chrome-Textglanz,
|
||
rotierender Rand, Sparkles, pulsierender Halo), aber größer, kräftiger
|
||
und in der Marken-Akzentfarbe --accent (Babyblau) statt neutralem Grau —
|
||
soll bewusst wie ein besonderes, "episches" Highlight wirken. */
|
||
.btn-legendary {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: visible;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .6rem;
|
||
padding: 1.05rem 2.7rem;
|
||
border-radius: 999px;
|
||
color: #fff;
|
||
font-weight: 800;
|
||
font-size: 1.18rem;
|
||
letter-spacing: .02em;
|
||
background: linear-gradient(160deg, #101b20, #0b0e14 55%, #16232a);
|
||
border: 1px solid rgba(143, 217, 234, .35);
|
||
text-decoration: none;
|
||
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
|
||
box-shadow: 0 8px 22px rgba(0, 0, 0, .45),
|
||
0 0 0 1px rgba(143, 217, 234, .06) inset;
|
||
animation: btn-legendary-halo 3s ease-in-out infinite;
|
||
}
|
||
.btn-legendary-text {
|
||
position: relative;
|
||
z-index: 2;
|
||
background: linear-gradient(100deg, #8fd9ea 0%, #ffffff 26%, #c7ccd1 42%, #8fd9ea 58%, #ffffff 76%, #c7ccd1 100%);
|
||
background-size: 260% 100%;
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6));
|
||
animation: btn-legendary-text-shine 3.4s linear infinite;
|
||
}
|
||
.btn-legendary-spark {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: inline-block;
|
||
font-size: .95em;
|
||
filter: drop-shadow(0 0 5px rgba(143, 217, 234, .9));
|
||
animation: btn-legendary-twinkle 1.7s ease-in-out infinite;
|
||
}
|
||
.btn-legendary-spark:last-child { animation-delay: .85s; }
|
||
.btn-legendary::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -1.5px;
|
||
z-index: 0;
|
||
border-radius: inherit;
|
||
padding: 2px;
|
||
background: conic-gradient(from 0deg, #8fd9ea, #eef1f5, #c7ccd1, #ffffff, #8fd9ea, #7d8794, #8fd9ea);
|
||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||
-webkit-mask-composite: xor;
|
||
mask-composite: exclude;
|
||
animation: btn-legendary-shine-rotate 4.5s linear infinite;
|
||
}
|
||
.btn-legendary::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
border-radius: inherit;
|
||
background: linear-gradient(115deg, transparent 32%, rgba(143, 217, 234, .55) 49%, transparent 66%);
|
||
background-size: 240% 100%;
|
||
mix-blend-mode: overlay;
|
||
animation: nav-cta-shimmer 4s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
.btn-legendary:hover {
|
||
transform: translateY(-2px) scale(1.03);
|
||
border-color: rgba(143, 217, 234, .55);
|
||
box-shadow: 0 14px 34px rgba(0, 0, 0, .5),
|
||
0 0 30px rgba(143, 217, 234, .5),
|
||
0 0 30px rgba(199, 204, 209, .35);
|
||
}
|
||
@keyframes btn-legendary-shine-rotate {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
@keyframes btn-legendary-text-shine {
|
||
0% { background-position: 0% 50%; }
|
||
100% { background-position: 260% 50%; }
|
||
}
|
||
@keyframes btn-legendary-twinkle {
|
||
0%, 100% { opacity: .5; transform: scale(.85) rotate(0deg); }
|
||
50% { opacity: 1; transform: scale(1.2) rotate(15deg); }
|
||
}
|
||
@keyframes btn-legendary-halo {
|
||
0%, 100% { box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 16px rgba(143, 217, 234, .22); }
|
||
50% { box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 32px rgba(143, 217, 234, .5); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn-legendary, .btn-legendary::before, .btn-legendary::after, .btn-legendary-text, .btn-legendary-spark {
|
||
animation: none;
|
||
}
|
||
}
|
||
|
||
/* =====================================================================
|
||
"Gesperrter Tresor"-Knopf für den DogiCrew-Registrieren-Knopf
|
||
(abonnieren.html, 20.08.2026, Nutzer-Wunsch: "richtig krank übertrieben
|
||
geiles... weil es wird ja das geilste Bonus und überhaupt so von mir").
|
||
Bewusst KEINE Wiederverwendung von .btn-silver — der ist neutral-grau und
|
||
auf DIESER Seite bereits für die Teddy-Kollektion (Nebensache) vergeben.
|
||
Chrome-Text-Clip-Schimmer + Schimmer-Sweep + Halo-Puls wie .btn-silver/
|
||
.btn-legendary, aber in den ECHTEN Gold-Tönen dieser Seite
|
||
(#ffe9a8/#d4af37, siehe .abo-panel .btn) und mit einem pulsierenden
|
||
Schloss statt Sternen, damit die Haupt-CTA sichtbar "das Besondere,
|
||
noch verschlossene" bleibt statt nur "irgendwann verfügbar".
|
||
WICHTIG: Für den Rand bewusst NICHT die rotierende Conic-Gradient-Maske
|
||
von .btn-silver/.btn-legendary kopiert — dieser Knopf läuft über
|
||
`width:100%` auf voller Kartenbreite (~440px) bei nur ~62px Höhe, also
|
||
ein sehr langgestrecktes Rechteck. Genau für diesen Fall ist die
|
||
dokumentierte Lektion in Projektregeln.md Punkt 14 gedacht (03.08.2026,
|
||
"TikTok-Button-Bug"): ein rotierendes maskiertes Pseudo-Element verzieht
|
||
sich auf länglichen Formen zu einer krummen Schlaufe, weil ein Rechteck
|
||
beim Rotieren nicht rotationssymmetrisch ist — live mit Playwright-
|
||
Screenshots über mehrere Frames nachgewiesen (die Schlaufe ist der
|
||
rotierende Rand bei verschiedenen Winkeln). Stattdessen derselbe sichere
|
||
Zwei-Layer-Background-Trick wie bei .abo-google-frame weiter oben in
|
||
dieser Datei (Füllung padding-box + Verlauf border-box, Bewegung nur
|
||
über background-position) — bleibt geometrisch exakt an der Kontur,
|
||
unabhängig vom Seitenverhältnis. Reine Deko/Statusanzeige — echte
|
||
Deaktivierung läuft über das native disabled-Attribut am <button>
|
||
(siehe abonnieren.html), nicht über pointer-events, damit auch
|
||
Tastatur-/Screenreader-Nutzung korrekt "nicht bedienbar" meldet. Bewusst
|
||
KEIN :hover-Zustand (keine Lift-Animation wie bei .btn-silver/
|
||
.btn-legendary) — soll nicht so wirken, als wäre er doch klickbar. */
|
||
.btn-gold-locked {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: .65rem;
|
||
padding: 1rem 1.4rem;
|
||
border-radius: 14px;
|
||
font-weight: 800;
|
||
font-size: 1.04rem;
|
||
letter-spacing: .02em;
|
||
border: 1.5px solid transparent;
|
||
background:
|
||
linear-gradient(160deg, #1c1710, #0b0e14 55%, #211a0d) padding-box,
|
||
linear-gradient(120deg, #d4af37, #ffe9a8, #b8912b, #fff2c9, #d4af37) border-box;
|
||
background-size: 100% 100%, 260% 100%;
|
||
cursor: not-allowed;
|
||
animation: btn-gold-locked-border-shine 6s ease-in-out infinite, btn-gold-locked-halo 3s ease-in-out infinite;
|
||
box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 0 1px rgba(212, 175, 55, .08) inset;
|
||
}
|
||
.btn-gold-locked-lock {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: inline-block;
|
||
font-size: 1.05em;
|
||
filter: drop-shadow(0 0 6px rgba(255, 214, 102, .85));
|
||
animation: btn-gold-locked-pulse 2.2s ease-in-out infinite;
|
||
}
|
||
.btn-gold-locked-text {
|
||
position: relative;
|
||
z-index: 2;
|
||
background: linear-gradient(100deg, #ffe9a8 0%, #ffffff 24%, #d4af37 42%, #ffe9a8 60%, #ffffff 78%, #d4af37 100%);
|
||
background-size: 260% 100%;
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6));
|
||
animation: btn-silver-text-shine 3.6s linear infinite; /* bestehendes Keyframe wiederverwendet */
|
||
}
|
||
.btn-gold-locked::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
border-radius: inherit;
|
||
background: linear-gradient(115deg, transparent 32%, rgba(255, 233, 168, .5) 49%, transparent 66%);
|
||
background-size: 240% 100%;
|
||
mix-blend-mode: overlay;
|
||
animation: nav-cta-shimmer 4s linear infinite; /* bestehendes Keyframe wiederverwendet */
|
||
pointer-events: none;
|
||
}
|
||
@keyframes btn-gold-locked-border-shine {
|
||
0%, 100% { background-position: 0 0, 0% 50%; }
|
||
50% { background-position: 0 0, 100% 50%; }
|
||
}
|
||
@keyframes btn-gold-locked-pulse {
|
||
0%, 100% { opacity: .7; transform: scale(.92) rotate(-4deg); }
|
||
50% { opacity: 1; transform: scale(1.12) rotate(4deg); }
|
||
}
|
||
@keyframes btn-gold-locked-halo {
|
||
0%, 100% { box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 16px rgba(212, 175, 55, .22); }
|
||
50% { box-shadow: 0 8px 22px rgba(0, 0, 0, .45), 0 0 32px rgba(255, 214, 102, .45); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn-gold-locked, .btn-gold-locked::after,
|
||
.btn-gold-locked-text, .btn-gold-locked-lock {
|
||
animation: none;
|
||
}
|
||
}
|
||
|
||
/* =====================================================================
|
||
.btn-holo — zweiter "Mega"-Button-Stil, bewusst MECHANISCH anders als
|
||
.btn-legendary/.btn-silver/.btn-tiktok (die alle nach demselben Muster
|
||
funktionieren: dunkler Hintergrund + heller Rand/Text-Glanz). Hier ist
|
||
stattdessen die GESAMTE Pille eine wandernde Holo-Foil-Fläche, wie bei
|
||
einer schillernden Trading-Card — Marken-Farbverlauf (Babyblau → Lila
|
||
→ Pink → Gold → zurück), ein diagonaler Glare-Sweep wie echtes reflek-
|
||
tierendes Folienlicht, feines Foliekorn und dunkle geprägte Schrift
|
||
OBEN DRAUF statt heller Chrome-Schrift auf Dunkel. Auf Vorrat gebaut
|
||
(03.08.2026, auf Wunsch von Dogi) — noch nirgends im Einsatz, einfach
|
||
die Klassen wie unten im Beispiel verwenden:
|
||
|
||
<a class="btn-holo" href="...">
|
||
<span class="btn-holo-spark" aria-hidden="true">💎</span>
|
||
<span class="btn-holo-text">Label</span>
|
||
<span class="btn-holo-spark" aria-hidden="true">💎</span>
|
||
</a>
|
||
===================================================================== */
|
||
.btn-holo {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .6rem;
|
||
padding: .95rem 2.4rem;
|
||
border-radius: 999px;
|
||
font-weight: 900;
|
||
font-size: 1.12rem;
|
||
letter-spacing: .02em;
|
||
text-decoration: none;
|
||
border: 1.5px solid rgba(255, 255, 255, .7);
|
||
background: linear-gradient(120deg,
|
||
#8fd9ea 0%, #8b5cf6 18%, #ff5fa8 38%, #ffcf4d 54%, #8fd9ea 74%, #8b5cf6 100%);
|
||
background-size: 340% 340%;
|
||
animation: btn-holo-shift 6s ease-in-out infinite, btn-holo-halo 2.6s ease-in-out infinite;
|
||
transition: transform .25s cubic-bezier(.2, .8, .3, 1.4), box-shadow .25s ease, border-color .25s ease;
|
||
box-shadow: 0 8px 22px rgba(0, 0, 0, .45),
|
||
0 0 0 3px rgba(11, 13, 16, .9),
|
||
0 0 0 4.5px rgba(255, 255, 255, .3);
|
||
}
|
||
.btn-holo-text {
|
||
position: relative;
|
||
z-index: 2;
|
||
color: #0b0d10;
|
||
text-transform: uppercase;
|
||
text-shadow: 0 1px 0 rgba(255, 255, 255, .6), 0 -1px 0 rgba(0, 0, 0, .22);
|
||
}
|
||
.btn-holo-spark {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: inline-block;
|
||
font-size: .9em;
|
||
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .4));
|
||
animation: btn-holo-twinkle 1.8s ease-in-out infinite;
|
||
}
|
||
.btn-holo-spark:last-child { animation-delay: .9s; }
|
||
/* Diagonaler Glare-Sweep, wie Licht, das über echte Folie wandert */
|
||
.btn-holo::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
background: linear-gradient(100deg,
|
||
transparent 28%, rgba(255, 255, 255, .95) 48%, rgba(255, 255, 255, .2) 54%, transparent 74%);
|
||
background-size: 250% 100%;
|
||
mix-blend-mode: overlay;
|
||
animation: btn-holo-glare 2.8s ease-in-out infinite;
|
||
pointer-events: none;
|
||
}
|
||
/* Feines Foliekorn (SVG-Turbulence), sorgt für den "echten Folien"-Look
|
||
statt einer platten Farbverlaufsfläche. */
|
||
.btn-holo::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
background-image: 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.5'/%3E%3C/svg%3E");
|
||
background-size: 150px 150px;
|
||
mix-blend-mode: overlay;
|
||
opacity: .3;
|
||
pointer-events: none;
|
||
}
|
||
.btn-holo:hover {
|
||
transform: translateY(-3px) scale(1.06);
|
||
border-color: #fff;
|
||
animation-play-state: paused;
|
||
box-shadow: 0 18px 44px rgba(0, 0, 0, .5),
|
||
0 0 0 3px rgba(11, 13, 16, .9),
|
||
0 0 0 4.5px rgba(255, 255, 255, .5),
|
||
0 0 40px rgba(139, 92, 246, .6),
|
||
0 0 40px rgba(143, 217, 234, .5);
|
||
}
|
||
@keyframes btn-holo-shift {
|
||
0%, 100% { background-position: 0% 50%; }
|
||
50% { background-position: 100% 50%; }
|
||
}
|
||
@keyframes btn-holo-halo {
|
||
0%, 100% {
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, .45),
|
||
0 0 0 3px rgba(11, 13, 16, .9),
|
||
0 0 0 4.5px rgba(255, 255, 255, .3),
|
||
0 0 18px rgba(139, 92, 246, .35),
|
||
0 0 18px rgba(143, 217, 234, .3);
|
||
}
|
||
50% {
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, .45),
|
||
0 0 0 3px rgba(11, 13, 16, .9),
|
||
0 0 0 4.5px rgba(255, 255, 255, .45),
|
||
0 0 34px rgba(139, 92, 246, .6),
|
||
0 0 34px rgba(255, 95, 168, .45);
|
||
}
|
||
}
|
||
@keyframes btn-holo-glare {
|
||
0% { background-position: -70% 0; }
|
||
100% { background-position: 170% 0; }
|
||
}
|
||
@keyframes btn-holo-twinkle {
|
||
0%, 100% { opacity: .6; transform: scale(.85) rotate(0deg); }
|
||
50% { opacity: 1; transform: scale(1.35) rotate(-14deg); }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn-holo, .btn-holo::before, .btn-holo-spark { animation: none; }
|
||
}
|
||
|
||
/* Kompakter Polarlicht-Button für Karten (z.B. Marinas Team-Modi-Karte →
|
||
direkter Link zur Manager-Seite): exakt derselbe Mechanismus wie
|
||
.btn-tiktok, nur kleiner und in den Spicy-Media-Markenfarben
|
||
(Rot #d94a5c + Orange #e8935a) statt Cyan/Pink. */
|
||
.btn-spicy-mini {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: .3rem;
|
||
margin-top: .6rem;
|
||
padding: .5rem 1rem;
|
||
border-radius: 999px;
|
||
color: #fff;
|
||
font-weight: 700;
|
||
font-size: .8rem;
|
||
background: #0b0e14;
|
||
border: 1px solid rgba(255, 255, 255, .16);
|
||
text-decoration: none;
|
||
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
|
||
box-shadow: 0 5px 14px rgba(0, 0, 0, .35);
|
||
}
|
||
.btn-spicy-mini span {
|
||
position: relative;
|
||
z-index: 2;
|
||
text-shadow: 0 1px 3px rgba(0, 0, 0, .6), 0 0 12px rgba(0, 0, 0, .35);
|
||
}
|
||
.btn-spicy-mini::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -60%;
|
||
z-index: 0;
|
||
background:
|
||
radial-gradient(circle at 22% 30%, rgba(217, 74, 92, .95), transparent 55%),
|
||
radial-gradient(circle at 78% 68%, rgba(232, 147, 90, .95), transparent 58%);
|
||
filter: blur(8px) saturate(1.35);
|
||
animation: nav-cta-aurora 9s ease-in-out infinite alternate;
|
||
}
|
||
.btn-spicy-mini::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
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;
|
||
}
|
||
.btn-spicy-mini:hover {
|
||
transform: translateY(-1px);
|
||
border-color: rgba(255, 255, 255, .32);
|
||
box-shadow: 0 8px 20px rgba(0, 0, 0, .4),
|
||
0 0 16px rgba(217, 74, 92, .35),
|
||
0 0 16px rgba(232, 147, 90, .35);
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn-spicy-mini::before, .btn-spicy-mini::after { animation: none; }
|
||
}
|
||
|
||
/* Plattform-Karten mit echten Markenfarben (z.B. links.html-Übersicht):
|
||
gleicher Polarlicht-Mechanismus wie .btn-tiktok, aber generisch über
|
||
--brand-1/--brand-2 (+ optional --brand-3) einstellbar, damit jede
|
||
Plattform ihre EIGENEN echten Farben bekommt, ohne den ganzen Block
|
||
pro Plattform zu duplizieren. Die konkreten Farben stehen weiter unten
|
||
in den .card-<plattform>-Klassen. */
|
||
.card-brand {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
background: #0b0e14;
|
||
border-color: rgba(255, 255, 255, .16);
|
||
padding: 2rem 1.8rem;
|
||
}
|
||
.card-brand .icon-badge, .card-brand h3, .card-brand p {
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
.card-brand h3, .card-brand p {
|
||
text-shadow: 0 1px 3px rgba(0, 0, 0, .6), 0 0 14px rgba(0, 0, 0, .35);
|
||
}
|
||
.card-brand .icon-badge {
|
||
display: block;
|
||
font-size: 2.4rem;
|
||
line-height: 1;
|
||
margin-bottom: .6rem;
|
||
filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .5));
|
||
}
|
||
.card-brand h3 { font-size: 1.5rem; }
|
||
.card-brand p { font-size: 1.05rem; margin-top: .3rem; }
|
||
.card-brand::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -60%;
|
||
z-index: 0;
|
||
background:
|
||
radial-gradient(circle at 22% 28%, var(--brand-1, rgba(143, 217, 234, .85)), transparent 55%),
|
||
radial-gradient(circle at 78% 70%, var(--brand-2, rgba(139, 92, 246, .85)), transparent 58%),
|
||
radial-gradient(circle at 50% 92%, var(--brand-3, transparent), transparent 55%);
|
||
filter: blur(11px) saturate(1.35);
|
||
animation: nav-cta-aurora 9s ease-in-out infinite alternate;
|
||
}
|
||
.card-brand::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, .35) 49%, transparent 63%);
|
||
background-size: 240% 100%;
|
||
mix-blend-mode: overlay;
|
||
animation: nav-cta-shimmer 4.5s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
.card-brand:hover {
|
||
border-color: rgba(255, 255, 255, .32);
|
||
box-shadow: 0 10px 26px rgba(0, 0, 0, .45),
|
||
0 0 22px var(--brand-1, rgba(143, 217, 234, .3)),
|
||
0 0 22px var(--brand-2, rgba(139, 92, 246, .28));
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.card-brand::before, .card-brand::after { animation: none; }
|
||
}
|
||
|
||
/* Bewusst NUR echte Plattform-/CTA-Farben, keine erfundenen: */
|
||
.card-tiktok { --brand-1: rgba(37, 244, 238, .95); --brand-2: rgba(254, 44, 85, .95); }
|
||
.card-instagram { --brand-1: rgba(131, 58, 180, .9); --brand-2: rgba(253, 29, 29, .82); --brand-3: rgba(252, 176, 69, .55); }
|
||
.card-snapchat { --brand-1: rgba(255, 252, 0, .85); --brand-2: rgba(255, 220, 0, .45); }
|
||
.card-snapchat h3, .card-snapchat p { text-shadow: 0 1px 3px rgba(0, 0, 0, .8), 0 0 16px rgba(0, 0, 0, .55); }
|
||
.card-discord { --brand-1: rgba(88, 101, 242, .95); --brand-2: rgba(88, 101, 242, .4); }
|
||
.card-shop { --brand-1: rgba(212, 175, 55, .85); --brand-2: rgba(255, 183, 77, .6); }
|
||
.card-bewerben { --brand-1: rgba(143, 217, 234, .85); --brand-2: rgba(139, 92, 246, .8); --brand-3: rgba(217, 74, 92, .5); }
|
||
|
||
/* "Feature"-Karten (links.html): zwei besondere, GRÖSSERE Kacheln über der
|
||
normalen Plattform-Icon-Reihe — Abo-System (VIP: Gold/Lila) und
|
||
Rabattcodes (Community-Ersparnis: Grün/Orange). Bauen auf .card-brand
|
||
auf (gleicher Aurora-/Schimmer-Mechanismus), bekommen zusätzlich einen
|
||
rotierenden Farbring (wie .card-duel) und ein Eckband mit Status-Text,
|
||
damit sie sich klar von den kompakten Plattform-Kacheln absetzen. */
|
||
.card-feature {
|
||
padding: 2.6rem 2rem;
|
||
min-height: 230px;
|
||
}
|
||
.card-feature::before { inset: -70%; }
|
||
.card-feature .icon-badge { font-size: 3.1rem; margin-bottom: .8rem; }
|
||
.card-feature h3 { font-size: 1.75rem; }
|
||
.card-feature-desc {
|
||
position: relative;
|
||
z-index: 2;
|
||
font-size: .96rem;
|
||
line-height: 1.55;
|
||
color: rgba(255, 255, 255, .8);
|
||
margin: .5rem auto 0;
|
||
max-width: 32ch;
|
||
text-shadow: 0 1px 3px rgba(0, 0, 0, .6), 0 0 14px rgba(0, 0, 0, .3);
|
||
}
|
||
/* Echtes <span> statt eines dritten Pseudo-Elements (::before/::after sind
|
||
an .card-brand schon für Aurora/Schimmer vergeben) — bewusst NICHT
|
||
rotiert (siehe .btn-tiktok-Notiz weiter oben: ein rotierender Masken-Ring
|
||
verzerrt sich auf länglichen/runden Formen), sondern ein ruhiger,
|
||
statischer Farbverlaufs-Rand. */
|
||
.card-feature-ring {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 3;
|
||
border-radius: inherit;
|
||
padding: 1.5px;
|
||
background: conic-gradient(from 0deg, var(--brand-1), var(--brand-2), var(--brand-1) 66%, var(--brand-2) 100%);
|
||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||
-webkit-mask-composite: xor;
|
||
mask-composite: exclude;
|
||
opacity: .8;
|
||
pointer-events: none;
|
||
}
|
||
.card-feature-badge {
|
||
position: absolute;
|
||
top: 1rem;
|
||
right: 1rem;
|
||
z-index: 4;
|
||
font-size: .66rem;
|
||
font-weight: 800;
|
||
letter-spacing: .05em;
|
||
text-transform: uppercase;
|
||
padding: .38rem .75rem;
|
||
border-radius: 999px;
|
||
background: rgba(8, 10, 14, .55);
|
||
border: 1px solid rgba(255, 255, 255, .28);
|
||
backdrop-filter: blur(4px);
|
||
color: #fff;
|
||
}
|
||
.card-feature:hover {
|
||
transform: translateY(-3px);
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.card-feature { transition: none; }
|
||
}
|
||
.card-abo { --brand-1: rgba(212, 175, 55, .9); --brand-2: rgba(139, 92, 246, .75); }
|
||
.card-abo .card-feature-badge { color: #ffe9a8; border-color: rgba(255, 214, 102, .5); }
|
||
.card-rabatt { --brand-1: rgba(52, 211, 153, .9); --brand-2: rgba(251, 146, 60, .8); }
|
||
.card-rabatt .card-feature-badge { color: #baf7d6; border-color: rgba(94, 234, 167, .5); }
|
||
|
||
/* Breite Variante von .card-feature — nimmt die volle Container-Breite ein
|
||
(statt im 2er-Grid neben einer zweiten Karte zu stehen) und wechselt
|
||
dafür auf ein horizontales Layout: Icon links, Titel/Text rechts daneben
|
||
statt zentriert übereinander, damit die Breite bewusst genutzt wird statt
|
||
nur Leerraum links/rechts vom zentrierten Text zu erzeugen. */
|
||
.card-feature-wide {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1.8rem;
|
||
text-align: left;
|
||
padding: 2.2rem 2.8rem;
|
||
min-height: auto;
|
||
}
|
||
.card-feature-wide .icon-badge {
|
||
flex-shrink: 0;
|
||
margin-bottom: 0;
|
||
}
|
||
.card-feature-wide .card-feature-text {
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
.card-feature-wide .card-feature-desc {
|
||
margin: .4rem 0 0;
|
||
max-width: 60ch;
|
||
}
|
||
@media (max-width: 640px) {
|
||
.card-feature-wide {
|
||
flex-direction: column;
|
||
text-align: center;
|
||
padding: 2.4rem 1.6rem;
|
||
}
|
||
.card-feature-wide .card-feature-desc { margin: .4rem auto 0; }
|
||
}
|
||
|
||
.nav-toggle {
|
||
display: none;
|
||
/* Leichte blaue Tönung (21.08.2026, Nutzer-Wunsch: "die kiste soll auch
|
||
leicht eine andere farbe haben so dass sie auffällt. eine leicht blau
|
||
tönung.") -- bewusst sehr dezent (8% Deckkraft), damit es zur übrigen
|
||
augenschonenden Optik der Seite passt und nicht wie ein grelles Warn-
|
||
Element wirkt, aber deutlich genug, um die Kiste vom sonst rein
|
||
schwarzen Kopfbereich abzuheben. */
|
||
background: rgba(143, 217, 234, .1);
|
||
border: 1px solid rgba(143, 217, 234, .35);
|
||
border-radius: 8px;
|
||
color: var(--text);
|
||
padding: .5rem .7rem;
|
||
cursor: pointer;
|
||
align-items: center;
|
||
gap: .4rem;
|
||
}
|
||
.nav-toggle:hover, .nav-toggle:focus-visible {
|
||
background: rgba(143, 217, 234, .18);
|
||
border-color: rgba(143, 217, 234, .55);
|
||
}
|
||
/* Sichtbares "Menü" NEBEN den drei Strichen (21.08.2026, Nutzer-Report per
|
||
Bild: "da soll auch menü stehen und die 3 striche"). */
|
||
.nav-toggle-label { font-size: .82rem; font-weight: 600; letter-spacing: .02em; }
|
||
|
||
/* Bugfix 20.08.2026 (Nutzer-Report per Screenshot: "DogiCrew"-Knopf/Badge
|
||
rechts abgeschnitten): die Schwelle war schon zweimal angehoben (880 ->
|
||
1480px, dazu der .nav-bar-Deckel 1400 -> 1440px), reichte aber seither
|
||
NICHT mehr aus — seit den neu dazugekommenen Nav-Punkten "DogiCrew" +
|
||
"BALD"-Badge braucht die aufgeklappte Desktop-Nav real ca. 1491px
|
||
Breite (per Playwright über mehrere Breiten nachgemessen), der Deckel
|
||
blieb aber bei 1440px hart begrenzt. Ergebnis: bei JEDER Fensterbreite
|
||
ab ca. 1500px (nicht nur in einer schmalen Übergangszone) lief die Nav
|
||
permanent ca. 50px über den Rand hinaus. Diesmal mit echtem Sicherheits-
|
||
abstand behoben statt wieder nur knapp: Schwelle auf 1650px, Deckel auf
|
||
1560px — bei exakt 1650px ergibt min(1560px, 94vw) ≈ 1551px, spürbar
|
||
mehr als die gemessenen ~1491px nötigen Breite. Bei jeder Fensterbreite
|
||
NACH der Schwelle reicht 94vw automatisch weiter aus (nur ganz nah an
|
||
der Schwelle war die Lücke kritisch). */
|
||
@media (max-width: 1650px) {
|
||
/* margin-left:auto (21.08.2026): schiebt den Menü-Knopf IMMER an die
|
||
rechte Kante, egal wie breit die Marke daneben ist. Ohne das stand er
|
||
direkt hinter der Marke und wurde auf schmalen Bildschirmen rechts aus
|
||
dem Bild geschoben (siehe Bugfix-Block bei @media max-width:620px). */
|
||
.nav-toggle { display: flex; margin-left: auto; }
|
||
.nav-links {
|
||
position: fixed;
|
||
inset: 62px 0 0 0;
|
||
background: var(--bg);
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
padding: 1.2rem 6vw;
|
||
gap: .3rem;
|
||
/* Bugfix 21.08.2026 (beim Testen des "Menü"-Knopf-Umbaus entdeckt, per
|
||
Playwright reproduziert): -110% verschiebt das Panel um 110% SEINER
|
||
EIGENEN Höhe -- das reicht nur dann sicher aus, wenn das Panel
|
||
mindestens 10x so hoch ist wie der "inset:62px"-Versatz oben
|
||
(Rechnung: Panel-Unterkante landet bei 62px - 10%-der-Panelhöhe).
|
||
Ist das Menü kürzer (z.B. weniger Punkte, oder der Kopfbereich wurde
|
||
etwas höher wie gerade eben durch den neuen "Menü"-Text), ragte die
|
||
UNTERKANTE des eigentlich geschlossenen Panels ein paar Pixel ins
|
||
Bild -- sichtbar wurde ausgerechnet der Sprachschalter (das farbige
|
||
"DE"-Pillenelement steht ganz unten in der Liste). Robuster Ersatz:
|
||
zusätzlich zu -100% (= exakt die eigene Höhe) ein FESTER Puffer, der
|
||
unabhängig von Panel- und Kopfbereichshöhe immer ausreicht. */
|
||
transform: translateY(calc(-100% - 200px));
|
||
transition: transform .25s ease;
|
||
overflow-y: auto;
|
||
/* Bugfix 21.08.2026 (Handy im QUERFORMAT): das zugeklappte Panel wird um
|
||
-110% SEINER EIGENEN HÖHE verschoben. Auf einem niedrigen Bildschirm
|
||
(quer, z.B. 568x320) ist das Panel nur 258px hoch, -110% sind also nur
|
||
-284px -- die Unterkante landet bei y=36px und lag damit GENAU über dem
|
||
Menü-Knopf (y=11..55). Unsichtbar, aber es hat jede Berührung
|
||
abgefangen: das Menü ließ sich im Querformat überhaupt nicht öffnen.
|
||
pointer-events:none im geschlossenen Zustand löst das unabhängig von
|
||
Bildschirmhöhe und Panelgröße -- was zu ist, kann nichts mehr
|
||
blockieren. */
|
||
pointer-events: none;
|
||
}
|
||
.nav-links.open { pointer-events: auto; }
|
||
.nav-links.open { transform: translateY(0); }
|
||
/* Bugfix 21.08.2026: .nav-links ist ein Flex-Container mit FESTER Höhe
|
||
(inset: 62px 0 0 0). Passen die Einträge zusammen nicht hinein, schrumpft
|
||
Flexbox sie standardmäßig (flex-shrink: 1) -- auf einem kurzen Bildschirm
|
||
(iPhone SE, 568px) wurden aus 59px hohen Menüzeilen dadurch 29px, und aus
|
||
den Knöpfen "DogiCrew"/"Bewerben" sogar nur 21px. Damit lagen sie unter
|
||
jeder vernünftigen Tippgröße (Empfehlung Apple/Google: ~44px).
|
||
flex-shrink:0 lässt sie ihre volle Höhe behalten -- der Bereich hat
|
||
bereits overflow-y:auto, scrollt also stattdessen. */
|
||
.nav-links > * { flex-shrink: 0; }
|
||
/* Trennlinien statt "Schüsseln" (Bugfix 21.08.2026): .nav-group > button
|
||
und .nav-flat tragen vom Desktop border-radius:999px (Pillen-Look). Mit
|
||
border-bottom zusammen bog sich die Linie an den Enden nach oben und sah
|
||
im aufgeklappten Handy-Menü aus wie eine Schale unter jedem Eintrag.
|
||
|
||
Lösung: border-bottom raus, Trennlinie stattdessen als ::after -- ein
|
||
absolut positionierter 1px-Streifen ist immer schnurgerade, egal welchen
|
||
Radius das Element hat. Dadurch bleibt gleichzeitig ein sanfter Radius
|
||
für die Farbfüllung des aktiven/offenen Eintrags möglich (ein harter
|
||
rechteckiger Block sah neben den runden Formen der Seite fremd aus).
|
||
::after ist bei beiden frei -- der ▾-Pfeil steht im Textinhalt, der
|
||
Farbschein nutzt ::before. */
|
||
.nav-group > button,
|
||
.nav-flat {
|
||
border-radius: 10px;
|
||
border-bottom: none;
|
||
}
|
||
.nav-group > button { width: 100%; justify-content: space-between; padding: .9rem .7rem; }
|
||
.nav-flat { display: block; padding: .9rem .7rem; }
|
||
.nav-group > button::after,
|
||
.nav-flat::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0; right: 0; bottom: 0;
|
||
height: 1px;
|
||
background: var(--border);
|
||
pointer-events: none;
|
||
}
|
||
.nav-dropdown { position: static; transform: none; box-shadow: none; width: 100%; margin-top: 0; animation: none; }
|
||
.nav-dropdown::before { display: none; }
|
||
.nav-group.open .nav-dropdown { display: flex; }
|
||
/* Bugfix 22.08.2026 (Nutzer-Report per Foto: "wenn ich auf DE klicke geht
|
||
das Fenster halb schräg auf, man sieht nichts"). Ursache: die Zeile
|
||
darüber (.nav-dropdown, Spezifität 0-1-0) hebt für das Handy-Menü
|
||
position/transform/animation auf — sie verliert aber gegen die
|
||
Desktop-Regel .sprach-schalter .nav-dropdown (0-2-0, Zeile ~427), denn
|
||
eine @media-Abfrage erhöht die Spezifität NICHT. Beim Sprachschalter
|
||
blieb dadurch die Aufklapp-Animation "sprach-dropdown-in" aktiv, und
|
||
die setzt (fill-mode: both) dauerhaft transform: translateX(-50%) —
|
||
die im Handy-Menü volle-Breite-Box wurde also um ihre halbe Breite
|
||
nach links aus dem Bild geschoben. Deshalb hier dieselben Regeln noch
|
||
einmal mit passender Spezifität (Blattname mitgenannt, damit sie in
|
||
jedem Fall gewinnt). */
|
||
.nav-links .sprach-schalter .nav-dropdown {
|
||
position: static;
|
||
transform: none;
|
||
animation: none;
|
||
width: 100%;
|
||
min-width: 0;
|
||
margin-top: 0;
|
||
box-shadow: none;
|
||
}
|
||
.nav-cta { align-self: flex-start; margin: 1rem 0 .6rem; }
|
||
|
||
/* Bugfix 20.08.2026 (Nutzer-Report: "auf dem Handy passt nicht immer alles").
|
||
Per echter Mobil-Emulation (iPhone 15 Pro + Pixel 8, Screenshots) nachgestellt:
|
||
Die schwebenden Eck-Knöpfe (Musik unten rechts, Vorschau-Umschalter unten links
|
||
für Dogi/VanVan — siehe .music-widget/.vorschau-widget weiter unten) sind
|
||
absichtlich IMMER sichtbar (position:fixed, direkte <body>-Kinder, eigener
|
||
Stacking-Kontext, unabhängig vom Menü). Bei aufgeklapptem Mobil-Menü liegen sie
|
||
dadurch ÜBER den untersten Menüpunkten (Sprachschalter + "Bewerben"-Knopf) und
|
||
verdecken/blockieren sie sichtbar. :has() statt einer weiteren main.js-Änderung,
|
||
weil beide Widgets keinen gemeinsamen Elternknoten mit .nav-links haben (beide
|
||
hängen direkt unter <body>, .nav-links steckt im Header) — reiner CSS-Fix bleibt
|
||
an der Stelle, an der auch die restliche Menü-Overlay-Logik dieses Blocks steht. */
|
||
body:has(.nav-links.open) .music-widget,
|
||
body:has(.nav-links.open) .vorschau-widget {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
/* =====================================================================
|
||
HANDY-KOPFLEISTE — Bugfix 21.08.2026 (Nutzer-Report per Screenshot:
|
||
"auf dem handy kann ich oben nicht aussehen in welche seite ich will
|
||
welche kategorie welche sprache garnichts").
|
||
|
||
Ursache (per Playwright bei 390px nachgemessen): .brand ist 352px breit
|
||
und steht auf `flex-shrink: 0` (Regel ganz oben) -- durfte also nicht
|
||
schrumpfen. Zusammen mit gap (2rem) und dem Menü-Knopf (39px) brauchte
|
||
die Leiste 423px, verfügbar waren aber nur 367px. Der Menü-Knopf landete
|
||
dadurch bei x=396px, also KOMPLETT außerhalb des 390px breiten Bildes.
|
||
Auf dem Handy war damit die gesamte Navigation unerreichbar: keine
|
||
Seiten, keine Kategorien, kein Sprachwechsel.
|
||
|
||
Fix in drei Teilen:
|
||
1. Menü-Knopf per margin-left:auto immer an die rechte Kante (oben im
|
||
1650px-Block) -- unabhängig von der Breite der Marke.
|
||
2. Die Marke darf hier ausnahmsweise schrumpfen. min-width:0 ist dabei
|
||
zwingend: ohne das schrumpft ein Flex-Element trotz flex-shrink NICHT
|
||
unter seine Inhaltsbreite (Standard ist min-width:auto).
|
||
3. Schriftgrößen etwas herunter + langer Text bricht sauber ab, statt
|
||
die Leiste zu sprengen.
|
||
===================================================================== */
|
||
@media (max-width: 620px) {
|
||
.nav-bar {
|
||
gap: .75rem;
|
||
padding: .7rem 0;
|
||
}
|
||
.brand {
|
||
flex-shrink: 1; /* hebt das globale flex-shrink:0 hier gezielt auf */
|
||
min-width: 0; /* ohne das greift flex-shrink nicht (min-width:auto) */
|
||
gap: .5rem;
|
||
font-size: 1.05rem;
|
||
line-height: 1.15;
|
||
}
|
||
/* Der Textblock neben dem Logo -- darf schmaler werden, Zeilen dürfen
|
||
umbrechen statt die Leiste breiter zu machen. */
|
||
.brand > span {
|
||
min-width: 0;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
.brand-logo { width: 34px; height: 34px; }
|
||
.brand small {
|
||
/* .56rem waren nur 8,96px -- deutlich unter dem, was auf einem Handy
|
||
noch angenehm lesbar ist (Faustregel: nicht unter 11-12px). Da der
|
||
Menü-Knopf inzwischen per margin-left:auto eigenständig rechts sitzt
|
||
und die Marke schrumpfen darf, ist der Platz dafür vorhanden. */
|
||
font-size: .69rem;
|
||
letter-spacing: .05em;
|
||
}
|
||
/* Menü-Knopf: etwas größere Tippfläche als die reine Schriftgröße
|
||
hergibt (Finger statt Mauszeiger), aber schmales Padding, damit er
|
||
auf sehr engen Geräten nicht selbst zum Platzproblem wird. */
|
||
.nav-toggle {
|
||
flex-shrink: 0;
|
||
font-size: 1.25rem;
|
||
line-height: 1;
|
||
padding: .45rem .6rem;
|
||
min-width: 44px;
|
||
min-height: 44px;
|
||
}
|
||
}
|
||
|
||
/* Sehr schmale Geräte (z.B. iPhone SE, 320-360px): dort ist selbst die
|
||
verkleinerte Unterzeile ("STREAMER · COMMUNITY · HASIDOG · MANAGER")
|
||
noch zu lang und drückt die Leiste unnötig in die Höhe. Sie ist reine
|
||
Deko -- der Markenname darüber sagt bereits alles -- deshalb hier weg,
|
||
damit Name und Menü-Knopf sicher nebeneinander passen. */
|
||
@media (max-width: 400px) {
|
||
.brand small { display: none; }
|
||
.brand { font-size: 1rem; }
|
||
}
|
||
|
||
/* ---------- Buttons ----------
|
||
Gleicher STIL wie der "Bewerben"-Knopf oben in der Leiste (wandernde,
|
||
weichgezeichnete Farbwolken + durchlaufender Lichtschimmer) — aber NICHT
|
||
dieselbe feste Regenbogen-Palette, sondern die Farben der jeweiligen
|
||
Seite/Karte (--accent/--accent-2, die überall schon pro Theme bzw. pro
|
||
Karte gesetzt sind). Läuft komplett über negative z-index-Ebenen, dadurch
|
||
bleibt der Button-Text automatisch scharf obenauf, ganz ohne <span>-
|
||
Wrapper in jeder einzelnen HTML-Datei (siehe Stacking-Reihenfolge: eigene
|
||
Box-Hintergrund → negative z-index-Kinder → normaler Inline-Text). */
|
||
.btn {
|
||
position: relative;
|
||
isolation: isolate;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .5rem;
|
||
padding: .8rem 1.5rem;
|
||
border-radius: 999px;
|
||
font-weight: 700;
|
||
font-size: .95rem;
|
||
border: 1px solid transparent;
|
||
cursor: pointer;
|
||
transition: transform .15s ease, opacity .15s ease, box-shadow .2s ease;
|
||
}
|
||
.btn::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -70%;
|
||
z-index: -2;
|
||
background:
|
||
radial-gradient(circle at 24% 28%, color-mix(in srgb, var(--accent) 92%, transparent), transparent 58%),
|
||
radial-gradient(circle at 76% 74%, color-mix(in srgb, var(--accent-2) 92%, transparent), transparent 58%);
|
||
filter: blur(9px) saturate(1.3);
|
||
opacity: .55;
|
||
animation: btn-aurora 11s ease-in-out infinite alternate;
|
||
}
|
||
.btn::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: -1;
|
||
background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, .32) 49%, transparent 63%);
|
||
background-size: 240% 100%;
|
||
mix-blend-mode: overlay;
|
||
animation: btn-shimmer 5.5s linear infinite;
|
||
pointer-events: none;
|
||
}
|
||
@keyframes btn-aurora {
|
||
from { transform: translate(-3%, -2%) rotate(0deg) scale(1); }
|
||
to { transform: translate(3%, 3%) rotate(6deg) scale(1.08); }
|
||
}
|
||
@keyframes btn-shimmer {
|
||
from { background-position: 130% 0; }
|
||
to { background-position: -30% 0; }
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.btn::before, .btn::after { animation: none; }
|
||
}
|
||
.btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 10px 22px rgba(0, 0, 0, .28),
|
||
0 0 18px color-mix(in srgb, var(--accent) 40%, transparent);
|
||
}
|
||
.btn-primary { background: var(--accent); color: var(--accent-contrast); }
|
||
.btn-secondary { background: var(--accent-2); color: #fff; }
|
||
.btn-outline { background: transparent; border-color: var(--border); color: var(--text); }
|
||
.btn-outline:hover { border-color: var(--accent); color: var(--accent); }
|
||
.btn-row { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 1.5rem; }
|
||
|
||
/* Kurzes "✓ Link kopiert"-Feedback für dogiTeilen()-Knöpfe (Zwischenablage-
|
||
Fallback ohne Web-Share-API) -- 21.08.2026. Gleiche Erfolgsfarbe wie
|
||
.vw-copy-btn.kopiert in der Verwaltung, für ein konsistentes Gefühl
|
||
zwischen öffentlicher Seite und Admin-Bereich. */
|
||
.dogi-teilen-kopiert { background: rgba(52,211,153,.15) !important; border-color: rgba(52,211,153,.5) !important; color: #5eeaa7 !important; }
|
||
|
||
/* ---------- Hero ---------- */
|
||
.hero {
|
||
position: relative;
|
||
padding: clamp(4rem, 10vw, 7rem) 0;
|
||
text-align: center;
|
||
overflow: hidden;
|
||
}
|
||
.hero > .container { position: relative; z-index: 1; }
|
||
/* Zusätzlicher, garantiert deckender Schleier NUR hinter dem Hero-Text auf
|
||
Seiten mit Hintergrundfoto (.page-bg) — Ergänzung zum globalen
|
||
body.mit-hintergrund-Verlauf oben. Grund (BFSG/WCAG-Audit 04.08.2026):
|
||
der globale Verlauf allein reichte bei hellen Fotomotiven nicht überall
|
||
für AA-Kontrast (Eyebrow/H1/Lead direkt im Hero betroffen). Sitzt NUR
|
||
um den Text-Container, deckt also NICHT das scharfe .hero-banner-Foto
|
||
darüber ab (das bleibt unverändert sichtbar). */
|
||
.hero.page-bg > .container::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -1.4rem -1.6rem;
|
||
z-index: -1;
|
||
border-radius: 28px;
|
||
background: color-mix(in srgb, var(--bg) 55%, transparent);
|
||
pointer-events: none;
|
||
}
|
||
.hero .worlds {
|
||
margin: .6rem 0 1.2rem;
|
||
color: var(--text-muted);
|
||
font-size: 1.05rem;
|
||
}
|
||
.hero-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 1.2rem;
|
||
margin-top: 3rem;
|
||
}
|
||
@media (max-width: 760px) { .hero-grid { grid-template-columns: 1fr; } }
|
||
|
||
/* "Event des Jahres" (20.08.2026) — volle Breite wie .hero-grid darüber (eigener Block,
|
||
kein Grid-Kind), zeigt bewusst IMMER genau zwei Events nebeneinander. Gleiche
|
||
Karten-/Tag-Optik wie die 3 Welt-Kacheln, damit es wie ein natürlicher Abschluss des
|
||
Grids wirkt statt wie ein fremdes Element. */
|
||
/* Die umgebende Kiste ist seit 27.08.2026 rahmenlos. Vorher trug sie
|
||
Hintergrund UND Rahmen, und die Event-Karte darin trug beides noch
|
||
einmal — zwei Rahmen um denselben Inhalt, dazwischen tote Fläche. Die
|
||
Karte allein trägt das Design jetzt besser; die Überschrift steht frei
|
||
darüber. */
|
||
.jahres-events {
|
||
margin-top: 1.8rem;
|
||
background: none;
|
||
border: 0;
|
||
padding: 0;
|
||
box-shadow: none;
|
||
}
|
||
.jahres-events-head { margin-bottom: .9rem; }
|
||
/* Ohne die umgebende Kiste stand die Überschrift als nackter Text
|
||
zwischen zwei Kacheln und wirkte verloren. Als goldene Plakette gehört
|
||
sie sichtbar zur Event-Karte darunter — gedecktes Gold, kein grelles
|
||
Leuchten (Projektregel: augenschonend). */
|
||
.jahres-events-head .tag {
|
||
display: inline-block;
|
||
padding: .34rem .95rem;
|
||
border-radius: 999px;
|
||
border: 1px solid rgba(212, 175, 55, .38);
|
||
background: rgba(212, 175, 55, .09);
|
||
color: #e8c465;
|
||
font-size: .82rem;
|
||
font-weight: 700;
|
||
letter-spacing: .04em;
|
||
}
|
||
.jahres-events-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 1.2rem;
|
||
}
|
||
@media (max-width: 760px) { .jahres-events-grid { grid-template-columns: 1fr; } }
|
||
/* Nutzer-Wunsch 20.08.2026: "die kacheln sollen auch bissl spezieller sein" —
|
||
goldener Trophäen-Akzent statt der neutralen Standard-Kartenoptik (eigener,
|
||
gedeckter Farbton, kein grelles Gold — augenschonend), plus ein dezenter
|
||
wandernder Lichtschimmer oben (".jahres-event-shine"), der die Kachel als
|
||
etwas Besonderes markiert statt als normale Karte. Jetzt ein <button>
|
||
(öffnet ein Detail-Fenster) statt eines <a> (navigierte sofort weg) —
|
||
deshalb hier zusätzlich ein vollständiger Button-Reset. */
|
||
/* [hidden] explizit VOR der Klassenregel + als eigene Regel danach: ein
|
||
simples "display:block" in .jahres-event-card hat dieselbe Spezifität
|
||
wie die eingebaute [hidden]-UA-Regel des Browsers und würde sie sonst im
|
||
Zweifel überschreiben (identischer Bug wie schon bei .jahres-event-bild
|
||
weiter unten, hier per Playwright-Screenshot erneut gefunden — eine
|
||
"leere" Kachel blieb trotz hidden-Attribut sichtbar). */
|
||
.jahres-event-card[hidden] { display: none; }
|
||
.jahres-event-card {
|
||
display: block;
|
||
width: 100%;
|
||
text-align: left;
|
||
font: inherit;
|
||
color: inherit;
|
||
cursor: pointer;
|
||
position: relative;
|
||
overflow: hidden;
|
||
isolation: isolate;
|
||
padding: 1.2rem 1.4rem;
|
||
border-radius: var(--radius);
|
||
border: 1px solid rgba(212, 175, 55, .35);
|
||
/* Die Karte steht jetzt ohne umgebende Kiste direkt über dem Artwork
|
||
und muss ihren Hintergrund selbst mitbringen — vorher genügte ein
|
||
Hauch Weiß, weil die Kiste darunter ohnehin deckend war. Deckend
|
||
genug für ruhigen Lesetext, mit einer Spur Milchglas, damit die Karte
|
||
zur Seite gehört statt wie ein Aufkleber darauf zu liegen. */
|
||
background:
|
||
radial-gradient(circle at 12% 0%, rgba(212, 175, 55, .10), transparent 58%),
|
||
linear-gradient(180deg, rgba(19, 23, 31, .90), rgba(13, 16, 22, .94));
|
||
-webkit-backdrop-filter: blur(6px);
|
||
backdrop-filter: blur(6px);
|
||
box-shadow: 0 14px 40px rgba(0, 0, 0, .38);
|
||
transition: border-color .2s ease, transform .2s ease, box-shadow .2s ease;
|
||
}
|
||
.jahres-event-card:hover, .jahres-event-card:focus-visible {
|
||
border-color: rgba(212, 175, 55, .7);
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 10px 26px rgba(0, 0, 0, .35), 0 0 22px rgba(212, 175, 55, .18);
|
||
}
|
||
.jahres-event-shine {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0; left: 6%; right: 6%;
|
||
height: 1px;
|
||
background: linear-gradient(90deg, transparent, rgba(255, 214, 102, .9), transparent);
|
||
animation: jahres-event-goldglanz 4.5s ease-in-out infinite;
|
||
pointer-events: none;
|
||
}
|
||
@keyframes jahres-event-goldglanz { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
|
||
@media (prefers-reduced-motion: reduce) { .jahres-event-shine { animation: none; opacity: .6; } }
|
||
/* Datum als gesperrte Versalzeile: eine Zeitangabe ist eine Marke, keine
|
||
Überschrift. So ordnet sie sich dem Titel unter, statt mit ihm zu
|
||
konkurrieren (Feinschliff 27.08.2026). */
|
||
.jahres-event-datum {
|
||
display: block;
|
||
color: #d9b45c;
|
||
font-weight: 700;
|
||
font-size: .72rem;
|
||
letter-spacing: .14em;
|
||
text-transform: uppercase;
|
||
margin-bottom: .3rem;
|
||
}
|
||
.jahres-event-card h3 { margin: 0 0 .4rem; font-size: 1.15rem; }
|
||
.jahres-event-card p { margin: 0 0 .6rem; color: var(--text-muted); font-size: .93rem; line-height: 1.55; }
|
||
/* Der Text kommt aus der Verwaltung und kann beliebig lang sein. Fünf
|
||
Zeilen halten die Karte in Form, egal was jemand einträgt — der
|
||
vollständige Text steht ohnehin im Fenster, das ein Klick öffnet.
|
||
Ohne diese Grenze bestimmt die Textlänge das Aussehen der Startseite,
|
||
und bei zwei Events stünden zwei unterschiedlich hohe Kacheln
|
||
nebeneinander. Gekürzt wird mit Auslassungspunkten, nicht mit einer
|
||
mitten durchgeschnittenen Zeile (siehe Hülle in index.html). */
|
||
.jahres-event-textwrap p {
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 5;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
/* "Mehr erfahren" war ein nackter Textlink in einer Karte, die man als
|
||
Ganzes anklickt — er sah aus wie vergessener Fließtext. Als ruhiger
|
||
Knopf ist sofort klar, dass hier etwas passiert; er reagiert mit der
|
||
ganzen Karte, weil die Karte selbst der Schalter ist. */
|
||
.jahres-event-mehr {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: .45rem;
|
||
padding: .52rem 1.05rem;
|
||
border-radius: 999px;
|
||
border: 1px solid rgba(212, 175, 55, .40);
|
||
background: rgba(212, 175, 55, .07);
|
||
color: #e8c465;
|
||
font-weight: 600;
|
||
font-size: .86rem;
|
||
transition: background .18s ease, border-color .18s ease;
|
||
}
|
||
.jahres-event-card:hover .jahres-event-mehr,
|
||
.jahres-event-card:focus-visible .jahres-event-mehr {
|
||
background: rgba(212, 175, 55, .14);
|
||
border-color: rgba(212, 175, 55, .65);
|
||
}
|
||
/* Das Bild bekommt eine Haarlinie als Rahmen — ohne sie schwimmt eine
|
||
dunkle Fotokante im dunklen Kartenhintergrund. */
|
||
.jahres-event-bild:not([hidden]) { border: 1px solid rgba(255, 255, 255, .07); }
|
||
/* Genau EIN aktives Event (27.08.2026 neu gebaut).
|
||
|
||
VORHER: eine 480px schmale Kachel, zentriert in einer 1180px breiten
|
||
Kiste. Links und rechts davon standen je 350px totes Dunkelgrau, und
|
||
weil die Kiste selbst schon Rahmen und Hintergrund hatte, saß eine
|
||
gerahmte Karte in einer gerahmten Kiste in einem Container — drei
|
||
Rahmen ineinander um einen einzigen Inhalt ("sieht irgendwie scheisse
|
||
aus", 27.08.2026).
|
||
|
||
JETZT: Die Karte nimmt die volle Breite ein und teilt sich in Bild
|
||
links / Text rechts. Das Bild ist das Beste am Event -- es bekommt
|
||
Platz statt Briefmarkenformat, und die leere Fläche verschwindet, weil
|
||
der Text sie füllt. Ab 900px abwärts wird daraus wieder
|
||
untereinander, sonst würden beide Spalten zu schmal. */
|
||
.jahres-events-grid-einzeln { grid-template-columns: 1fr; }
|
||
/* ⚠️ :not([hidden]) ist hier PFLICHT, nicht Deko.
|
||
".jahres-event-card[hidden]{display:none}" weiter oben hat die Stärke
|
||
Klasse+Attribut. Eine Regel "Klasse Klasse" wie diese hier ist exakt
|
||
gleich stark und steht später in der Datei — sie hätte das Verstecken
|
||
also ausgehebelt und die zweite, leere Event-Kachel wieder sichtbar
|
||
gemacht. Genau das ist beim ersten Entwurf passiert (im Bild stand
|
||
eine leere Kachel mit einsamem "Mehr erfahren →"). Im Code stand die
|
||
Warnung davor schon zweimal; sie stimmt. */
|
||
.jahres-events-grid-einzeln .jahres-event-card:not([hidden]) {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
|
||
/* Zeilen nach Inhalt, Block als Ganzes mittig: sonst verteilt das
|
||
Raster Datum/Titel/Text/Link über die volle Bildhöhe und der Text
|
||
steht auseinandergezogen wie eine Liste statt als Absatz. */
|
||
grid-template-rows: repeat(4, max-content);
|
||
align-content: center;
|
||
column-gap: 1.7rem;
|
||
row-gap: .1rem;
|
||
padding: 1.5rem;
|
||
}
|
||
.jahres-events-grid-einzeln .jahres-event-bild:not([hidden]) {
|
||
margin-bottom: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
min-height: 230px;
|
||
aspect-ratio: auto;
|
||
align-self: stretch;
|
||
object-fit: cover;
|
||
}
|
||
/* Datum, Titel, Text und "Mehr erfahren" bilden die zweite Spalte. Sie
|
||
stehen im HTML als Geschwister nebeneinander, deshalb hier ein eigenes
|
||
Unter-Raster statt eines zusätzlichen <div> 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 <h2> (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 <h2> (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 <h4>, 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:
|
||
|
||
<section class="hero page-bg"
|
||
style="--page-bg:url('assets/img/bg-x.jpg');
|
||
--page-bg-mobile:url('assets/img/bg-x-mobile.jpg');">
|
||
|
||
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 <img> 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 <img width:100% height:auto>, 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.
|
||
|
||
<section class="hero page-bg">
|
||
<div class="hero-banner"><img src="assets/img/bg-x.jpg" alt="" /></div>
|
||
<div class="container">...</div>
|
||
</section>
|
||
|
||
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 <linearGradient> 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 <img> 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); }
|