/* willers.one - Motiv der oeffentlichen Startseite
   Dunkler, wandernder Farbhintergrund mit Koernung. Gehoert nur zur
   Startseite (index.html); das Board selbst nutzt /assets/shell.css. */

:root { --win-text: #ece9f2; }

*, *::before, *::after { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
}

/* Die dunkle Grundflaeche gehoert an <html>, nicht nur an <body>.
   Auf den Wegpunkte-Seiten ist body bewusst transparent, damit die
   App-Flaechenfarbe den Hintergrund nicht ueberdeckt - ohne Farbe am <html>
   faellt die Leinwand dann auf das Browser-Weiss zurueck. Gilt in beiden
   Ansichten: der Bereich ausserhalb des Fensters bleibt immer dunkel,
   er ist der Bildhintergrund. */
html {
    background: #050506;
}

body {
    background: #050506;
    color: var(--win-text);
    font-family: "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif;
    overflow: hidden;
}

/* ---------- Hintergrund ---------- */

.bg {
    position: fixed;
    inset: -20%;
    z-index: 0;
    filter: blur(90px) saturate(120%);
    will-change: transform;
    pointer-events: none;
}

.blob {
    /* --ax/--ay steuern die Reichweite. Die Keyframes rechnen nur mit diesen
       Variablen, dadurch laesst sich der Weg pro Seitentyp anpassen, ohne die
       Keyframes zu verdoppeln. */
    --ax: 38vw;
    --ay: 32vh;

    position: absolute;
    inset: 0;
    margin: auto;
    border-radius: 50%;
    mix-blend-mode: screen;
    opacity: .62;
}

/* Kompakter Kern statt weit auslaufendem Rand: die Farbe haelt bis 40% und
   faellt dann zuegig ab. So gibt es einen erkennbaren Fleck, der wandert,
   statt eines flaechigen Schleiers, der sich kaum veraendert. */
.blob.a {
    width: 56vmax; height: 56vmax;
    background: radial-gradient(circle at 50% 50%, #8d1522 0%, #4a0a12 40%, transparent 68%);
    animation: roamA 52s ease-in-out infinite;
}

.blob.b {
    width: 60vmax; height: 60vmax;
    background: radial-gradient(circle at 50% 50%, #123a7a 0%, #08182f 40%, transparent 68%);
    animation: roamB 64s ease-in-out infinite;
}

.blob.c {
    width: 48vmax; height: 48vmax;
    background: radial-gradient(circle at 50% 50%, #4a1740 0%, #200a1e 40%, transparent 68%);
    animation: roamC 58s ease-in-out infinite;
}

/* Jede Farbe laeuft einen vollen Rundlauf ueber alle vier Ecken - Rot im
   Uhrzeigersinn, Blau gegenlaeufig und um eine halbe Runde versetzt, Violett
   quer durch die Mitte. Erster und letzter Keyframe sind gleich, damit die
   Schleife nahtlos ist (deshalb kein "alternate"). Die drei Laufzeiten sind
   unterschiedlich, so wiederholt sich das Zusammenspiel erst nach Stunden. */
@keyframes roamA {
    0%   { transform: translate3d(calc(var(--ax) * -1),   calc(var(--ay) * -.85), 0) scale(1);    opacity: .60; }
    25%  { transform: translate3d(calc(var(--ax) * .95),  calc(var(--ay) * -.75), 0) scale(1.14); opacity: .76; }
    50%  { transform: translate3d(calc(var(--ax) * .85),  calc(var(--ay) * .90),  0) scale(1.02); opacity: .54; }
    75%  { transform: translate3d(calc(var(--ax) * -.90), calc(var(--ay) * .85),  0) scale(1.16); opacity: .72; }
    100% { transform: translate3d(calc(var(--ax) * -1),   calc(var(--ay) * -.85), 0) scale(1);    opacity: .60; }
}

@keyframes roamB {
    0%   { transform: translate3d(calc(var(--ax) * .95),  calc(var(--ay) * .85),  0) scale(1.10); opacity: .72; }
    25%  { transform: translate3d(calc(var(--ax) * -.95), calc(var(--ay) * .90),  0) scale(.96);  opacity: .54; }
    50%  { transform: translate3d(calc(var(--ax) * -1),   calc(var(--ay) * -.80), 0) scale(1.14); opacity: .74; }
    75%  { transform: translate3d(calc(var(--ax) * .90),  calc(var(--ay) * -.90), 0) scale(.98);  opacity: .52; }
    100% { transform: translate3d(calc(var(--ax) * .95),  calc(var(--ay) * .85),  0) scale(1.10); opacity: .72; }
}

@keyframes roamC {
    0%   { transform: translate3d(0,                      calc(var(--ay) * -1),   0) scale(1.05); opacity: .48; }
    25%  { transform: translate3d(calc(var(--ax) * 1),    calc(var(--ay) * .12),  0) scale(1.20); opacity: .66; }
    50%  { transform: translate3d(0,                      calc(var(--ay) * 1),    0) scale(1);    opacity: .46; }
    75%  { transform: translate3d(calc(var(--ax) * -1),   calc(var(--ay) * -.12), 0) scale(1.18); opacity: .64; }
    100% { transform: translate3d(0,                      calc(var(--ay) * -1),   0) scale(1.05); opacity: .48; }
}

.vignette {
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(ellipse at center, transparent 20%, rgba(0,0,0,.62) 68%, #000 100%);
}

.grain {
    position: fixed;
    inset: -50%;
    z-index: 2;
    pointer-events: none;
    opacity: .045;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
    animation: grain 1.2s steps(4) infinite;
}

@keyframes grain {
    0%, 100% { transform: translate(0, 0); }
    25%      { transform: translate(-2%, 1%); }
    50%      { transform: translate(1%, -2%); }
    75%      { transform: translate(2%, 2%); }
}

/* Auf Fensterseiten ist vom Hintergrund nur der schmale Rand zu sehen.
   Kleinere, kraeftigere Wolken und weniger Weichzeichnung sorgen dafuer,
   dass dort ueberhaupt Bewegung erkennbar bleibt - und kosten nebenbei
   deutlich weniger Rechenleistung als die grossen. */
/* Im Fenstermodus ist nur der schmale Rand sichtbar. Damit dort ueberhaupt
   Farbe ankommt, muessen die Kerne bis ueber die Fensterkante hinauslaufen -
   deshalb deutlich groessere Reichweite und weniger Weichzeichnung. Kleinere
   Wolken kosten dabei zugleich weniger Rechenleistung. */
body.framed .bg     { filter: blur(46px) saturate(140%); }
body.framed .blob   { --ax: 52vw; --ay: 46vh; opacity: .78; }
body.framed .blob.a { width: 40vmax; height: 40vmax; }
body.framed .blob.b { width: 44vmax; height: 44vmax; }
body.framed .blob.c { width: 34vmax; height: 34vmax; }

/* Keine Vignette im Fenstermodus: sie dunkelt genau den Rand ab, in dem
   der Hintergrund ueberhaupt zu sehen ist. */
body.framed .vignette { display: none; }

/* Waehrend die Karte gezogen wird, steht der Hintergrund still. */
body.bg-paused .blob,
body.bg-paused .grain { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
    .blob, .grain { animation: none; }
}
