/*
 * Dunkel, weil der Feuerball auf hellem Grund nicht glüht.
 *
 * Alle Abstände unten rechnen mit safe-area-inset: auf dem iPhone liegt sonst
 * das Eingabefeld hinter der Home-Leiste, und man tippt daneben.
 */

:root {
  --ground: #08070c;
  --raised: #14121b;
  --line: #262232;
  --ink: #f2eee8;
  --muted: #8d8799;
  --ember: #ff8a3d;
  --ember-deep: #d9542b;
  --danger: #ff6b5e;
  --radius: 14px;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font:
    16px/1.5 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    system-ui,
    sans-serif;
  /* Sonst wippt die ganze Seite beim Scrollen im Home-Bildschirm-Modus. */
  overscroll-behavior: none;
}

/*
 * Muss VOR .screen stehen und !important tragen.
 *
 * Das Browser-Standardblatt setzt `[hidden] { display: none }` — aber eine
 * Klassenregel wie `.screen { display: flex }` ist spezifischer und gewinnt.
 * Ohne diese Zeile werden beide Bildschirme gezeichnet, der Kopplungsschirm
 * ist 100dvh hoch und deckt alles zu: die App zeigt dauerhaft die Kopplung,
 * obwohl das Token laengst da ist.
 *
 * Im JavaScript sieht dabei alles richtig aus — `pairing.hidden` ist `true`.
 * Aufgefallen ist es erst auf einem Bildschirmfoto.
 */
[hidden] {
  display: none !important;
}

.screen {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  padding: max(8px, env(safe-area-inset-top)) 14px max(10px, env(safe-area-inset-bottom));
}

.muted {
  color: var(--muted);
}
.small {
  font-size: 13px;
}
.error {
  color: var(--danger);
}

code {
  background: var(--raised);
  padding: 2px 6px;
  border-radius: 6px;
  font-size: 13px;
}

/* ---------------------------------------------------------- Der Ball */

/*
 * Der Ball nimmt sich den Platz, den er gerade verdient.
 *
 * Christians Wunsch klang widerspruechlich — Ball groesser, Chat groesser,
 * oben weniger hoch. Das geht, wenn die Groesse nicht fest ist: solange nichts
 * zu lesen ist, darf er den Bildschirm fuellen; sobald Text da ist, gehoert
 * der Platz dem Text.
 */
.orb {
  display: block;
  width: min(94vw, 420px);
  height: min(94vw, 420px);
  margin: 0 auto;
  flex: none;
  transition:
    width 420ms ease,
    height 420ms ease;
}

/* Sobald der erste Text steht. Gesetzt von app.js. */
#chat.chat--busy .orb {
  width: min(34vw, 128px);
  height: min(34vw, 128px);
  /* Der Ball fuellt seine Flaeche nicht ganz aus — ohne den negativen Abstand
     bleibt ringsum toter Rand, der unten im Gespraech fehlt. */
  margin: -6px auto -10px;
}

/*
 * Solange nichts zu lesen ist, gehoert dem Ball die ganze Flaeche — dann soll
 * er auch in ihrer Mitte sitzen. Vorher klebte er oben und darunter stand ein
 * halber Bildschirm Leere: der leere Verlauf nahm sich per `flex: 1` den Platz,
 * ohne etwas damit anzufangen.
 */
#chat:not(.chat--busy) #transcript {
  flex: none;
}

#chat:not(.chat--busy) .orb {
  margin: auto;
}

@media (prefers-reduced-motion: reduce) {
  .orb {
    transition: none;
  }
}

.orb--small {
  width: min(40vw, 150px);
  height: min(40vw, 150px);
}

/* ---------------------------------------------------------- Kopplung */

#pairing {
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 6px;
}

#pairing h1 {
  margin: 8px 0 0;
  font-size: 26px;
  letter-spacing: 0.24em;
  font-weight: 500;
}

#pairing-form {
  display: flex;
  gap: 8px;
  margin: 18px 0 8px;
  width: min(100%, 340px);
}

#pairing-code {
  flex: 1;
  text-align: center;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-size: 20px;
}

/* ---------------------------------------------------------- Gespräch */

/*
 * Flach halten. Jede Zeile hier fehlt unten im Gespraech — und das Gespraech
 * ist, wofuer die App da ist.
 */
#chat header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex: none;
  min-height: 28px;
}

/*
 * Das Etikett ("denkt nach", "liest das Postfach") stand als eigene Zeile
 * unter dem Ball und kostete dort Hoehe. In der Kopfzeile sagt es dasselbe
 * und kostet nichts.
 */
#orb-label {
  flex: 1;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#transcript {
  flex: 1;
  /* Ohne das waechst der Verlauf statt zu scrollen und schiebt die
     Eingabezeile aus dem Bild. */
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-bottom: 8px;
}

/*
 * Nachrichten stehen oben, direkt unter dem Ball.
 *
 * Der naheliegende Chat-Reflex waere, sie unten ankleben zu lassen
 * (`margin-top: auto` am ersten Kind). Ausprobiert und wieder verworfen: bei
 * wenigen Nachrichten sitzt die Leere dann zwischen Ball und Text, und der
 * Ball steht allein oben herum. So sitzt sie zwischen Text und Freigabekarte,
 * also an der Stelle, an der sie niemanden stoert. Bei einem laengeren
 * Gespraech laeuft der Verlauf ueber und der Unterschied verschwindet.
 */

.bubble {
  margin: 0;
  padding: 9px 12px;
  border-radius: var(--radius);
  max-width: 88%;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.bubble--ich {
  align-self: flex-end;
  background: var(--ember-deep);
  color: #fff;
}

.bubble--viktor {
  align-self: flex-start;
  background: var(--raised);
}

/*
 * Kein Gespraechsbeitrag, sondern eine Randnotiz: "fortgesetzt — zuletzt um
 * 09:40 Uhr". Muss sich klar von den Blasen absetzen, sonst liest es sich wie
 * etwas, das VIKTOR gesagt hat.
 */
.trenner {
  align-self: center;
  margin: 4px 0;
  text-align: center;
  opacity: 0.75;
}

.bubble--fehler {
  align-self: flex-start;
  background: #2a1618;
  color: var(--danger);
}

/*
 * Der Preis unter der Antwort.
 *
 * Leise und klein: er soll das Gespraech nicht stoeren, aber jedes Mal da sein.
 * Christian hat bisher erst auf der Abrechnung gesehen, was ein Zug kostet.
 */
.kostenzeile {
  align-self: flex-end;
  margin: -4px 0 0;
  opacity: 0.55;
  font-size: 11px;
}

/* ---------------------------------------------------------- Freigaben */

#approvals {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 32dvh;
  overflow-y: auto;
}

.approval {
  background: var(--raised);
  /* Der Rand ist das Dringlichkeitssignal — das Einzige, was man beim
     Runterschauen aufs Handgelenk noch erkennt. */
  border-left: 3px solid var(--ember);
  border-radius: var(--radius);
  padding: 12px 14px;
}

.approval--hoch,
.approval--kritisch {
  border-left-color: var(--danger);
}

.approval h3 {
  margin: 0 0 8px;
  font-size: 15px;
  font-weight: 600;
}

.approval dl {
  margin: 0 0 10px;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 12px;
  font-size: 14px;
}

.approval dt {
  color: var(--muted);
}
.approval dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.approval--done {
  opacity: 0.5;
  border-left-color: var(--muted);
}
.approval--failed {
  border-left-color: var(--danger);
}

/* ---------------------------------------------------------- Eingabe */

#composer {
  display: flex;
  gap: 8px;
  align-items: center;
  flex: none;
  padding-top: 10px;
}

#message {
  flex: 1;
}

input {
  background: var(--raised);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: var(--radius);
  padding: 12px 14px;
  /* Unter 16px zoomt iOS beim Antippen in die Seite hinein. */
  font-size: 16px;
  min-width: 0;
}

input:focus {
  outline: 2px solid var(--ember);
  outline-offset: -1px;
}

button {
  background: var(--ember);
  color: #1a0d05;
  border: 0;
  border-radius: var(--radius);
  padding: 12px 16px;
  font-size: 16px;
  font-weight: 600;
  /* 44px ist die Grenze, unter der man auf dem Telefon danebentippt. */
  min-height: 44px;
  min-width: 44px;
  cursor: pointer;
}

button:disabled {
  opacity: 0.45;
}

button.ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}

button.small {
  padding: 6px 10px;
  font-size: 13px;
  min-height: 34px;
}

.icon-button {
  background: transparent;
  color: var(--muted);
  font-size: 22px;
  padding: 0 10px;
}

.talk {
  background: var(--raised);
  border: 1px solid var(--line);
  font-size: 20px;
  color: var(--ember);
  /* Ein Halten darf nicht als Textauswahl enden. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.talk--active {
  background: var(--ember);
  transform: scale(1.06);
}

/*
 * Das Mikrofon-Emoji rendert als dunkle Glyphe und verschwand auf dem dunklen
 * Grund fast vollstaendig — auf dem Bildschirmfoto sass dort ein leerer
 * Kasten. Der Filter gehoert auf das Symbol, nicht auf den Knopf: sonst
 * bleicht er auch dessen Hintergrund aus.
 */
.talk span {
  display: block;
  filter: grayscale(1) brightness(2.8);
}

.talk--active span {
  filter: grayscale(1) brightness(0.3);
}

/* ---------------------------------------------------------- Geräte */

dialog {
  background: var(--raised);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  width: min(92vw, 400px);
}

dialog::backdrop {
  background: rgba(4, 3, 8, 0.7);
}

dialog h2 {
  margin: 0 0 12px;
  font-size: 17px;
}

#device-list {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

#device-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 8px;
}

select {
  flex: 1;
  background: var(--ground);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 10px;
  padding: 8px 10px;
  font-size: 16px;
  min-width: 0;
}

.row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.row--end {
  justify-content: flex-end;
}

/* Wer Bewegung abbestellt hat, bekommt einen ruhigen Ball statt gar keinem. */
@media (prefers-reduced-motion: reduce) {
  .talk--active {
    transform: none;
  }
  * {
    scroll-behavior: auto !important;
  }
}
