Files
Webklar/src/components/home/demos/chat/chat.css
T
rootandClaude Opus 5.5 c1d775e090 Bühne: Live-Vorschau mit echter Bäckerei-Website, Chat als Live-Demo mit Zoom, weiches Zuklappen
- Live-Vorschau: Im MacBook steht die Beispiel-Website der Bäckerei Sonnenschein selbst
  (Startbereich, Sortiment, Backstube, Torten, Öffnungszeiten, Fuß; Instrument Serif,
  CC0-Fotos von Wikimedia Commons, nur Backwaren). Beim Scrollen durch die Station läuft
  sie einmal durch (--kp-v, nur transform). Portal-Aufnahmen (Projekte, Als App) neu mit
  derselben Website im Vorschaukasten.
- Chat: Portal-Chat als Live-Demo. Die Kamera zoomt aufs Gespräch, Foto anhängen, tippen,
  Sprachnachricht, Antworten von Kenso ploppen auf (spielerische Texte, Sie-Form). Das iPhone
  gleitet in dieser Station weg. Hinweis auf die E-Mail bei Team-Antworten (K17).
- „Funktionen“: Unterpunkte falten sich beim Verlassen ein, danach gleitet „Als App“ per FLIP
  nach oben (auch beim Aufklappen nach unten), Pfeil zeigt den Zustand.
- Schrittlängen je Station (normal, Demo, Vorschau, Chat), bei reduzierter Bewegung kurz.
- Tests: Bühne angepasst, neue Tests für Chat-Ablauf und Bäckerei-Website (287 grün).

Spezifikation: docs/superpowers/specs/2026-10-04-vorschau-chat.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 18:16:15 +00:00

384 lines
7.8 KiB
CSS

/*
* Chat-Demo (Station Chat): Live-Ebene über der Aufnahme des leeren Portal-Chats. Alle Klassen mit Präfix ch-.
* Desktop 1512 x 893 mit Kamera-Zoom, Handy 402 x 874. Farben und Formen wie im Portal (kundenbereich.css, chat-composer.css).
* Grundzustand statisch; Bewegung nur transform/opacity hinter prefers-reduced-motion: no-preference.
*/
.ch-seite {
position: absolute;
inset: 0;
overflow: hidden;
background: #0b0712;
}
/* Die Kamera: hineingezoomt füllt die Eingabezeile (822 px breit) das MacBook fast ganz, unten bleibt sie im Bild.
In der Station Chat gleitet das iPhone zur Seite (kundenportal.css), damit nichts das Gespräch verdeckt. */
.ch-kamera {
position: absolute;
left: 0;
top: 0;
width: 1512px;
height: 893px;
transform-origin: 0 0;
transform: scale(1) translate(0px, 0px);
}
.ch-kamera[data-zoom="ja"] {
transform: scale(1.8) translate(-472px, -246px);
}
.ch-kulisse {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: top;
}
.ch-handy {
position: absolute;
inset: 0;
pointer-events: none;
}
.ch-ebene {
position: absolute;
inset: 0;
pointer-events: none;
color: #fff;
font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
font-size: 16px;
line-height: 1.4;
text-align: left;
letter-spacing: normal;
-webkit-font-smoothing: antialiased;
user-select: none;
}
.ch-ebene *,
.ch-ebene *::before,
.ch-ebene *::after {
box-sizing: border-box;
margin: 0;
}
/* ── Nachrichten ─────────────────────────────────────────────────────── */
.ch-ausschnitt {
position: absolute;
overflow: hidden;
}
.ch-liste {
position: absolute;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
gap: 10px;
}
.ch-liste[data-aus="ja"] {
opacity: 0;
}
.ch-blase {
max-width: 76%;
padding: 11px 15px 10px;
border-radius: 16px;
font-size: 17px;
word-break: break-word;
}
[data-variante="handy"] .ch-blase {
max-width: 84%;
font-size: 15px;
}
.ch-blase--ich {
align-self: flex-end;
background: rgb(157 61 254 / 0.26);
border: 1px solid rgb(157 61 254 / 0.5);
border-bottom-right-radius: 4px;
transform-origin: 100% 100%;
}
.ch-blase--team {
align-self: flex-start;
background: rgb(255 255 255 / 0.06);
border: 1px solid rgb(255 255 255 / 0.16);
border-bottom-left-radius: 4px;
transform-origin: 0 100%;
}
.ch-text {
display: block;
}
.ch-meta {
display: block;
margin-top: 4px;
font-size: 12.5px;
opacity: 0.6;
}
.ch-blase--foto {
padding: 6px 6px 9px;
}
.ch-blase--foto .ch-text,
.ch-blase--foto .ch-meta {
padding: 0 9px;
}
.ch-blase--foto .ch-text {
margin-top: 8px;
}
.ch-foto {
display: block;
width: auto;
height: 236px;
border-radius: 11px;
}
[data-variante="handy"] .ch-foto {
width: 100%;
height: auto;
}
/* Sprachnachricht wie im Portal: Abspielknopf, Wort, Leiste, Dauer */
.ch-audio {
display: flex;
align-items: center;
gap: 10px;
width: 260px;
max-width: 100%;
padding: 2px 0;
}
.ch-audio__play {
flex: none;
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: 50%;
background: #fff;
color: #17102a;
}
.ch-audio__play svg {
width: 16px;
height: 16px;
}
.ch-audio__mitte {
flex: 1;
display: grid;
gap: 7px;
}
.ch-audio__wort {
font-size: 12px;
font-weight: 600;
opacity: 0.8;
}
.ch-audio__leiste {
display: block;
height: 6px;
border-radius: 999px;
background: rgb(255 255 255 / 0.2);
}
.ch-audio__zeit {
flex: none;
font-size: 12px;
font-variant-numeric: tabular-nums;
opacity: 0.8;
}
/* ── Eingabebereich ──────────────────────────────────────────────────── */
/* Anhang über dem Eingabefeld (wie die Vorschau im Portal vor dem Senden) */
.ch-anhang {
position: absolute;
width: 64px;
height: 64px;
border-radius: 12px;
border: 1px solid rgb(255 255 255 / 0.16);
overflow: hidden;
transform-origin: 0 100%;
}
.ch-anhang img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
/* Getippter Text: deckt das Platzhalter-Feld der Aufnahme ab; ist der Text länger, bleibt sein Ende sichtbar */
.ch-feld {
position: absolute;
display: flex;
align-items: center;
justify-content: flex-end;
overflow: hidden;
background: #171719;
border: 1px solid rgb(255 255 255 / 0.16);
font-size: 16px;
white-space: nowrap;
}
[data-variante="handy"] .ch-feld {
background: #1b1b1d;
}
.ch-feld__text {
flex: none;
min-width: 100%;
}
.ch-feld__strich {
display: inline-block;
width: 2px;
height: 1.15em;
margin-left: 1px;
vertical-align: -0.2em;
background: #c9a2ff;
}
.ch-senden {
position: absolute;
display: grid;
place-items: center;
border-radius: 999px;
background: #9d3dfe;
color: #fff;
font-size: 16px;
font-weight: 700;
}
.ch-senden svg {
width: 19px;
height: 19px;
}
/* Sprachaufnahme: rote Leiste statt Anhang, Textfeld und Mikrofon */
.ch-aufnahme {
position: absolute;
display: flex;
align-items: center;
gap: 10px;
padding: 0 6px 0 16px;
border-radius: 999px;
border: 1px solid rgb(248 113 113 / 0.45);
background: #1e1416;
font-size: 15px;
}
.ch-aufnahme__punkt {
flex: none;
width: 10px;
height: 10px;
border-radius: 50%;
background: #f87171;
}
.ch-aufnahme__wort {
flex: none;
font-size: 13px;
color: rgb(255 255 255 / 0.6);
}
.ch-aufnahme__zeit {
flex: none;
min-width: 36px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.ch-aufnahme__pegel {
flex: 1;
min-width: 0;
height: 24px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 2px;
overflow: hidden;
color: #fca5a5;
}
.ch-aufnahme__pegel i {
flex: none;
width: 3px;
height: 100%;
border-radius: 2px;
background: currentColor;
transform: scaleY(var(--ch-h, 0.5));
}
.ch-aufnahme__stopp {
flex: none;
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: 50%;
}
.ch-aufnahme__stopp::before {
content: "";
width: 12px;
height: 12px;
border-radius: 3px;
background: #f87171;
}
/* ── Bewegung ────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
.ch-kamera {
transition: transform 1150ms cubic-bezier(0.65, 0, 0.35, 1);
}
/* neue Nachricht: ploppt aus ihrer Ecke auf, mit einem kleinen Nachfedern */
.ch-blase {
animation: ch-auf 560ms cubic-bezier(0.2, 0.9, 0.3, 1.25) both;
}
.ch-liste {
transition: opacity 600ms ease;
}
.ch-anhang {
animation: ch-auf 420ms cubic-bezier(0.2, 0.9, 0.3, 1.25) both;
}
.ch-feld__strich {
animation: ch-blinken 1s steps(1) infinite;
}
.ch-senden[data-druck="ja"] {
animation: ch-druck 320ms ease-out both;
}
.ch-aufnahme {
animation: ch-einblenden 220ms ease-out both;
}
.ch-aufnahme__punkt {
animation: ch-pulsieren 1.2s ease-in-out infinite;
}
.ch-aufnahme__pegel i {
animation: ch-pegel 520ms ease-in-out infinite alternate;
}
}
@keyframes ch-auf {
from {
opacity: 0;
transform: translateY(14px) scale(0.86);
}
45% {
opacity: 1;
}
to {
opacity: 1;
transform: none;
}
}
@keyframes ch-blinken {
50% {
opacity: 0;
}
}
@keyframes ch-druck {
40% {
transform: scale(0.9);
}
to {
transform: none;
}
}
@keyframes ch-einblenden {
from {
opacity: 0;
}
}
@keyframes ch-pulsieren {
50% {
opacity: 0.25;
}
}
@keyframes ch-pegel {
from {
transform: scaleY(0.15);
}
to {
transform: scaleY(var(--ch-h, 0.5));
}
}