Files
dogfather-universe/workspace/assets/css/unsere-seiten.css
T
DogFatherGitandClaude Opus 5 eca9aed279 Der Treff sagt jetzt, ob gerade gestreamt wird
Filipe zu dieser Seite: "mach was anderes daraus oder mach es viel
krass und geiler ... erstell was was mich von den socken schmeisst. es
soll wirklich sogar ein wow effekt fuer die community ergeben." Dazu
die eine Auflage: die Kachel bleibt.

WAS SIE WAR: zwei Karten mit zwei Adressen. Sauber gebaut, richtig
beschriftet -- und niemand kam ein zweites Mal wieder. Wer im Treff
ist, kennt die Website. Den Rabattcode merkt man sich beim ersten Mal.

DIE FRAGE, DIE WIRKLICH JEMAND HAT, IST EINE ANDERE: Laeuft er
gerade? Und wenn nicht -- wie lange noch? Die Antwort kennt das Haus
seit dem 20.08.: postfach.dogfather-universe.com/live-status, derselbe
Dienst, von dem der oeffentliche Streamplan lebt. Im Treff gab es sie
bisher nicht.

Jetzt steht oben ein Puls: ein Ring, der sich ueber den Tag bis zur
naechsten Sendezeit fuellt, darin der Countdown auf die Sekunde. Sendet
er, wird die Karte rot, atmet im Ruhepuls und traegt den Titel des
Streams plus einen Weg hin. Darunter die drei Accounts und -- wenn die
Verwaltung eines eintraegt -- das besondere Event mit eigener Uhr.

DREI AUSGAENGE, NICHT ZWEI. Das ist der eigentliche Unterschied zur
oeffentlichen Seite: streamplan.js faengt dort jeden Fehler ab und
setzt `istLive = false`. Aus "wir konnten nicht fragen" wird "er sendet
nicht" -- und wer das liest, macht die Seite zu und verpasst den
Stream. Der Dienst liefert `autoHealthy` sogar mit; gelesen wird es
draussen nicht. Hier schon: Bei einer Stoerung steht "Konnten wir
gerade nicht nachsehen", dazu der Hinweis, dass das NICHT heisst, dass
kein Stream laeuft. Der Countdown laeuft dabei weiter -- er braucht
kein Netz.

NICHTS IST ABGESCHRIEBEN. Die drei Accounts kommen ueber
/workspace/api/draussen aus derselben KANAELE-Liste, an der die
Aufgabenverteilung haengt; die Adressen baut der Steckbrief. Die
Sendezeit steht im Server, und pruef-draussen haelt sie gegen
FIX_STUNDE in streamplan.js -- verschiebt jemand den Termin und aendert
nur einen Ort, wird die Pruefung rot.

Gemessen, bevor gebaut wurde: der Dienst antwortet und meldet sich
gesund, CORS steht auf *, und `connect-src` der Treff-Seiten fuehrt
postfach bereits. Ohne das Letzte waere der Abruf still blockiert
worden und haette ausgesehen wie ein toter Dienst.

Die Kachel heisst jetzt "Draussen" statt "Unsere Seiten" -- drei Dinge
statt zwei Adressen. Ziel und Datei bleiben gleich.
pruef-wege-nach-draussen schreibt den Namen nicht mehr ab, sondern
verlangt, dass Kachel und Seitenueberschrift uebereinstimmen. Zwei
Namen fuer denselben Ort waren schon einmal ein echter Fehler.

Nebenbefund, dort gleich behoben: Dieselbe Pruefung verlangte, dass
die Community-Kacheln restlos in Dreierreihen aufgehen -- obwohl ihr
eigener Kommentar sagt, eine freie Zelle am Ende sei erlaubt. Sie war
rot bei einwandfreiem Raster. Gemessen wird jetzt, was wirklich
schiefgeht: eine doppelt breite Kachel, die in der letzten Spalte
beginnt und die Zelle davor leer laesst. Mit Gegenprobe.

pruef-draussen: 39 Pruefungen, alle vier Lagen im echten Browser --
die Stoerung wird dafuer absichtlich hergestellt.
pruef-wege-nach-draussen: 67 statt 66, keine Fehler mehr.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 12:06:23 +02:00

798 lines
24 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =====================================================================
UNSERE SEITEN (19.09.2026)
Zwei Karten, die aus dem Treff hinausführen: die Website und
VanVans Shop.
WARUM SIE ANDERS AUSSEHEN ALS DIE BRETTER-KACHELN: Sie tun etwas
anderes. Eine Brett-Kachel öffnet eine Liste im selben Fenster; diese
hier verlassen den Treff. Dass man das vorher sieht, ist kein
Schmuck, sondern die Ansage — deshalb der eigene Zuschnitt, der
deutlich sichtbare Adressname und der Pfeil nach außen.
AUGENSCHONEND, WIE ÜBERALL IM HAUS: Die Farbe liegt im Verlauf und
im Rand, nie in einer leuchtenden Fläche hinter Text. Bewegung gibt
es nur beim Darüberfahren, und `prefers-reduced-motion` schaltet sie
ganz ab.
===================================================================== */
.seiten-gitter {
display: grid;
gap: 1.1rem;
/* EINE REGEL STATT EINER ZAHL. Zwei Spalten, sobald zweimal 21rem
plus Abstand hineinpassen — und sonst eine. Kommt eine dritte
Karte dazu, ordnet sich das von selbst, ohne dass jemand eine
Schwelle nachziehen muss. */
grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr));
margin: 1.4rem 0 0;
}
.aussen {
position: relative;
isolation: isolate;
overflow: hidden;
display: flex;
flex-direction: column;
gap: .75rem;
padding: 1.35rem 1.35rem 1.2rem;
border-radius: 1.1rem;
border: 1px solid color-mix(in srgb, var(--aussen-ton) 42%, transparent);
/* DREI LAGEN STATT ZWEI (19.09.2026). Filipe: "auch der hintegrrund
der kacheln, ich will es viel spezieller".
Vorher lag der Ton mit 7 % auf der Flaeche -- auf einem dunklen
Bildschirm sieht man davon fast nichts, die Kachel wirkte grau.
Jetzt: ein heller Bogen oben links (woher das Licht kommt), ein
zweiter, schwacher unten rechts (damit die Flaeche nicht flach
kippt) und ein Grundverlauf, der den Ton wirklich traegt.
Nach oben begrenzt bleibt es trotzdem: Der hellste Punkt liegt bei
28 %, und Text steht nie darauf -- er hat seine eigene Lage. */
background:
radial-gradient(120% 95% at 6% -5%,
color-mix(in srgb, var(--aussen-ton) 28%, transparent), transparent 58%),
radial-gradient(90% 80% at 105% 110%,
color-mix(in srgb, var(--aussen-ton) 16%, transparent), transparent 62%),
linear-gradient(158deg,
color-mix(in srgb, var(--aussen-ton) 14%, #0c1420),
#090f1a 72%);
box-shadow:
0 18px 38px -20px color-mix(in srgb, var(--aussen-ton) 85%, transparent),
inset 0 1px 0 color-mix(in srgb, var(--aussen-ton) 22%, transparent);
cursor: pointer;
transition: transform .22s ease, border-color .22s ease, box-shadow .22s ease;
}
/* Die Töne der beiden Karten. Sie stehen hier und nicht im HTML,
damit eine dritte Karte eine Zeile braucht und nicht zehn.
BABYBLAU UND LILA seit dem 19.09.2026 (Filipe: „die linke kachel soll
babyblau sein und rechte lila").
Babyblau ist im Haus schon vergeben — es ist der Ton der Sekunde auf
der Uhr (#7ec8f2), und dieselbe Farbe zweimal anders zu treffen wäre
schlampig. Also derselbe Wert.
Das Lila ist dasselbe, in das an diesem Tag die Stunden der Uhr
umgerechnet wurden (OKLCH-Farbton 303°). Beide Kacheln sprechen
damit die Sprache, die die Startseite ohnehin spricht.
`--logo` nennt die Maske. Sie steht an der Karte und nicht am
Logofeld, damit eine dritte Karte nur diese zwei Zeilen braucht. */
.aussen--dogi {
--aussen-ton: #7ec8f2;
--logo: url("/assets/img/marke/maske-dogi.png");
}
.aussen--shop {
--aussen-ton: #b284ec;
--logo: url("/assets/img/marke/maske-vanvan.png");
}
/* ---- DIE SCHWEBENDEN LOGOS ------------------------------------------
Vier Stück je Karte, verschieden groß, verschieden schnell, mit
verschiedener Verzögerung. Gleich wäre Tapete.
SIE LIEGEN UNTER ALLEM (`z-index: 0` im eigenen Kontext, Text
darüber). Die Deckkraft liegt zwischen 10 und 16 Prozent — der erste
Versuch mit 5 bis 9 war auf dem Bildschirmfoto praktisch unsichtbar,
und „soll mega aussehen" heißt nicht „soll man erahnen können".
Nach oben ist trotzdem eine Grenze: Ab etwa 25 Prozent fängt das
Logo an, mit der Überschrift zu konkurrieren, und der Text wird
mühsam. Was hier entstehen soll, ist Tiefe, kein zweiter Titel.
`mask-image` statt `background-image`: Die PNG-Dateien tragen nur
Alpha. Die Farbe ist `currentColor` der Karte — dadurch ist das
Logo automatisch babyblau bzw. lila, ohne zweite Datei. */
.logo-feld {
position: absolute;
inset: 0;
z-index: 0;
overflow: hidden;
border-radius: inherit;
pointer-events: none;
}
.logo-feld__stueck {
position: absolute;
background-color: var(--aussen-ton);
-webkit-mask-image: var(--logo);
mask-image: var(--logo);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-position: center;
mask-position: center;
will-change: transform;
}
/* Die vier Lagen. Die Zahlen sind gesetzt, nicht gerechnet — ein
Zufallsgenerator würde bei jedem Laden anders aussehen, und dann
fällt niemandem mehr auf, wenn eines daneben liegt. */
.logo-feld__stueck[data-n="1"] {
width: 15rem; height: 15rem; right: -4.5rem; top: -3.5rem;
opacity: .16;
animation: logo-schweben-a 26s ease-in-out infinite;
}
.logo-feld__stueck[data-n="2"] {
width: 8rem; height: 8rem; right: 4.5rem; bottom: -1.5rem;
opacity: .13;
animation: logo-schweben-b 34s ease-in-out infinite;
animation-delay: -6s;
}
.logo-feld__stueck[data-n="3"] {
width: 5rem; height: 5rem; right: 12rem; top: 35%;
opacity: .105;
animation: logo-schweben-a 41s ease-in-out infinite;
animation-delay: -15s;
}
.logo-feld__stueck[data-n="4"] {
width: 3.4rem; height: 3.4rem; right: 2rem; top: 18%;
opacity: .14;
animation: logo-schweben-b 29s ease-in-out infinite;
animation-delay: -21s;
}
/* ZWEI BAHNEN, NICHT EINE. Mit nur einer bewegten sich alle vier
gleich — das sieht aus, als wackle die ganze Kachel. Die zweite
läuft andersherum, dadurch entsteht der Eindruck, dass sie
unabhängig voneinander treiben.
SEHR KLEINE WEGE (unter 14 px) und sehr lange Dauern (26–41 s). Was
man beim Hinsehen als Bewegung erkennt, lenkt beim Lesen ab. Das hier
merkt man erst, wenn man zweimal hinschaut — und genau das ist
gemeint mit „ganz leicht bewegen". */
@keyframes logo-schweben-a {
0% { transform: translate3d(0, 0, 0) rotate(0deg); }
33% { transform: translate3d(-9px, -11px, 0) rotate(2.5deg); }
66% { transform: translate3d(7px, -5px, 0) rotate(-1.8deg); }
100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}
@keyframes logo-schweben-b {
0% { transform: translate3d(0, 0, 0) rotate(0deg); }
40% { transform: translate3d(8px, 9px, 0) rotate(-3deg); }
75% { transform: translate3d(-6px, 4px, 0) rotate(1.5deg); }
100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}
/* Wer weniger Bewegung will, bekommt die Logos trotzdem — nur still.
Sie ganz zu entfernen wäre falsch: Sie sind Gestaltung, nicht
Animation. */
@media (prefers-reduced-motion: reduce) {
.logo-feld__stueck { animation: none; }
}
/* Der stille Schein im Hintergrund. Liegt UNTER allem (`z-index: -1`)
und ist so schwach, dass er bei Tageslicht kaum auffällt — er soll
Tiefe geben, nicht leuchten. */
.aussen__schein {
position: absolute;
inset: -40% -20% auto -20%;
height: 78%;
z-index: -1;
background: radial-gradient(60% 60% at 50% 50%,
color-mix(in srgb, var(--aussen-ton) 34%, transparent), transparent 70%);
filter: blur(30px);
opacity: .7;
pointer-events: none;
}
.aussen:hover,
.aussen:focus-within {
transform: translateY(-3px);
border-color: color-mix(in srgb, var(--aussen-ton) 52%, transparent);
box-shadow: 0 22px 40px -20px color-mix(in srgb, var(--aussen-ton) 85%, transparent);
}
/* ALLES, WAS MAN LIEST, LIEGT ÜBER DEN LOGOS. Ohne diese Zeile wandert
der Text unter das Logofeld, sobald es eine eigene Ebene bekommt —
die Karte sähe dann leer aus, und man sucht den Fehler beim Text. */
.aussen > *:not(.logo-feld):not(.aussen__schein) {
position: relative;
z-index: 1;
}
.aussen__kopf {
display: flex;
align-items: center;
gap: .85rem;
}
.aussen__zeichen {
flex: 0 0 auto;
display: grid;
place-items: center;
width: 3rem;
height: 3rem;
border-radius: .8rem;
border: 1px solid color-mix(in srgb, var(--aussen-ton) 38%, transparent);
background: linear-gradient(150deg,
color-mix(in srgb, var(--aussen-ton) 20%, transparent), transparent 74%);
}
.aussen__zeichen svg {
width: 1.65rem;
height: 1.65rem;
fill: none;
stroke: color-mix(in srgb, var(--aussen-ton) 78%, #dceaf8);
stroke-width: 1.6;
stroke-linecap: round;
stroke-linejoin: round;
}
.aussen__marke {
margin: 0 0 .1rem;
font-size: .74rem;
letter-spacing: .12em;
text-transform: uppercase;
color: color-mix(in srgb, var(--aussen-ton) 55%, #9fb4c9);
}
.aussen__titel {
margin: 0;
font-size: 1.32rem;
line-height: 1.2;
/* Text bleibt hell und ruhig. Die Farbe steckt im Rahmen, nicht in
der Schrift — farbige Überschriften auf dunklem Grund sind der
schnellste Weg zu müden Augen. */
color: #e9f2fb;
}
.aussen__satz {
margin: 0;
color: var(--text-leise, #93a7bd);
font-size: .95rem;
line-height: 1.5;
}
/* Was es auf der Seite gibt. Ruhig gesetzt: Der Punkt links ist ein
kleiner Strich in der Kartenfarbe, kein Aufzählungszeichen — vier
bunte Punkte untereinander wären mehr Unruhe als Information. */
.aussen__liste {
margin: .1rem 0 .2rem;
padding: 0;
list-style: none;
display: grid;
gap: .42rem;
}
.aussen__liste li {
position: relative;
padding-left: 1.05rem;
font-size: .89rem;
line-height: 1.45;
color: var(--text-leise, #93a7bd);
}
.aussen__liste li::before {
content: "";
position: absolute;
left: 0;
top: .62em;
width: .5rem;
height: 1px;
background: color-mix(in srgb, var(--aussen-ton) 60%, transparent);
}
.aussen__weg {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: .6rem;
margin: auto 0 0;
padding-top: .35rem;
}
.aussen__adresse {
font-size: .82rem;
color: color-mix(in srgb, var(--aussen-ton) 45%, #8ea3b9);
word-break: break-all;
}
.aussen__knopf {
flex: 0 0 auto;
display: inline-block;
padding: .55rem 1rem;
border-radius: .6rem;
border: 1px solid color-mix(in srgb, var(--aussen-ton) 45%, transparent);
background: color-mix(in srgb, var(--aussen-ton) 14%, transparent);
color: #eaf3fc;
font-weight: 600;
font-size: .92rem;
text-decoration: none;
/* 44 px hoch, damit ein Daumen ihn trifft. */
min-height: 2.75rem;
display: inline-flex;
align-items: center;
transition: background-color .18s ease, border-color .18s ease;
}
.aussen__knopf:hover,
.aussen__knopf:focus-visible {
background: color-mix(in srgb, var(--aussen-ton) 26%, transparent);
border-color: color-mix(in srgb, var(--aussen-ton) 68%, transparent);
}
/* ---- DER GUTSCHEIN ---------------------------------------------------
Sieht aus wie ein abgerissener Abschnitt, weil genau das gemeint
ist: etwas zum Mitnehmen. Die gestrichelte Linie ist das einzige
Stilmittel — sie sagt "hier abtrennen", ohne ein Wort dafür zu
brauchen. */
.gutschein {
margin: .2rem 0 .1rem;
padding: .9rem 1rem 1rem;
border-radius: .8rem;
border: 1px dashed color-mix(in srgb, var(--aussen-ton) 42%, transparent);
background: color-mix(in srgb, var(--aussen-ton) 8%, transparent);
}
.gutschein__zeile {
display: flex;
align-items: baseline;
gap: .55rem;
margin: 0 0 .6rem;
}
.gutschein__prozent {
font-size: 1.5rem;
font-weight: 700;
line-height: 1;
color: #f2f7fc;
}
.gutschein__wofuer {
font-size: .88rem;
color: var(--text-leise, #93a7bd);
}
.gutschein__code {
display: flex;
align-items: center;
justify-content: space-between;
gap: .7rem;
width: 100%;
min-height: 3rem;
padding: .6rem .9rem;
border-radius: .6rem;
border: 1px solid color-mix(in srgb, var(--aussen-ton) 50%, transparent);
background: rgba(255, 255, 255, .04);
color: #f2f7fc;
cursor: pointer;
text-align: left;
transition: background-color .18s ease, border-color .18s ease;
}
.gutschein__code:hover,
.gutschein__code:focus-visible {
background: rgba(255, 255, 255, .08);
border-color: color-mix(in srgb, var(--aussen-ton) 72%, transparent);
}
.gutschein__wort {
font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
font-size: 1.22rem;
font-weight: 700;
letter-spacing: .1em;
}
.gutschein__hinweis {
font-size: .78rem;
color: var(--text-leise, #93a7bd);
text-align: right;
}
/* Nach dem Kopieren steht dort die Bestätigung — in Grün, aber in
einem gedeckten, das auf Dunkel nicht sticht. */
.gutschein__code[data-kopiert="ja"] .gutschein__hinweis { color: #74c79a; }
.gutschein__klein {
margin: .6rem 0 0;
font-size: .78rem;
line-height: 1.45;
color: var(--text-leise, #93a7bd);
}
.seiten-fuss {
margin: 1.4rem 0 0;
font-size: .85rem;
color: var(--text-leise, #93a7bd);
}
/* Wer Bewegung ausgeschaltet hat, bekommt keine. Die Karte bleibt
trotzdem erkennbar bedienbar — über Rand und Schatten. */
@media (prefers-reduced-motion: reduce) {
.aussen,
.aussen__knopf,
.gutschein__code { transition: none; }
.aussen:hover,
.aussen:focus-within { transform: none; }
}
/* =====================================================================
DER PULS, DAS EVENT UND DIE KANAELE (21.09.2026)
Filipe wollte aus dieser Seite etwas machen, das "von den Socken
haut". Der Weg dahin war NICHT mehr Effekt, sondern eine Frage, die
vorher niemand beantwortet hat: Laeuft er gerade?
DESHALB LIEGT DER GANZE AUFWAND OBEN. Der Puls ist das Erste und
Groesste auf der Seite, und er ist das Einzige, was sich bewegt --
und zwar nur dann, wenn die Bewegung etwas bedeutet (er sendet).
Bewegung, die immer laeuft, ist Tapete; Bewegung, die genau einmal
im Tag anspringt, ist ein Signal.
AUGENSCHONEND WIE ALLES IM HAUS: Der Ton liegt im Verlauf, im Rand
und im Ring -- nie als leuchtende Flaeche hinter Text. Das Rot des
Live-Zustands ist ein gedecktes Korallrot (#e8736b), kein
Signalrot: Auf einem dunklen Bildschirm ist reines Rot nach zwei
Minuten unangenehm, und diese Seite soll man waehrend des Streams
offen lassen koennen.
`prefers-reduced-motion` schaltet jede Bewegung ab. Der Zustand
bleibt trotzdem erkennbar -- er steht in Farbe UND in Worten, nicht
nur im Puls. Eine Auskunft, die ausschliesslich an einer Animation
haengt, kommt bei einem Teil der Leute gar nicht an.
===================================================================== */
.puls {
position: relative;
isolation: isolate;
overflow: hidden;
display: flex;
align-items: center;
gap: 1.25rem;
margin: 1.5rem 0 0;
padding: 1.35rem 1.4rem;
border-radius: 1.1rem;
border: 1px solid color-mix(in srgb, var(--puls-ton) 42%, transparent);
background:
radial-gradient(120% 95% at 6% -5%,
color-mix(in srgb, var(--puls-ton) 26%, transparent), transparent 58%),
radial-gradient(90% 80% at 105% 110%,
color-mix(in srgb, var(--puls-ton) 15%, transparent), transparent 62%),
linear-gradient(158deg,
color-mix(in srgb, var(--puls-ton) 13%, #0c1420),
#090f1a 72%);
box-shadow:
0 18px 38px -20px color-mix(in srgb, var(--puls-ton) 85%, transparent),
inset 0 1px 0 color-mix(in srgb, var(--puls-ton) 22%, transparent);
transition: border-color .4s ease, box-shadow .4s ease;
}
/* DIE VIER LAGEN. Jede hat ihren Ton, und der Ton ist nie die einzige
Auskunft -- daneben steht immer ein Satz. Wer Farben nicht
unterscheidet, liest trotzdem, was los ist. */
.puls { --puls-ton: #7ec8f2; } /* laedt / wartet */
.puls[data-lage="live"] { --puls-ton: #e8736b; } /* er sendet */
.puls[data-lage="unklar"] { --puls-ton: #d9a441; } /* wir wissen es nicht */
/* Die Aura liegt UNTER allem und traegt die einzige Bewegung der
Seite. Sie ist nur im Live-Zustand sichtbar. */
.puls__aura {
position: absolute;
inset: -40%;
z-index: 0;
pointer-events: none;
opacity: 0;
background: radial-gradient(closest-side,
color-mix(in srgb, var(--puls-ton) 30%, transparent), transparent 70%);
transition: opacity .6s ease;
}
.puls[data-lage="live"] .puls__aura {
opacity: 1;
animation: puls-atmen 3.4s ease-in-out infinite;
}
/* 3,4 SEKUNDEN, NICHT EINE. Ein schneller Puls wirkt wie eine Warnung
und macht nervoes; dieser hier atmet ungefaehr im Ruhepuls eines
Menschen. Die Deckkraft schwankt zwischen 55 und 100 Prozent --
sichtbar, aber nicht blinkend. */
@keyframes puls-atmen {
0%, 100% { opacity: .55; transform: scale(1); }
50% { opacity: 1; transform: scale(1.06); }
}
.puls__ring-feld {
position: relative;
z-index: 1;
flex: 0 0 auto;
width: 5.6rem;
height: 5.6rem;
display: grid;
place-items: center;
}
.puls__ring {
width: 100%;
height: 100%;
/* Oben anfangen statt rechts -- so liest sich der Bogen wie eine
Uhr und nicht wie ein Tachometer. */
transform: rotate(-90deg);
}
.puls__ring-bahn {
fill: none;
stroke: color-mix(in srgb, var(--puls-ton) 18%, transparent);
stroke-width: 6;
}
.puls__ring-fortschritt {
fill: none;
stroke: var(--puls-ton);
stroke-width: 6;
stroke-linecap: round;
/* Der Umfang wird im Skript gesetzt -- aus dem Radius gerechnet,
damit eine Aenderung am SVG nicht hier nachgezogen werden muss. */
transition: stroke-dashoffset .6s ease;
}
.puls__punkt {
position: absolute;
width: .85rem;
height: .85rem;
border-radius: 50%;
background: var(--puls-ton);
opacity: .9;
}
.puls[data-lage="live"] .puls__punkt {
animation: puls-punkt 3.4s ease-in-out infinite;
}
@keyframes puls-punkt {
0%, 100% { transform: scale(1); opacity: .75; }
50% { transform: scale(1.35); opacity: 1; }
}
.puls__text {
position: relative;
z-index: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: .2rem;
}
.puls__marke {
margin: 0;
font-size: .78rem;
letter-spacing: .08em;
text-transform: uppercase;
color: color-mix(in srgb, var(--puls-ton) 70%, #cfe0f0);
}
.puls__lage {
margin: 0;
font-size: 1.05rem;
font-weight: 600;
color: #eaf3fb;
}
/* DIE ZAHL IST DAS GROESSTE AUF DER SEITE -- sie ist der Grund, warum
man wiederkommt. `tabular-nums` verhindert das Zappeln, das sonst
jede Sekunde entsteht, wenn eine 1 schmaler ist als eine 8. */
.puls__zahl {
margin: .1rem 0 0;
font-size: clamp(1.8rem, 6vw, 2.6rem);
font-weight: 700;
line-height: 1.1;
font-variant-numeric: tabular-nums;
letter-spacing: .01em;
color: #f4f9ff;
overflow-wrap: anywhere;
}
/* Im Live-Zustand steht dort der Titel des Streams, kein Countdown --
ein Satz in Countdown-Groesse wuerde umbrechen und die Karte
aufreissen. */
.puls[data-lage="live"] .puls__zahl {
font-size: clamp(1.1rem, 3.4vw, 1.45rem);
font-weight: 600;
}
.puls__klein {
margin: .25rem 0 0;
font-size: .82rem;
line-height: 1.45;
color: #9fb4c8;
}
.puls__knopf {
position: relative;
z-index: 1;
/* Rechts anschlagen, solange die Karte eine Zeile ist. Bricht sie um,
hebt `margin-left: 0` unten die Regel wieder auf. */
margin-left: auto;
flex: 0 0 auto;
/* 44 px ist die Grenze im Haus -- am Daumen, nicht an der Maus
gemessen. */
min-height: 44px;
display: inline-flex;
align-items: center;
padding: .55rem 1.05rem;
border-radius: .7rem;
border: 1px solid color-mix(in srgb, var(--puls-ton) 55%, transparent);
background: color-mix(in srgb, var(--puls-ton) 18%, transparent);
color: #f4f9ff;
font-weight: 600;
text-decoration: none;
transition: background .2s ease, border-color .2s ease, transform .2s ease;
}
.puls__knopf:hover {
background: color-mix(in srgb, var(--puls-ton) 28%, transparent);
border-color: color-mix(in srgb, var(--puls-ton) 75%, transparent);
}
.puls__knopf:focus-visible {
outline: 2px solid var(--puls-ton);
outline-offset: 2px;
}
/* AM HANDY UNTEREINANDER. Keine Schwelle in Pixeln, sondern die
Frage, ob der Text neben dem Ring noch lesbar ist: Unter 34rem
bleiben fuer ihn weniger als 20 Zeichen je Zeile. */
@media (max-width: 34rem) {
.puls { flex-direction: column; align-items: flex-start; gap: .9rem; }
.puls__ring-feld { width: 4.6rem; height: 4.6rem; }
/* In einer Spalte gibt es kein "rechts" -- der Knopf stellt sich
unter den Text und nimmt die volle Breite, damit er am Daumen
nicht gesucht werden muss. */
.puls__knopf { margin-left: 0; width: 100%; justify-content: center; }
}
/* Der Textblock nimmt den Platz, der zwischen Ring und Knopf uebrig
bleibt -- sonst draengt sich alles links zusammen. */
.puls__text { flex: 1 1 auto; }
/* ---- DAS BESONDERE EVENT ------------------------------------------- */
.event {
position: relative;
display: flex;
align-items: center;
gap: 1rem;
margin: .9rem 0 0;
padding: 1rem 1.2rem;
border-radius: 1rem;
--event-ton: #d49ae8;
border: 1px solid color-mix(in srgb, var(--event-ton) 45%, transparent);
background: linear-gradient(152deg,
color-mix(in srgb, var(--event-ton) 16%, #0c1420), #090f1a 78%);
}
.event[hidden] { display: none; }
.event__zeichen {
flex: 0 0 auto;
font-size: 1.5rem;
color: var(--event-ton);
line-height: 1;
}
.event__text { min-width: 0; }
.event__marke {
margin: 0;
font-size: .74rem;
letter-spacing: .08em;
text-transform: uppercase;
color: color-mix(in srgb, var(--event-ton) 75%, #cfe0f0);
}
.event__titel {
margin: .15rem 0 0;
font-size: 1.05rem;
font-weight: 600;
color: #eaf3fb;
}
.event__zahl {
margin: .2rem 0 0;
font-variant-numeric: tabular-nums;
font-size: .92rem;
color: #b9c9da;
}
.event[data-jetzt="ja"] .event__zahl {
color: #f4f9ff;
font-weight: 700;
}
.event__knopf {
margin-left: auto;
min-height: 44px;
display: inline-flex;
align-items: center;
padding: .5rem 1rem;
border-radius: .7rem;
border: 1px solid color-mix(in srgb, var(--event-ton) 55%, transparent);
background: color-mix(in srgb, var(--event-ton) 16%, transparent);
color: #f4f9ff;
text-decoration: none;
font-weight: 600;
}
.event__knopf:focus-visible { outline: 2px solid var(--event-ton); outline-offset: 2px; }
@media (max-width: 34rem) {
.event { flex-wrap: wrap; }
.event__knopf { margin-left: 0; width: 100%; justify-content: center; }
}
/* ---- DIE KANAELE ---------------------------------------------------- */
.kanaele { margin: 1.6rem 0 0; }
.kanaele[hidden] { display: none; }
.kanaele__titel,
.seiten-titel {
margin: 0 0 .7rem;
font-size: 1.05rem;
font-weight: 600;
color: #cfe0f0;
}
.seiten-titel { margin-top: 1.8rem; }
.kanaele__reihe {
display: grid;
gap: .8rem;
/* Dieselbe Regel wie beim Kartengitter darunter: eine Regel statt
einer Zahl. Ein vierter Kanal ordnet sich von selbst ein. */
grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}
.kanal {
--kanal-ton: #7ec8f2;
display: flex;
flex-direction: column;
gap: .15rem;
padding: .85rem 1rem;
border-radius: .9rem;
border: 1px solid color-mix(in srgb, var(--kanal-ton) 30%, transparent);
background: linear-gradient(150deg,
color-mix(in srgb, var(--kanal-ton) 11%, #0c1420), #090f1a 80%);
text-decoration: none;
transition: transform .2s ease, border-color .2s ease, background .2s ease;
}
.kanal:hover {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--kanal-ton) 58%, transparent);
}
.kanal:focus-visible { outline: 2px solid var(--kanal-ton); outline-offset: 2px; }
.kanal__name { font-weight: 600; color: #eaf3fb; }
.kanal__handle {
font-size: .85rem;
color: color-mix(in srgb, var(--kanal-ton) 78%, #cfe0f0);
overflow-wrap: anywhere;
}
.kanal__satz { margin-top: .2rem; font-size: .84rem; line-height: 1.45; color: #9fb4c8; }
.kanaele__fehler {
margin: 0;
padding: .8rem 1rem;
border-radius: .8rem;
border: 1px solid rgba(217, 164, 65, .35);
background: rgba(217, 164, 65, .08);
font-size: .88rem;
line-height: 1.5;
color: #d8c49a;
}
.kanaele__fehler[hidden] { display: none; }
/* ---- WER BEWEGUNG NICHT MOECHTE ------------------------------------- */
/* Der Zustand bleibt vollstaendig lesbar: Farbe, Ring und Text stehen
weiter da. Es hoert nur das Atmen auf. */
@media (prefers-reduced-motion: reduce) {
.puls[data-lage="live"] .puls__aura,
.puls[data-lage="live"] .puls__punkt { animation: none; }
.puls__ring-fortschritt { transition: none; }
.kanal { transition: none; }
.kanal:hover { transform: none; }
}