/* Die KI-Bubble.
 *
 * Gehoert zu views/partials/bubble.php. Das Markup dort ist stumm - die
 * gesamte Bewegung und Faerbung steckt hier und haengt an einem einzigen
 * Attribut: data-zustand.
 *
 *   ""        wartet    - eigene Farbe des Kunden, ruhige Stroemung
 *   hoert     nimmt auf - Gruen, schnellere und hoehere Wellen, Pulsring
 *   denkt     arbeitet  - Gelb, kurzes Tempo, die Kugel atmet
 *   spricht   liest vor - Blau, Wellen schlagen im Sprechrhythmus
 *   fehler    Abbruch   - Rot, Stroemung kommt fast zum Stillstand
 *
 * Warum die Ruhefarbe die des Kunden ist und die Zustaende feste Signal-
 * farben haben: die Personalisierung aus 09 soll erhalten bleiben, aber
 * "hoert gerade zu" muss auf jedem Geraet dasselbe Gruen sein, sonst ist
 * es keine Rueckmeldung, sondern Dekoration.
 *
 * **--bubble-farbe steht auf :root und nicht auf der Bubble selbst.**
 * thema.css hellt --deep im Dunkelmodus am <body> auf (45 % Farbe, 55 %
 * Fast-Weiss) - richtig fuer Raender, Links und den Verlaufsgrund, falsch
 * hier: Die Kugel erbte den bereits entsaettigten Wert und mischte ihn
 * ein zweites Mal gegen Weiss und Schwarz. Danach sahen alle sechs Toene
 * gleich aus. Auf :root ausgewertet steht dagegen der Wert, den die Seite
 * aus der Datenbank gesetzt hat; die Aufhellung am body greift dort nicht.
 *
 * **Gemischt wird in oklch, wo der Browser es kann.** Eine Mischung in
 * sRGB zieht die Buntheit mit der Helligkeit heraus - 38 % Farbe auf
 * Weiss ergab bei jeder der sechs Vorgaben dasselbe Hellgrau. oklch haelt
 * die Buntheit, waehrend nur die Helligkeit wandert. Der sRGB-Block
 * darueber bleibt als Rueckfall stehen und wird vom oklch-Block
 * ueberschrieben, wo er greift.
 *
 * Hell und dunkel brauchen dabei verschiedene Richtungen: Auf hellem
 * Papier muss die Kugel dunkler sein als der Grund, auf dunklem Grund
 * heller. Derselbe Mischwert fuer beide gibt es nicht.
 *
 * **Im Dunkelmodus reichte die frueher hier stehende Aufhellung nicht.**
 * Der Koerper der Kugel stand auf 88 % Kundenfarbe gegen Weiss - bei
 * einer Palette, die durchweg aus dunklen Toenen besteht (siehe
 * src/Bubblefarbe.php), ergab das eine fast schwarze Kugel auf fast
 * schwarzem Grund: sichtbar waren nur noch Rand und Ring. Der Koerper
 * geht deshalb auf 76 %, der Lichtkern auf 60 % und die Linien auf 36 %.
 * Die drei Werte haengen zusammen - wer einen aendert, muss die
 * Reihenfolge Koerper < Lichtkern < Linien einhalten, sonst verschwindet
 * die Zeichnung in der Flaeche.
 *
 * Die Zustandsfarben werden im selben Zug mit aufgehellt. Das ist
 * gewollt: Sie sollen sich vom Ruhezustand unterscheiden, nicht von der
 * Helligkeit des Bildschirms - und ein pastelliges Gruen ist auf dunklem
 * Grund immer noch eindeutig Gruen.
 *
 * Zum Tempo: --bubble-tempo ist die Zeit fuer eine Verschiebung um 100
 * viewBox-Einheiten. Bei 104px Kugeldurchmesser sind das rund 52 echte
 * Pixel. Die erste Fassung stand auf 26s - rechnerisch eine Animation,
 * auf dem Handy ein Standbild. Wer eine Bewegung nicht sieht, hat keine.
 * Die Zustaende sind bewusst mitgezogen worden: ihr Sinn ist der
 * Unterschied zur Ruhe, nicht ihr absolutes Tempo.
 *
 * Das Element ist breiter als hoch, weil links und rechts Wellen durch
 * das Bild laufen. --bubble-groesse ist deshalb der Durchmesser der
 * Kugel, nicht die Breite des Elements - die ergibt sich daraus.
 *
 * Kein Canvas, kein JavaScript, keine Filter: alles laeuft ueber
 * transform und opacity. Das ist der einzige Weg, eine dauerhaft laufende
 * Animation auf einem alten Handy zu haben, ohne dass der Akku es merkt.
 */

/* Die Farbe des Kunden, bevor thema.css sie am body aufhellt. */
:root{
  --bubble-farbe:var(--deep, #1f3a5f);
}

.bubble{
  --bubble-groesse:132px;  /* Durchmesser der Kugel */
  --bubble-basis:var(--bubble-farbe);
  --bubble-akzent:var(--bubble-basis);
  --bubble-tempo:11s;      /* Umlaufzeit der Wellen */
  --bubble-welle:.7;       /* Hoehenfaktor der Wellen */
  --bubble-schein:.22;     /* Staerke des Leuchthofs */
  /* Sichtbarkeit der Wellen neben der Kugel. In Ruhe zurueckhaltend:
     bei .55 liefen sie auf dem Handy bis an den Bildschirmrand und
     machten aus der Kugel ein ausgefranstes Motiv. Die Zustaende unten
     ziehen den Wert hoch - dort ist die Bewegung die Rueckmeldung. */
  --bubble-aussen:.38;

  /* Rueckfallwerte fuer Browser ohne color-mix. Sehen ordentlich aus,
     nur eben nicht aus der Kundenfarbe abgeleitet. */
  --k-mittel:var(--bubble-akzent);
  --k-hell:#cfe4ff;
  --k-tief:#0a1a24;

  position:relative;
  display:block;
  flex:none;
  width:calc(var(--bubble-groesse) * 1.7);
  height:var(--bubble-groesse);
  max-width:100%;
  border:0;
  padding:0;
  background:none;
  color:inherit;
  -webkit-tap-highlight-color:transparent;
}

/* Rueckfall in sRGB: blasser als die oklch-Fassung darunter, aber immer
   noch aus der Kundenfarbe abgeleitet. */
@supports (color: color-mix(in srgb, red 50%, blue)){
  .bubble{
    --k-hell:color-mix(in srgb, var(--bubble-akzent) 45%, #ffffff);
    --k-tief:color-mix(in srgb, var(--bubble-akzent) 78%, #05121b);
  }
  :root[data-thema="dunkel"] .bubble{
    --k-hell:color-mix(in srgb, var(--bubble-akzent) 36%, #ffffff);
    --k-mittel:color-mix(in srgb, var(--bubble-akzent) 60%, #ffffff);
    --k-tief:color-mix(in srgb, var(--bubble-akzent) 76%, #ffffff);
  }
}

@supports (color: color-mix(in oklch, red 50%, blue)){
  .bubble{
    --k-hell:color-mix(in oklch, var(--bubble-akzent) 45%, #ffffff);
    --k-tief:color-mix(in oklch, var(--bubble-akzent) 78%, #05121b);
  }
  /* Auf dunklem Grund darf die Kugel nicht abgedunkelt werden - sie
     verschwindet sonst im Hintergrund. Drei Stufen statt zwei: der
     Koerper hebt sich vom Grund ab, der Lichtkern vom Koerper, die
     Linien vom Lichtkern. */
  :root[data-thema="dunkel"] .bubble{
    --k-hell:color-mix(in oklch, var(--bubble-akzent) 36%, #ffffff);
    --k-mittel:color-mix(in oklch, var(--bubble-akzent) 60%, #ffffff);
    --k-tief:color-mix(in oklch, var(--bubble-akzent) 76%, #ffffff);
  }
}

/* Der Leuchthof traegt im Dunkeln mehr als im Hellen: Er ist dort das
   Einzige, was die Kugel vom Grund abhebt. */
:root[data-thema="dunkel"] .bubble{ --bubble-schein:.32 }

button.bubble{cursor:pointer}
button.bubble:focus-visible{outline:3px solid var(--ink,#14201d);outline-offset:6px;border-radius:12px}

.bubble svg{display:block;width:100%;height:100%}

/* Farbwechsel darf nicht springen - die halbe Sekunde ist der Unterschied
   zwischen "die Kugel wechselt die Stimmung" und "da blinkt was". */
.b-koerper,.b-band,.b-linie,.b-rand,.b-ring,.b-ring-vorn,.b-puls{
  transition:fill .55s ease, stroke .55s ease;
}
.b-aura{opacity:var(--bubble-schein);transition:opacity .55s ease}

/* Der weisse Glanzpunkt oben links stammt aus dem hellen Modus, wo er
   auf einer dunklen Kugel sitzt. Auf der aufgehellten Kugel im
   Dunkelmodus wird daraus ein grauer Fleck. Dort deutlich schwaecher. */
:root[data-thema="dunkel"] .b-glanz{opacity:.18}

/* --- Stroemung ------------------------------------------------------ */

.b-wellen{
  transform-box:view-box;
  transform-origin:100px 100px;
  transform:scaleY(var(--bubble-welle));
  transition:transform .6s ease;
}

/* Die Wellen links und rechts sind dieselben Linien - sie laufen einmal
   quer durchs Bild und verschwinden hinter der Kugel. Genau das macht
   den Eindruck, dass die Kugel in etwas drinsteckt und nicht davor
   klebt. Die weichen Enden kommen aus einer Maske, nicht aus einem
   Verlauf am Strich: ein Verlauf wuerde mitwandern. */
.b-aussen{
  transform-box:view-box;
  transform-origin:100px 100px;
  transform:scaleY(var(--bubble-welle));
  opacity:var(--bubble-aussen);
  transition:transform .6s ease, opacity .55s ease;
}

/* Die Pfade sind 600 Einheiten breit und wiederholen sich alle 100.
   Eine Verschiebung um genau 100 ist deshalb nahtlos - man sieht keinen
   Sprung, obwohl die Animation von vorn beginnt. */
.b-schicht{
  animation:b-fliessen var(--bubble-tempo) linear infinite;
  will-change:transform;
}
.b-schicht--rueck{animation-direction:reverse}

@keyframes b-fliessen{
  from{transform:translateX(0)}
  to{transform:translateX(-100px)}
}

/* --- Zustaende ------------------------------------------------------ */

.bubble[data-zustand="hoert"]{
  --bubble-akzent:#25b880;
  --bubble-tempo:5s;
  --bubble-welle:1.15;
  --bubble-schein:.5;
  --bubble-aussen:.85;
}

.bubble[data-zustand="denkt"]{
  --bubble-akzent:#d99a10;
  --bubble-tempo:3s;
  --bubble-welle:.85;
  --bubble-schein:.42;
  --bubble-aussen:.68;
}

.bubble[data-zustand="spricht"]{
  --bubble-akzent:#2f7dd1;
  --bubble-tempo:4s;
  --bubble-welle:1.2;
  --bubble-schein:.55;
  --bubble-aussen:.9;
}

.bubble[data-zustand="fehler"]{
  --bubble-akzent:#b8402f;
  --bubble-tempo:20s;
  --bubble-welle:.4;
  --bubble-schein:.3;
  --bubble-aussen:.2;
}

/* Der Ring nach aussen zeigt: es wird gerade aufgenommen. Das ist die
   Rueckmeldung, die auf Armlaenge noch erkennbar ist, wenn das Handy auf
   der Werkbank liegt. */
.b-puls{
  opacity:0;
  transform-box:view-box;
  transform-origin:100px 100px;
}
.bubble[data-zustand="hoert"] .b-puls{animation:b-puls 1.9s ease-out infinite}

@keyframes b-puls{
  0%{transform:scale(.88);opacity:.6}
  100%{transform:scale(1.32);opacity:0}
}

.bubble[data-zustand="denkt"] svg{
  animation:b-atmen 2.4s ease-in-out infinite;
  transform-origin:50% 50%;
}
@keyframes b-atmen{
  0%,100%{transform:scale(1)}
  50%{transform:scale(.94)}
}

/* Beim Vorlesen schlagen die Wellen hoeher und flacher - grob im Takt
   einer Stimme, innen wie aussen. Das ersetzt keine Pegelmessung, aber
   es beantwortet die Frage "redet sie noch oder haengt sie?". */
.bubble[data-zustand="spricht"] .b-wellen,
.bubble[data-zustand="spricht"] .b-aussen{
  animation:b-sprechen 1.15s ease-in-out infinite;
}
@keyframes b-sprechen{
  0%,100%{transform:scaleY(calc(var(--bubble-welle) * .65))}
  50%{transform:scaleY(calc(var(--bubble-welle) * 1.3))}
}

/* --- Beschriftung unter der Kugel ---------------------------------- */

/* Nur wo partials/bubble.php mit $bubbleHinweis eingebunden wird - heute
   die Hauptansicht. Dort war die Kugel die einzige Bedienung ohne
   Beschriftung, waehrend die Nebentaste "Foto aufnehmen" darunter eine
   hatte. Der Satz im Zustandstext verschwand nach fuenf Eintraegen im
   Betrieb - wer spaeter dazukam, erfuhr nie, dass die Kugel die
   Aufnahme ist.

   Das Element waechst dafuer nach unten, die Kugel behaelt ihre Hoehe.
   Die Zeile liegt im Knopf und ist damit selbst Trefferflaeche.
   font:inherit, weil ein <button> sonst die Systemschrift des Browsers
   an die Zeile weitergibt. */
.bubble--hinweis{height:auto;font:inherit}
.bubble--hinweis > svg{height:var(--bubble-groesse)}

.bubble-hinweis{
  display:flex;align-items:center;justify-content:center;gap:7px;
  margin-top:4px;
  font-size:.95rem;font-weight:600;line-height:1.3;
  color:var(--ink,#14201d);
  transition:opacity .3s ease;
}
/* Spezifischer als ".bubble svg" oben - sonst wird das Mikrofon so gross
   wie die Kugel. */
.bubble .bubble-hinweis svg{width:18px;height:18px;flex:none}

/* Waehrend Aufnahme, Verarbeitung und Vorlesen hat die Zeile nichts zu
   sagen - dann spricht der Zustandstext darunter. Unsichtbar statt
   entfernt, damit nichts springt. Bei "fehler" bleibt sie stehen: genau
   dann muss klar sein, wie es weitergeht. */
.bubble[data-zustand="hoert"] .bubble-hinweis,
.bubble[data-zustand="denkt"] .bubble-hinweis,
.bubble[data-zustand="spricht"] .bubble-hinweis{opacity:0}

/* Ohne Bewegung bleibt die Farbe als Rueckmeldung uebrig - die reicht,
   und sie ist der Teil, auf den es ankommt. */
@media (prefers-reduced-motion:reduce){
  .bubble svg,
  .bubble svg *{animation:none !important}
}
