Files
dogfather-universe/workspace/assets/css/chat.css
T
DogFatherGitandClaude Opus 5 14e9bbf7a5 Chat: Fotos und PDFs schicken, Gespraeche wegraeumen
Filipe, mit Bildschirmfoto: "man muss die chats auch geloescht
bekommen!!! am besten waere es auch wenn man da auch im chat pdfs
schicken koennte. pdfs und fotos."

Zwei Entscheidungen vorher abgestimmt, weil sie den Bau bestimmen:
Geloescht wird NUR BEI MIR. Schicken duerfen ALLE im Gespraech, auch
Creator -- anders als in der Dateiablage, wo etwas in einem Bereich
landet, den mehrere sehen. Hier bekommt es genau der, mit dem man
ohnehin gerade spricht.

--- ANHAENGE ---

Drei Wege zur selben Sache, weil Leute unterschiedlich arbeiten: die
Bueroklammer, Hineinziehen und Einfuegen mit Strg+V (der Weg fuer einen
Screenshot -- der liegt in der Zwischenablage und nirgends als Datei).
Alle drei laufen durch dieselbe Funktion; drei Fassungen waeren drei
Gelegenheiten, dass eine die Pruefung vergisst.

Ein Foto wird GEZEIGT, ein PDF wird als Karte ANGEBOTEN. Das ist kein
Schoenheitsunterschied: Ein Bild erkennt man in einer Zehntelsekunde,
ein PDF muss man ohnehin oeffnen -- eine Vorschau davon waere ein
grauer Kasten, der so tut, als koennte man etwas lesen.

DIE SICHERHEIT STEHT IN dateiErkennen(). Dateiname und Content-Type
kommen vom Absender und sind frei erfunden; der Typ wird deshalb aus
den ersten Bytes bestimmt (PNG/GIF/WebP/JPEG/PDF, mit Breite und Hoehe
im selben Durchgang). SVG steht absichtlich NICHT in der Liste -- das
ist XML, das Skripte enthalten darf, ein als Bild getarntes Programm.
Ausgeliefert wird spaeter genau der ERKANNTE Typ, nie der eingeschickte,
dazu nosniff und "default-src 'none'; sandbox".

Auf der Platte bekommt jede Datei einen erzeugten Zufallsnamen, in
einem Ordner ausserhalb des Repos. Zuruecknehmen loescht die Datei
wirklich -- sonst waere sie im Verlauf weg und ueber die Adresse noch
da, also nur der Anschein einer Ruecknahme.

--- WEGRAEUMEN ---

Zwei Spalten in chat_teilnehmer statt einer, wegen eines Randfalls: Bei
einem Gespraech ohne jede Nachricht waere die Grenze 0 -- und 0 heisst
sonst "nie geloescht". geloescht_am unterscheidet die beiden.

Die Grenze wirkt in der Liste, im Verlauf, in der Vorschau, in der
SUCHE, bei den Anhaengen und in der Ungelesen-Zahl. Die Suche ist die
Stelle, an der so etwas typischerweise durchrutscht: aus der Liste weg,
ueber die Suche noch da.

--- DER FUND: 323 PIXEL ---

Ein Bild ist spaeter fertig als der Rest der Seite. Beim Oeffnen springt
der Verlauf ans Ende, dann kommt das Foto an und schiebt alles darunter
weg -- man steht ploetzlich mittendrin, ohne etwas angeklickt zu haben.

Das width/height-Attribut am <img>, wie man es ueberall liest, hilft
hier NICHT: Es gibt nur das Seitenverhaeltnis. Damit daraus eine Hoehe
wird, muss die Breite feststehen -- bei "width: auto" und einem nicht
geladenen Bild ist sie 0. Der Platz wird jetzt am KASTEN reserviert
(aspect-ratio + max-width aus den gemessenen Massen).

Und die Pruefung dazu hatte denselben Fehler wie das Auge: Sie mass in
einem Fenster, in dem das Bild laengst im Zwischenspeicher lag, und
meldete tadellose 0 px. Sie misst jetzt in einem FRISCHEN Browser --
der Fall, um den es geht, ist der erste.

--- SICHERUNG ---

chat-anhaenge/ ist im selben Zug in tools/sicherung-holen.sh
eingetragen, nicht spaeter, wenn es auffaellt: Genau so ist die Luecke
bei den Profilbildern entstanden. tools/wiederherstellung-proben.mjs
bestaetigt: "der Server benutzt 4 Datenordner", keiner fehlt.

--- Pruefung ---

server/pruef-chat-anhaenge.mjs, neu, 60 Pruefungen, alle gruen.
Abschnitt 3 versucht ausdruecklich, hereinzukommen: HTML als bild.png,
SVG als foto.png, SVG als svg, eine Textdatei, ein PNG-Kopf ohne Inhalt
-- alle fuenf mit 415 abgewiesen, ein echtes JPEG danach mit 201
angenommen (sonst bewiese der Block nur, dass gar nichts durchkommt).
13 MB geben 413 mit lesbarem Text, nicht 500.

Konsolenfehler werden nach ZEITPUNKT getrennt, nicht nach Statusnummer:
Was waehrend eines absichtlichen Versuchs entsteht, ist gewollt. Nach
Nummer zu filtern waere bequem und wuerde ab morgen echte 404 mit
verschlucken.

Ausserdem gruen: pruef-chat, pruef-chat-optik, pruef-chat-ausbau,
pruef-css-klassen. Angesehen bei 1440 px und bei 390 px.

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

1079 lines
42 KiB
CSS

/* =====================================================================
chat.css — Gespräche im Workspace.
Wunsch Filipe, 06.09.2026: *"richtig krass, richtig hochwertig,
professionell und ultra geil."*
WAS DAS HIER HEISST — und was nicht:
Nicht mehr Effekte. Ein Chat wird täglich benutzt und oft lange
angesehen; was beim ersten Blick beeindruckt, stört beim hundertsten.
Die Wirkung kommt aus vier Dingen:
1. EINE FLÄCHE, kein scrollendes Dokument. Die Seite hat die Höhe
des Fensters, gescrollt wird nur INNERHALB der Spalten. Das
Eingabefeld steht immer an derselben Stelle -- man muss es nie
suchen.
2. RUHE IM VERLAUF. Fast schwarzer Grund, die eigenen Nachrichten
in einem gedeckten Blau, fremde in einem neutralen Grau. Kein
Farbverlauf in der Blase; er macht Text unruhig zu lesen.
3. GRUPPIERUNG. Mehrere Nachrichten derselben Person rücken
zusammen und wiederholen den Namen nicht. Ein Datumstrenner
gliedert den Verlauf.
4. GENUG LUFT. Zeilenhöhe 1.5, Blasen mit ordentlichem Innenabstand.
Enge sieht auf einem Bildschirmfoto ordentlich aus und liest
sich schlecht.
Augenschonend ist Hausregel: keine harten Weißflächen, keine
Neonränder, Bewegung nur als kurze Blende.
===================================================================== */
/* ---------- Die Fläche --------------------------------------------------- */
.chat-seite {
/* Der Rest des Hauses scrollt; hier soll die Seite stehen.
100dvh statt 100vh: Auf dem Handy ändert sich die sichtbare Höhe,
wenn die Adresszeile ein- und ausfährt -- mit vh springt das
Eingabefeld dabei aus dem Bild.
--kopf-hoehe WIRD GEMESSEN, nicht geraten (chat.js). Der erste
Entwurf hatte hier 62 px stehen; am Handy ist die Kopfleiste aber
zweizeilig und gut doppelt so hoch. Folge: Die Seite war zu lang,
und das Eingabefeld stand halb unterhalb des Bildschirmrands --
ausgerechnet das Feld, um das es geht. Der Rückfallwert bleibt
stehen für den Moment vor der ersten Messung. */
height: calc(100dvh - var(--kopf-hoehe, 62px));
display: flex; flex-direction: column;
padding-bottom: 0;
overflow: hidden;
}
.chat {
flex: 1;
min-height: 0; /* sonst wächst das Raster über die Fläche */
display: grid;
grid-template-columns: minmax(240px, 320px) 1fr;
gap: 0;
border: 1px solid var(--rand);
border-radius: var(--radius);
background:
radial-gradient(120% 90% at 0% 0%, rgba(255, 255, 255, .03), transparent 55%),
var(--flaeche);
overflow: hidden;
}
.chat__spalte {
display: flex; flex-direction: column;
min-height: 0; min-width: 0;
}
/* Der Trenner zwischen Liste und Verlauf. Läuft oben und unten aus --
eine durchgehende Linie zerschneidet die Kachel in zwei. */
.chat__spalte--verlauf { position: relative; }
.chat__spalte--verlauf::before {
content: ""; position: absolute; left: 0; top: 12px; bottom: 12px; width: 1px;
background: linear-gradient(180deg,
transparent, var(--rand-hell) 15%, var(--rand-hell) 85%, transparent);
}
.chat__kopf {
display: flex; align-items: center; gap: 12px;
padding: 15px 17px;
border-bottom: 1px solid var(--rand);
flex: none;
}
.chat__kopf-text { min-width: 0; }
.chat__titel {
margin: 0;
font-size: 1.02rem; font-weight: 650; color: var(--text);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat__unter {
margin: 2px 0 0;
font-size: .78rem; color: var(--text-still);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat__kopf .knopf { margin-left: auto; flex: none; }
/* Der Zurück-Pfeil gehört dem Handy. Am Rechner stehen beide Spalten
nebeneinander, da gibt es nichts, wohin man zurückkönnte. */
.chat__zurueck {
display: none;
flex: none;
width: 34px; height: 34px;
align-items: center; justify-content: center;
border: 1px solid var(--rand); border-radius: 10px;
background: rgba(255, 255, 255, .04);
color: var(--text-leise); cursor: pointer;
}
.chat__zurueck svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; }
.chat__zurueck:hover { color: var(--text); border-color: var(--rand-hell); }
.chat__suche { padding: 10px 14px 4px; flex: none; }
.chat__suche input { width: 100%; }
.chat__leer {
margin: 0; padding: 20px 18px;
font-size: .86rem; color: var(--text-still); line-height: 1.55;
}
/* ---------- Links: die Gespräche ----------------------------------------- */
.chat__liste {
flex: 1; min-height: 0;
overflow-y: auto;
margin: 0; padding: 8px; list-style: none;
display: grid; gap: 3px; align-content: start;
}
.chat-raum__knopf {
--r: var(--akzent);
width: 100%;
display: grid; grid-template-columns: auto 1fr auto;
align-items: center; gap: 11px;
padding: 10px 11px;
border: 1px solid transparent; border-radius: 12px;
background: transparent;
color: inherit; font: inherit; text-align: left; cursor: pointer;
transition: background .16s ease, border-color .16s ease;
}
.chat-raum__knopf:hover { background: rgba(255, 255, 255, .04); }
.chat-raum__knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: -2px; }
/* Das offene Gespräch bleibt sichtbar markiert -- sonst weiß man nach
dem Scrollen nicht mehr, wo man ist. */
.chat-raum[data-offen="ja"] .chat-raum__knopf {
background: color-mix(in srgb, var(--akzent) 11%, transparent);
border-color: color-mix(in srgb, var(--akzent) 32%, transparent);
}
.chat-raum__zeichen {
flex: none;
width: 38px; height: 38px; border-radius: 50%;
display: grid; place-items: center;
font-size: .82rem; font-weight: 700;
color: var(--r);
background: color-mix(in srgb, var(--r) 13%, transparent);
border: 1px solid color-mix(in srgb, var(--r) 30%, transparent);
}
/* Dieselben Rollenfarben wie überall im Haus. */
.chat-raum__zeichen[data-rolle="admin"] { --r: var(--dogi-haupt); }
.chat-raum__zeichen[data-rolle="manager"] { --r: var(--manager-haupt); }
.chat-raum__zeichen[data-rolle="scout"] { --r: var(--scout-haupt); }
.chat-raum__zeichen[data-rolle="creator"] { --r: var(--creator-haupt); }
/* Eine Gruppe zeigt ihre Größe statt einer Initiale -- der Name der
Gruppe steht ohnehin daneben. */
.chat-raum__zeichen[data-gruppe="ja"] {
--r: #a0aec4;
border-radius: 12px;
font-variant-numeric: tabular-nums;
}
.chat-raum__mitte { min-width: 0; }
.chat-raum__oben { display: flex; align-items: baseline; gap: 8px; }
.chat-raum__name {
flex: 1; min-width: 0;
font-size: .89rem; font-weight: 600; color: var(--text-leise);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-raum__zeit {
flex: none;
font-size: .75rem; color: var(--text-still);
font-variant-numeric: tabular-nums;
}
.chat-raum__vorschau {
display: block; margin-top: 2px;
font-size: .78rem; color: var(--text-still);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-raum__vorschau[data-weg="ja"] { font-style: italic; opacity: .8; }
/* Ungelesen: die Zahl UND ein kräftigerer Name. Nur eine Zahl übersieht
man beim Überfliegen. */
.chat-raum[data-neu="ja"] .chat-raum__name { color: var(--text); font-weight: 700; }
.chat-raum[data-neu="ja"] .chat-raum__vorschau { color: var(--text-leise); }
.chat-raum__zahl {
flex: none;
min-width: 21px; height: 21px; padding: 0 6px;
display: grid; place-items: center;
border-radius: 999px;
font-size: .72rem; font-weight: 700;
font-variant-numeric: tabular-nums;
color: #0b0f16;
background: var(--akzent);
}
/* ---------- Rechts: der Verlauf ------------------------------------------ */
.chat__verlauf {
flex: 1; min-height: 0;
overflow-y: auto;
padding: 18px 18px 8px;
display: flex; flex-direction: column; gap: 3px;
/* Ein weicher Schleier am oberen Rand: Der Verlauf scrollt unter den
Kopf, statt an einer harten Kante abgeschnitten zu wirken. */
mask-image: linear-gradient(180deg, transparent, #000 14px);
}
/* KURZE GESPRÄCHE LIEGEN UNTEN AN.
Bei drei Nachrichten standen sie oben, und darunter klaffte der halbe
Bildschirm -- man sucht die neueste dann am falschen Ende. Jeder
Messenger legt sie ans untere Ende, direkt über das Eingabefeld, und
das ist kein Geschmack: Dort schaut man hin, wenn man antworten will.
`margin-top: auto` auf dem ERSTEN Kind statt `justify-content:
flex-end` am Behälter. Der naheliegende Weg hat einen bekannten
Haken: In einem scrollbaren Flex-Behälter wird der obere Teil damit
unerreichbar, sobald der Inhalt überläuft -- man käme an die ältesten
Nachrichten nicht mehr heran. */
.chat__verlauf > :first-child { margin-top: auto; }
/* Der Datumstrenner. */
.chat-tag {
display: flex; align-items: center; gap: 10px;
margin: 14px 0 10px;
color: var(--text-still);
}
.chat-tag::before, .chat-tag::after {
content: ""; flex: 1; height: 1px;
background: linear-gradient(90deg, transparent, var(--rand-hell), transparent);
}
.chat-tag__text {
flex: none;
font-size: .72rem; font-weight: 700;
letter-spacing: .07em; text-transform: uppercase;
}
.chat-nachricht {
display: grid;
grid-template-columns: 30px 1fr;
gap: 9px;
align-items: flex-end;
max-width: 76%;
margin-top: 9px;
}
/* Folgt eine Nachricht derselben Person, rückt sie näher und lässt den
Kreis weg -- der Platz bleibt frei, damit die Blasen fluchten. */
.chat-nachricht[data-folge="ja"] { margin-top: 2px; }
.chat-nachricht[data-selbst="ja"] {
grid-template-columns: 1fr;
margin-left: auto;
}
.chat-nachricht__zeichen {
--r: #a0aec4;
grid-column: 1;
width: 30px; height: 30px; border-radius: 50%;
display: grid; place-items: center;
font-size: .75rem; font-weight: 700;
color: var(--r);
background: color-mix(in srgb, var(--r) 13%, transparent);
border: 1px solid color-mix(in srgb, var(--r) 28%, transparent);
}
.chat-nachricht__zeichen[data-rolle="admin"] { --r: var(--dogi-haupt); }
.chat-nachricht__zeichen[data-rolle="manager"] { --r: var(--manager-haupt); }
.chat-nachricht__zeichen[data-rolle="scout"] { --r: var(--scout-haupt); }
.chat-nachricht__zeichen[data-rolle="creator"] { --r: var(--creator-haupt); }
/* Ohne Kreis (Folgenachricht) bleibt die Spalte trotzdem stehen. */
.chat-nachricht[data-folge="ja"]:not([data-selbst="ja"]) .chat-nachricht__blase { grid-column: 2; }
.chat-nachricht__blase {
grid-column: 2;
padding: 10px 13px 7px;
border: 1px solid var(--rand);
border-radius: 14px 14px 14px 4px;
background: rgba(255, 255, 255, .045);
min-width: 0;
}
.chat-nachricht[data-folge="ja"] .chat-nachricht__blase { border-radius: 14px 14px 14px 8px; }
/* Die eigenen: gedecktes Blau, Ecke rechts. Kein Verlauf in der Fläche
-- Text auf einem Farbverlauf liest sich unruhig. */
.chat-nachricht[data-selbst="ja"] .chat-nachricht__blase {
grid-column: 1;
border-radius: 14px 14px 4px 14px;
background: color-mix(in srgb, var(--akzent) 16%, transparent);
border-color: color-mix(in srgb, var(--akzent) 30%, transparent);
}
.chat-nachricht[data-selbst="ja"][data-folge="ja"] .chat-nachricht__blase {
border-radius: 14px 14px 8px 14px;
}
.chat-nachricht__von {
margin: 0 0 3px;
font-size: .74rem; font-weight: 700;
color: color-mix(in srgb, var(--text-leise) 85%, transparent);
}
.chat-nachricht__text {
margin: 0;
font-size: .92rem; color: var(--text);
/* pre-wrap: Zeilenumbrüche aus der Eingabe bleiben erhalten, ohne
dass dafür HTML erzeugt werden müsste (das wäre der Weg, über den
jemand Auszeichnung einschleust). */
white-space: pre-wrap;
overflow-wrap: anywhere; /* eine lange Adresse sprengt nichts */
line-height: 1.5;
}
.chat-nachricht__weg { color: var(--text-still); font-style: italic; }
.chat-nachricht[data-weg="ja"] .chat-nachricht__blase {
background: transparent;
border-style: dashed;
}
/* EINE FARBE FÜR DIE GANZE FUSSZEILE — und zwar hier, an einer Stelle.
---------------------------------------------------------------------
Uhrzeit, "antworten", "zurücknehmen" und "kopieren" standen alle auf
var(--text-still) (#7f8fa6). Gemessen (pruef-chat-ausbau, Abschnitt 9)
ergibt das auf der eigenen Blase 3,68:1 -- unter den 4,5:1, die für
Text dieser Größe gelten. Es ist nie aufgefallen, weil niemand
nachgemessen hat; die Blase ist heller als der übrige Grund, und
genau dort wird eine leise Farbe zu leise.
var(--text-leise) (#94a5bb) bringt dieselbe Stelle auf 4,80:1 und
bleibt trotzdem deutlich ruhiger als der Nachrichtentext.
Die Kinder erben sie (color: inherit). Vier eigene Farbangaben wären
vier Stellen, die beim nächsten Mal auseinanderlaufen -- der Fehler,
der in diesem Haus am häufigsten vorkommt. */
.chat-nachricht__fuss {
display: flex; align-items: center; gap: 9px;
margin-top: 4px;
color: var(--text-leise);
}
.chat-nachricht__zeit {
font-size: .75rem; color: inherit;
font-variant-numeric: tabular-nums;
}
/* Der Zurücknehmen-Knopf erscheint erst beim Darüberfahren -- er ist
die seltene Handlung und soll nicht in jeder Zeile mitlaufen. Auf
Geräten ohne Zeiger steht er immer da (siehe unten). */
.chat-nachricht__weg-knopf {
padding: 0; border: 0; background: none;
font: inherit; font-size: .75rem;
color: inherit; cursor: pointer;
opacity: 0; transition: opacity .16s ease, color .16s ease;
}
.chat-nachricht:hover .chat-nachricht__weg-knopf,
.chat-nachricht__weg-knopf:focus-visible { opacity: 1; }
.chat-nachricht__weg-knopf:hover { color: var(--warn); }
/* Unterwegs und gescheitert -- der Unterschied muss sichtbar sein. */
.chat-nachricht__blase:has(+ *) { /* Platzhalter, damit :has unterstützt bleibt */ }
/* ---------- Das Eingabefeld ---------------------------------------------- */
.chat__eingabe {
flex: none;
display: flex; align-items: flex-end; gap: 10px;
padding: 12px 14px 14px;
border-top: 1px solid var(--rand);
background: rgba(0, 0, 0, .2);
}
.chat__eingabe-schild {
position: absolute; width: 1px; height: 1px; margin: -1px;
overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.chat__eingabe textarea {
flex: 1; min-width: 0;
resize: none;
min-height: 42px; max-height: 160px;
line-height: 1.5;
}
.chat__senden {
flex: none;
width: 42px; height: 42px;
display: grid; place-items: center;
border: 1px solid color-mix(in srgb, var(--akzent) 40%, transparent);
border-radius: 12px;
background: color-mix(in srgb, var(--akzent) 18%, transparent);
color: color-mix(in srgb, var(--akzent) 55%, #ffffff);
cursor: pointer;
transition: background .16s ease, color .16s ease;
}
.chat__senden svg { width: 20px; height: 20px; fill: currentColor; }
.chat__senden:hover {
background: color-mix(in srgb, var(--akzent) 28%, transparent);
color: #fff;
}
.chat__senden:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
/* ---------- Die Wahl im Neu-Dialog --------------------------------------- */
.chat-wahl { margin: 4px 0 6px; max-height: 46vh; overflow-y: auto; }
.chat-wahl__gruppe + .chat-wahl__gruppe { margin-top: 13px; }
.chat-wahl__titel {
margin: 0 0 7px;
display: flex; align-items: center; gap: 7px;
font-size: .75rem; font-weight: 700;
letter-spacing: .08em; text-transform: uppercase;
color: var(--text-still);
}
.chat-wahl__punkt {
width: 7px; height: 7px; border-radius: 50%;
background: var(--r, var(--text-still)); flex: none;
}
.chat-wahl__gruppe[data-rolle="admin"] { --r: var(--dogi-haupt); }
.chat-wahl__gruppe[data-rolle="manager"] { --r: var(--manager-haupt); }
.chat-wahl__gruppe[data-rolle="scout"] { --r: var(--scout-haupt); }
.chat-wahl__gruppe[data-rolle="creator"] { --r: var(--creator-haupt); }
.chat-wahl__liste { display: flex; flex-wrap: wrap; gap: 7px; }
.chat-wahl__knopf {
--r: rgba(255, 255, 255, .5);
display: inline-flex; align-items: center; gap: 9px;
min-height: 40px;
padding: 5px 14px 5px 6px;
border: 1px solid var(--rand); border-radius: 999px;
background: rgba(255, 255, 255, .035);
color: var(--text-leise); font: inherit; cursor: pointer;
transition: color .16s ease, border-color .16s ease, background .16s ease;
}
.chat-wahl__knopf[data-rolle="admin"] { --r: var(--dogi-haupt); }
.chat-wahl__knopf[data-rolle="manager"] { --r: var(--manager-haupt); }
.chat-wahl__knopf[data-rolle="scout"] { --r: var(--scout-haupt); }
.chat-wahl__knopf[data-rolle="creator"] { --r: var(--creator-haupt); }
.chat-wahl__knopf:hover { color: var(--text); border-color: rgba(255, 255, 255, .24); }
.chat-wahl__knopf:focus-visible { outline: 2px solid var(--r); outline-offset: 2px; }
.chat-wahl__zeichen {
flex: none;
width: 28px; height: 28px; border-radius: 50%;
display: grid; place-items: center;
font-size: .74rem; font-weight: 700;
color: var(--r);
background: color-mix(in srgb, var(--r) 14%, transparent);
border: 1px solid color-mix(in srgb, var(--r) 34%, transparent);
}
.chat-wahl__name { font-size: .86rem; font-weight: 550; }
.chat-wahl__knopf[data-an="ja"] {
color: var(--text); font-weight: 600;
border-color: color-mix(in srgb, var(--r) 55%, transparent);
background: color-mix(in srgb, var(--r) 13%, transparent);
}
.chat-wahl__knopf[data-an="ja"] .chat-wahl__zeichen {
color: #12151b; background: var(--r); border-color: var(--r);
}
/* ---------- Handy --------------------------------------------------------
EINE Spalte, umgeschaltet über data-ansicht. Zwei Spalten auf 390
Pixeln hiessen zwei unbenutzbare Hälften. */
@media (max-width: 860px) {
.chat { grid-template-columns: 1fr; }
.chat__spalte--verlauf::before { display: none; }
.chat__zurueck { display: flex; }
.chat[data-ansicht="liste"] .chat__spalte--verlauf { display: none; }
.chat[data-ansicht="verlauf"] .chat__spalte--liste { display: none; }
/* Mehr Breite für die Blasen -- auf einem schmalen Schirm sind 76 %
drei Wörter je Zeile. */
.chat-nachricht { max-width: 88%; }
/* Ohne Zeiger gibt es kein "Darüberfahren": Der Knopf steht immer da,
sonst wäre er auf dem Handy gar nicht erreichbar. */
.chat-nachricht__weg-knopf { opacity: .75; }
}
@media (hover: none) {
.chat-nachricht__weg-knopf { opacity: .75; }
}
@media (prefers-reduced-motion: reduce) {
.chat-raum__knopf, .chat__senden, .chat-wahl__knopf,
.chat-nachricht__weg-knopf { transition: none; }
}
/* Ohne Farbverläufe tragen Kanten und Formen allein. Die eigenen
Nachrichten sind dann nur noch an der Ecke und der Ausrichtung zu
erkennen -- deshalb bekommen sie hier einen kräftigeren Rand. */
@media (forced-colors: active) {
.chat { border: 1px solid CanvasText; }
.chat__spalte--verlauf::before { background: CanvasText; }
.chat-nachricht__blase { border: 1px solid CanvasText; }
.chat-nachricht[data-selbst="ja"] .chat-nachricht__blase { border-width: 2px; }
.chat-raum__zeichen, .chat-nachricht__zeichen { border: 1px solid CanvasText; }
.chat-raum__zahl { border: 1px solid CanvasText; }
.chat-tag::before, .chat-tag::after { background: CanvasText; }
.chat__verlauf { mask-image: none; }
}
/* =====================================================================
DER CHAT (07.09.2026)
Wunsch Filipe: "mach die chat fenster auch viel geiler, viel
detaillierter und viel perfekter. ich will dass die leute auch bock
bekommen diesen chat zu benutzen."
---------------------------------------------------------------------
WORAN MAN EINEN GUTEN CHAT ERKENNT
Nicht an Effekten. An vier Dingen, die alle mit ORIENTIERUNG zu tun
haben -- und alle vier fehlten:
1. MAN SIEHT, MIT WEM MAN SCHREIBT. Initialen sind ein Platzhalter,
kein Gesicht. Die Bilder liefert der Server seit heute mit; hier
werden sie gezeichnet -- rund, mit einem feinen Rand in der Farbe
der Rolle.
2. EINE NACHRICHT HAT EINE RICHTUNG. Eigene Nachrichten kommen von
rechts und tragen den Hausakzent, fremde von links und bleiben
neutral. Die Ecke am Anfang einer Folge ist eckig, die übrigen
rund -- so sieht man, wo ein Gedanke anfängt, ohne den Namen zu
lesen.
3. EIN GESPRÄCH HAT EIN GEWICHT. Ungelesenes ist nicht "auch da",
sondern das, weshalb man die Seite geöffnet hat: kräftigerer
Grund, farbige Schiene, die Zahl als Marke.
4. DAS EINGABEFELD IST DAS WICHTIGSTE ELEMENT DER SEITE. Es war
eines von vielen. Jetzt sitzt es in einer eigenen Leiste, die
sich beim Hineinschreiben hebt.
Und was NICHT passiert ist: kein Blinken, kein Springen, keine
Verläufe im Text. Ein Chat wird stundenlang angesehen -- alles, was
einmal auffällt, nervt beim zwanzigsten Mal.
===================================================================== */
/* ---------- Das Gesicht ---------------------------------------------- */
.chat-raum__zeichen,
.chat-nachricht__zeichen {
position: relative;
overflow: hidden;
background: linear-gradient(150deg,
color-mix(in srgb, var(--rton, var(--akzent)) 30%, rgba(20, 27, 40, .9)),
rgba(12, 17, 26, .95));
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--rton, var(--akzent)) 38%, transparent),
0 2px 6px -3px rgba(0, 0, 0, .8);
}
/* Die Farbe der Rolle -- dieselbe Zuordnung wie überall im Haus. */
.chat-raum__zeichen[data-rolle="spicy"],
.chat-nachricht__zeichen[data-rolle="spicy"] { --rton: var(--spicy-haupt); }
.chat-raum__zeichen[data-rolle="admin"],
.chat-nachricht__zeichen[data-rolle="admin"] { --rton: var(--dogi-haupt); }
.chat-raum__zeichen[data-rolle="manager"],
.chat-nachricht__zeichen[data-rolle="manager"] { --rton: var(--manager-haupt); }
.chat-raum__zeichen[data-rolle="scout"],
.chat-nachricht__zeichen[data-rolle="scout"] { --rton: var(--scout-haupt); }
.chat-raum__zeichen[data-rolle="creator"],
.chat-nachricht__zeichen[data-rolle="creator"] { --rton: var(--creator-haupt); }
/* Das Bild liegt ÜBER dem Buchstaben, nicht an seiner Stelle. Fällt es
aus, steht der Buchstabe weiterhin da. */
.chat-raum__zeichen img,
.chat-nachricht__zeichen img {
position: absolute; inset: 0;
width: 100%; height: 100%;
object-fit: cover;
border-radius: inherit;
}
/* ---------- Die Gesprächsliste --------------------------------------- */
.chat-raum__knopf {
position: relative;
border-radius: 12px;
margin: 0 8px 4px;
transition: background var(--tempo), box-shadow var(--tempo);
}
/* Das offene Gespräch trägt eine Schiene -- man sieht auch beim Scrollen
der Liste, wo man gerade ist. */
.chat-raum__knopf[data-an="ja"] {
background: linear-gradient(90deg,
color-mix(in srgb, var(--akzent) 16%, transparent),
rgba(255, 255, 255, .03) 55%);
box-shadow: inset 3px 0 0 var(--akzent);
}
/* Ungelesenes ist der Grund, warum man hier ist. */
.chat-raum__knopf:has(.chat-raum__zahl) {
background: rgba(255, 255, 255, .045);
}
/* ---------- Die Nachrichten ------------------------------------------ */
.chat-nachricht__blase {
border-radius: 16px 16px 16px 5px;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .06),
0 2px 6px -3px rgba(0, 0, 0, .55);
}
/* Die erste Blase einer Folge bekommt oben eine eckige Ecke -- dort
fängt der Gedanke an. Die folgenden sind rundum weich. */
.chat-nachricht[data-folge="ja"] .chat-nachricht__blase {
border-top-left-radius: 8px;
}
.chat-nachricht[data-selbst="ja"] .chat-nachricht__blase {
border-radius: 16px 16px 5px 16px;
background: linear-gradient(160deg,
color-mix(in srgb, var(--akzent) 26%, rgba(17, 24, 37, .95)),
color-mix(in srgb, var(--akzent) 12%, rgba(12, 17, 27, .95)));
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, .10),
0 2px 8px -3px color-mix(in srgb, var(--akzent) 45%, transparent);
}
.chat-nachricht[data-selbst="ja"][data-folge="ja"] .chat-nachricht__blase {
border-top-right-radius: 8px;
border-top-left-radius: 16px;
}
/* Der Tagestrenner: eine Linie mit dem Datum darin statt eines Wortes
im Nichts. */
.chat-tag {
display: flex; align-items: center; gap: 12px;
margin: 18px 0 12px;
}
.chat-tag::before, .chat-tag::after {
content: ""; flex: 1 1 auto; height: 1px;
background: linear-gradient(90deg, transparent, rgba(150, 186, 220, .18), transparent);
}
/* ---------- Das Eingabefeld ------------------------------------------ */
/* Es ist das wichtigste Element der Seite und sah aus wie eines von
vielen. Eine eigene Leiste, die sich beim Hineinschreiben hebt. */
/* Sie heisst .chat__eingabe (chat.html), nicht .chat-neu -- ich hatte
den Namen aus dem Kopf geschrieben. pruef-struktur meldete es als
totes CSS: eine Regel, die auf nichts zeigt, sieht aus wie erledigte
Arbeit und ist keine. */
.chat__eingabe {
position: relative;
padding: 12px 14px;
border-top: 1px solid rgba(150, 186, 220, .12);
background: linear-gradient(180deg, rgba(13, 18, 28, .6), rgba(9, 12, 20, .92));
transition: box-shadow var(--tempo);
}
.chat__eingabe:focus-within {
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--akzent) 34%, transparent);
}
@media (prefers-reduced-motion: reduce) {
.chat-raum__knopf, .chat__eingabe { transition: none; }
}
@media (forced-colors: active) {
.chat-nachricht__blase,
.chat-raum__knopf[data-an="ja"] { box-shadow: none; border: 1px solid CanvasText; }
.chat-raum__zeichen, .chat-nachricht__zeichen { background: Canvas; box-shadow: none; }
}
/* =====================================================================
DREI DINGE, DIE DEM CHAT GEFEHLT HABEN (Punkt 15, 09.09.2026)
Filipe: "ich will dass du diese seite viel krasser und detaillierter
machst, ich will dass du dich informierst und alles reinsetzt was
wir noch gebrauchen könnten."
Nicht alles, sondern das, was hier täglich fehlt. Der Chat konnte
schon Räume, Verlauf, Gelesen-Stand, Live-Zustellung, Gruppen und
Zurücknehmen. Was fehlte:
1. SUCHE IN DEN NACHRICHTEN. Ein Chat ohne sie ist ab dem zweiten
Monat ein Archiv, in dem man nichts findet. Das Suchfeld gab es
— es durchsuchte aber nur die NAMEN der Gespräche.
2. ANTWORTEN MIT ZITAT. Zu zweit weiß man meist, worauf sich etwas
bezieht. In einer Gruppe laufen drei Fäden parallel, und "ja,
mach das" kann alles heißen.
3. DIE LINIE "AB HIER NEU". Wer nach zwei Tagen zurückkommt, sucht
sonst die Stelle, an der er aufgehört hat, indem er Uhrzeiten
liest.
Bewusst NICHT gebaut: Anhänge (dafür gibt es den Dateien-Bereich mit
Rechten und Ablauf), Reaktionen (eine vierte Sache, bevor die drei
sich bewährt haben) und Tipp-Anzeigen (sie kosten dauernd Verkehr
und sagen nichts, was man nicht in zwei Sekunden sieht).
===================================================================== */
/* ---- Das Zitat in der Blase ---------------------------------------- */
.chat-zitat {
display: block; width: 100%; text-align: left;
margin: 0 0 7px; padding: 6px 10px 6px 11px;
border: 0; border-radius: 0;
/* Der senkrechte Strich links ist das Zeichen für ein Zitat -- in
jedem Mailprogramm seit dreißig Jahren dasselbe. */
box-shadow: inset 3px 0 0 color-mix(in srgb, var(--akzent) 60%, transparent);
background: rgba(255, 255, 255, .05);
color: var(--text-leise);
font: inherit; cursor: pointer;
transition: background var(--tempo);
}
.chat-zitat:hover { background: rgba(255, 255, 255, .09); }
.chat-zitat__von {
display: block;
font-size: .74rem; font-weight: 700;
color: color-mix(in srgb, var(--akzent) 70%, #ffffff);
}
.chat-zitat__text {
display: block;
font-size: .8rem; line-height: 1.35;
/* Zwei Zeilen reichen: Es ist ein Hinweis auf die Stelle, nicht ihre
Wiederholung. */
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
overflow: hidden;
}
/* Die zitierte Nachricht, wenn man hinspringt -- kurz hervorgehoben.
Ein Sprung ohne Markierung lässt einen raten, welche Zeile gemeint
war. */
.chat-nachricht[data-hervor="ja"] .chat-nachricht__blase {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--akzent) 65%, transparent);
transition: box-shadow .4s ease;
}
@media (prefers-reduced-motion: reduce) {
.chat-nachricht[data-hervor="ja"] .chat-nachricht__blase { transition: none; }
}
/* ---- Die Linie "ab hier neu" --------------------------------------- */
.chat-neu {
display: flex; align-items: center; gap: 10px;
margin: 14px 2px 10px;
color: #ff8f98;
font-size: .72rem; font-weight: 700;
letter-spacing: .1em; text-transform: uppercase;
}
.chat-neu::before, .chat-neu::after {
content: ""; flex: 1; height: 1px;
background: linear-gradient(90deg, transparent, rgba(255, 143, 152, .5));
}
.chat-neu::after { background: linear-gradient(90deg, rgba(255, 143, 152, .5), transparent); }
.chat-neu__text { flex: none; }
/* ---- Die Antwortleiste über dem Eingabefeld ------------------------ */
.antwort-leiste {
display: flex; align-items: flex-start; gap: 10px;
margin-bottom: 8px; padding: 8px 10px 8px 11px;
box-shadow: inset 3px 0 0 var(--akzent);
background: rgba(255, 255, 255, .05);
}
.antwort-leiste[hidden] { display: none; }
.antwort-leiste__inhalt { min-width: 0; flex: 1; }
.antwort-leiste__schild {
/* 0,72 rem = 11,52 px. Mit 0,7 waeren es 11,2 und damit unter der
Grundlinie, die pruef-css-klassen haelt. */
font-size: .72rem; letter-spacing: .08em; text-transform: uppercase;
color: var(--text-still);
}
.antwort-leiste__von {
margin-left: 6px;
font-size: .78rem; font-weight: 700;
color: color-mix(in srgb, var(--akzent) 70%, #ffffff);
}
.antwort-leiste__text {
display: block;
font-size: .82rem; color: var(--text-leise);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.antwort-leiste__weg {
flex: none; width: 28px; height: 28px;
border: 0; border-radius: 50%;
background: rgba(255, 255, 255, .07);
color: var(--text-leise); font-size: .9rem; cursor: pointer;
}
.antwort-leiste__weg:hover { background: rgba(255, 255, 255, .13); color: var(--text); }
/* ---- Fundstellen in Nachrichten ------------------------------------ */
.chat-funde { padding: 4px 10px 12px; }
.chat-funde[hidden] { display: none; }
.chat-funde__schild {
margin: 8px 0 6px;
font-size: .72rem; font-weight: 700;
letter-spacing: .09em; text-transform: uppercase;
color: var(--text-still);
}
.chat-funde__liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.chat-funde__leer { font-size: .84rem; color: var(--text-still); }
.chat-fund {
display: grid; gap: 2px;
width: 100%; padding: 8px 11px;
text-align: left; border: 0;
clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
background: rgba(255, 255, 255, .045);
color: var(--text); font: inherit; cursor: pointer;
transition: background var(--tempo);
}
.chat-fund:hover { background: rgba(255, 255, 255, .09); }
.chat-fund__kopf { display: flex; justify-content: space-between; gap: 8px; }
.chat-fund__raum {
font-size: .78rem; font-weight: 700;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-fund__wann { flex: none; font-size: .72rem; color: var(--text-still); }
.chat-fund__von { font-size: .72rem; color: var(--text-still); }
.chat-fund__text {
font-size: .82rem; color: var(--text-leise); line-height: 1.35;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
overflow: hidden;
}
/* Der Antworten-Knopf am Fuß einer Nachricht -- genauso leise wie
"zurücknehmen" daneben. Er ist ein Angebot, keine Aufforderung. */
.chat-nachricht__antwort-knopf {
border: 0; background: none; padding: 0;
font: inherit; font-size: .72rem;
color: inherit; cursor: pointer;
text-decoration: underline; text-underline-offset: 2px;
}
.chat-nachricht__antwort-knopf:hover { color: var(--text); }
/* =====================================================================
CHAT: SECHS ERGÄNZUNGEN (09.09.2026)
Filipe: "die kategorie chat, boah ich will dass du die wirklich
überall perfektionierst. wirklich alles was gratis ist und
hinzugefügt werden kann ohne problem will ich drin haben."
Alle sechs kommen ohne fremde Bibliothek aus und laden nichts nach:
Links, Kopieren, Emoji-Auswahl, Zeichenzähler, ein Bildlauf der nicht
mehr wegreisst, und Entwürfe je Gespräch (dafür braucht es kein CSS).
===================================================================== */
/* Ein Link in einer Nachricht ist unterstrichen, nicht farbig -- eine
Blase hat schon eine Farbe, und zwei Farben in einer Blase lesen sich
wie zwei Sachen. */
.chat-nachricht__link {
color: inherit;
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-color: color-mix(in srgb, currentColor 55%, transparent);
word-break: break-word;
}
.chat-nachricht__link:hover { text-decoration-color: currentColor; }
.chat-nachricht__link:focus-visible {
outline: 2px solid var(--akzent); outline-offset: 2px; border-radius: 3px;
}
/* Der Kopier-Knopf sieht aus wie "antworten" -- es ist dieselbe Sorte
Handgriff an derselben Stelle. Ein anders gestalteter Knopf daneben
waere eine zweite Sprache in derselben Zeile. */
.chat-nachricht__kopie-knopf {
appearance: none; border: 0; background: none; padding: 0;
font: inherit; font-size: .72rem; font-weight: 600;
color: inherit; cursor: pointer;
text-decoration: underline; text-underline-offset: 2px;
}
.chat-nachricht__kopie-knopf:hover { color: var(--text); }
.chat-nachricht__kopie-knopf:focus-visible {
outline: 2px solid var(--akzent); outline-offset: 2px; border-radius: 4px;
}
/* ---- Emoji ---------------------------------------------------------- */
.chat__emoji {
flex: none;
width: 40px; height: 40px;
display: flex; align-items: center; justify-content: center;
appearance: none; border: 1px solid rgba(150, 186, 220, .18);
border-radius: 11px;
background: rgba(255, 255, 255, .04);
color: var(--text-leise);
font-size: 1.15rem; line-height: 1; cursor: pointer;
transition: color var(--tempo), border-color var(--tempo);
}
.chat__emoji:hover { color: var(--text); border-color: rgba(150, 186, 220, .34); }
.chat__emoji:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
/* Die Tafel steht ÜBER der Eingabe, nicht darunter: Darunter läge sie
auf dem Handy hinter der Bildschirmtastatur. */
.emoji-tafel {
position: absolute;
right: 14px; bottom: calc(100% - 6px);
z-index: 5;
display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px;
padding: 10px;
border-radius: 14px;
background: rgba(8, 12, 20, .97);
border: 1px solid rgba(150, 186, 220, .2);
box-shadow: 0 18px 40px -18px rgba(0, 0, 0, .9);
}
.emoji-tafel__knopf {
appearance: none; border: 0; background: none;
width: 34px; height: 34px; border-radius: 8px;
font-size: 1.15rem; line-height: 1; cursor: pointer;
transition: background var(--tempo);
}
.emoji-tafel__knopf:hover { background: rgba(255, 255, 255, .1); }
.emoji-tafel__knopf:focus-visible { outline: 2px solid var(--akzent); outline-offset: -2px; }
@media (max-width: 620px) {
.emoji-tafel { left: 14px; right: 14px; grid-template-columns: repeat(8, 1fr); }
}
/* ---- Zeichenzähler --------------------------------------------------- */
.chat__zeichen {
flex: none; align-self: center;
font-size: .72rem; font-weight: 700; letter-spacing: .04em;
color: var(--text-still);
font-variant-numeric: tabular-nums;
}
/* Eng heisst rot -- aber erst dann. Ein dauerhaft roter Zähler ist eine
Warnung, die niemand mehr liest. */
.chat__zeichen[data-eng="ja"] { color: var(--warn, #ff9aa2); }
/* ---- Zum neuesten ---------------------------------------------------- */
.chat__zum-neuesten {
position: absolute; left: 50%; bottom: 96px;
transform: translateX(-50%);
z-index: 4;
padding: 9px 18px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--akzent) 40%, transparent);
background: rgba(8, 12, 20, .95);
color: var(--text);
font: inherit; font-size: .8rem; font-weight: 700;
cursor: pointer;
box-shadow: 0 10px 26px -12px rgba(0, 0, 0, .9);
}
.chat__zum-neuesten:hover { border-color: var(--akzent); }
.chat__zum-neuesten:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
.chat__emoji, .emoji-tafel__knopf { transition: none; }
}
@media (forced-colors: active) {
.emoji-tafel, .chat__zum-neuesten { border: 1px solid CanvasText; background: Canvas; }
}
/* =====================================================================
ANHÄNGE, ABLAGE UND WEGRÄUMEN (09.09.2026)
Filipe: "man muss die chats auch gelöscht bekommen!!! am besten wäre
es auch wenn man da auch im chat pdfs schicken könnte. pdfs und
fotos."
===================================================================== */
/* Der Wegräum-Knopf sitzt im Kopf, rechts. Er ist absichtlich LEISE:
Löschen ist die seltene Handlung, und ein roter Knopf, der jeden Tag
danebensteht, wird irgendwann aus Versehen getroffen. Rot wird er
erst beim Darüberfahren -- dann, wenn jemand ihn wirklich meint. */
.chat__weg {
flex: none; margin-left: auto;
width: 34px; height: 34px;
display: grid; place-items: center;
border: 1px solid var(--rand); border-radius: 10px;
background: rgba(255, 255, 255, .03);
color: var(--text-leise); cursor: pointer;
transition: color var(--tempo), border-color var(--tempo);
}
.chat__weg svg {
width: 17px; height: 17px;
fill: none; stroke: currentColor; stroke-width: 1.7;
stroke-linecap: round; stroke-linejoin: round;
}
.chat__weg:hover { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.chat__weg:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
/* Steht der Knopf da, braucht der Text daneben seinen eigenen Rand --
sonst hat .chat__kopf-text keine Grenze und schiebt ihn hinaus. */
.chat__kopf--verlauf .chat__kopf-text { min-width: 0; flex: 1; }
/* ---- Die Büroklammer ------------------------------------------------ */
.chat__anhang-feld {
/* Nicht display:none -- ein verstecktes Feld lässt sich in manchen
Browsern nicht mehr über click() öffnen. Es steht da, nur ohne
Fläche. */
position: absolute; width: 1px; height: 1px;
padding: 0; margin: -1px; overflow: hidden;
clip-path: inset(50%); border: 0;
}
.chat__anhang {
flex: none;
width: 40px; height: 40px;
display: flex; align-items: center; justify-content: center;
appearance: none; border: 1px solid rgba(150, 186, 220, .18);
border-radius: 11px;
background: rgba(255, 255, 255, .04);
color: var(--text-leise); cursor: pointer;
transition: color var(--tempo), border-color var(--tempo);
}
.chat__anhang svg {
width: 19px; height: 19px;
fill: none; stroke: currentColor; stroke-width: 1.7;
stroke-linecap: round; stroke-linejoin: round;
}
.chat__anhang:hover { color: var(--text); border-color: rgba(150, 186, 220, .34); }
.chat__anhang:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
.chat__anhang:disabled { opacity: .45; cursor: progress; }
/* ---- Ein Foto in der Blase ------------------------------------------ */
/* Die Höhe ist begrenzt, die Breite folgt dem Bild. Ein Hochformat
nähme sonst den halben Verlauf ein und schöbe alles darunter aus dem
Bild -- man scrollt dann durch ein Foto statt durch ein Gespräch. */
.chat-bild {
display: block;
width: 100%; /* die Hoechstbreite setzt das Skript */
margin: 0 0 6px;
border-radius: 12px;
overflow: hidden;
line-height: 0;
background: rgba(255, 255, 255, .04);
}
/* Die Groesse macht der Kasten (aspect-ratio + max-width, siehe
chat.js). Das Bild fuellt ihn nur aus. Stuende die Groesse hier am
Bild, waere sie erst bekannt, wenn das Bild da ist -- und genau das
war der Fehler, der den Verlauf um 323 px verschoben hat. */
.chat-bild img {
display: block;
width: 100%; height: 100%;
object-fit: contain;
}
/* Ohne bekannte Masse gibt es kein Verhaeltnis, an dem der Kasten
haengen koennte. Dann greift der alte Weg -- und der Zuhoerer auf
`load` in chat.js haelt den Bildlauf unten. */
.chat-bild:not([style*="aspect-ratio"]) img { height: auto; max-height: 340px; }
.chat-bild:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
.chat-bild[data-kaputt="ja"] {
line-height: 1.5; padding: 12px 14px;
font-size: .84rem; color: var(--text-leise);
}
/* ---- Ein PDF als Karte ---------------------------------------------- */
.chat-datei {
display: flex; align-items: center; gap: 11px;
margin: 0 0 6px; padding: 10px 12px;
border: 1px solid rgba(150, 186, 220, .2);
border-radius: 12px;
background: rgba(255, 255, 255, .04);
color: inherit; text-decoration: none;
transition: border-color var(--tempo), background var(--tempo);
}
.chat-datei:hover {
border-color: rgba(150, 186, 220, .38);
background: rgba(255, 255, 255, .07);
}
.chat-datei:focus-visible { outline: 2px solid var(--akzent); outline-offset: 2px; }
.chat-datei__zeichen {
flex: none;
width: 38px; height: 38px; border-radius: 10px;
display: grid; place-items: center;
font-size: .72rem; font-weight: 800; letter-spacing: .04em;
color: #ff9aa2;
background: rgba(255, 154, 162, .12);
border: 1px solid rgba(255, 154, 162, .3);
}
.chat-datei__mitte { min-width: 0; display: grid; }
.chat-datei__name {
font-size: .86rem; font-weight: 600; color: var(--text);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-datei__mass { font-size: .74rem; color: var(--text-leise); }
/* ---- Die Ablagefläche beim Hineinziehen ------------------------------ */
.chat__ablage {
position: absolute; inset: 8px;
z-index: 6;
display: grid; place-items: center;
border: 2px dashed color-mix(in srgb, var(--akzent) 55%, transparent);
border-radius: 16px;
background: rgba(8, 12, 20, .82);
color: var(--text);
font-size: .95rem; font-weight: 650;
pointer-events: none; /* sonst frisst sie das drop-Ereignis */
}
/* ---- Zwischenstand statt Störung ------------------------------------ */
/* "wird geschickt …" ist keine Fehlermeldung. Rot ist hier das
Einzige, was Aufmerksamkeit verlangen darf -- wer es für
Zwischenstände mitbenutzt, macht es wertlos. */
.fehler[data-art="lauf"] { color: var(--text-leise); }
@media (prefers-reduced-motion: reduce) {
.chat__weg, .chat__anhang, .chat-datei { transition: none; }
}
@media (forced-colors: active) {
.chat-datei, .chat__ablage { border: 1px solid CanvasText; }
}