/* PV-Leads – Oberfläche
   ---------------------------------------------------------------------------
   Der Arbeitsbereich ist EINSPALTIG. In 3088_ics, von dem die Bedienung stammt,
   sind es zwei Spalten (Haushalte links, Detail rechts); hier liegt unter der
   Nadel direkt der Ausgang, es gibt also nichts auszuwählen. Nur die Verpackung
   wechselt mit der Geräteausrichtung:

   • Querformat (>= 900px): ein schmales Panel am rechten Kartenrand, die Karte
                            läuft daneben durch.
   • Hochformat (< 900px):  dasselbe Panel als Bottom-Sheet mit Griff
                            (halb / ganz / zu).

   Gestaltungsprinzip: ruhige Flächen, Haarlinien statt Rahmen, Bedeutung über
   Icon-Chips statt über Farbflächen. Jede Kachel trägt ein Icon im abgerundeten
   Quadrat – im Ruhezustand grau, aktiv in der Farbe der Sache. Primäre
   Touchziele bleiben bei mindestens 44px.

   Die eine Farbregel, die überall gilt: die sieben Ausgangsfarben sind dieselben
   wie in 3060_d2d und 3088_ics, und sie stehen im Skript (OUTCOME_TYPES), nicht
   hier. Das CSS bekommt sie je Element als --c gereicht.
*/

:root {
  --ink: #0f172a;
  --ink-2: #475569;
  --muted: #94a3b8;
  --line: #e6ebf2;
  --line-soft: #f1f5f9;
  --bg: #f6f8fb;
  --card: #ffffff;
  --accent: #2563eb;

  --topbar-h: 46px;
  --r-tile: 12px;
  --r-field: 10px;
  --shadow-tile: 0 1px 1.5px rgba(15, 23, 42, .03);
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0; padding: 0;
  height: 100%;
  overflow: hidden;             /* kein Seiten-Scroll – nur Panels scrollen */
  overscroll-behavior: none;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body { display: flex; flex-direction: column; }

button, input, textarea, select { font: inherit; color: inherit; }
svg { display: block; }

/* Ein `hidden`-Attribut muss stärker sein als jede display-Regel einer Klasse.
   Der Browser bringt dafür nur `[hidden] { display: none }` mit – und das
   verliert gegen jedes `.klasse { display: flex }`. Einmal zentral geklärt. */
[hidden] { display: none !important; }

/* ===========================================================================
   Kopfzeile
   =========================================================================== */

.topbar {
  flex: 0 0 auto;
  height: calc(var(--topbar-h) + var(--safe-top));
  padding: var(--safe-top) 12px 0;
  display: flex; align-items: center; gap: 14px;
  background: #0b1220; color: #f8fafc;
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, .07);
  z-index: 30;
}

.brand {
  display: flex; align-items: center; gap: 7px;
  font-weight: 700; letter-spacing: .08em; font-size: 12.5px;
  color: #7dd3fc; flex: 0 0 auto;
}

/* Das angemeldete Konto – als Schild neben der Marke. Auf einer GEMEINSAMEN
   Karte ist das keine Zierde: die eigenen Nadeln und die der anderen
   unterscheiden sich nur in der Deckkraft, und eine Nadel im falschen Namen
   fällt sonst erst Wochen später auf. Der Punkt davor trägt die Kontofarbe,
   dieselbe, die am Ring der eigenen Nadeln bei den anderen steht. */
.brand-konto {
  display: inline-flex; align-items: center; gap: 5px;
  max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 2px 8px 2px 6px; border-radius: 999px;
  background: rgba(125, 211, 252, .14);
  color: #bae6fd; font-weight: 600; font-size: 11px; letter-spacing: .02em;
  text-transform: lowercase;
}
.brand-konto::before {
  content: ''; flex: 0 0 auto;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--c, #38bdf8);
  box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .25);
}

.tabs { display: flex; gap: 2px; background: rgba(255, 255, 255, .07); padding: 3px; border-radius: 10px; }
.tab {
  appearance: none; border: 0; background: transparent; position: relative;
  color: #b5c2d3; font-size: 13px; font-weight: 600;
  padding: 6px 16px; border-radius: 7px; cursor: pointer; min-height: 30px;
  transition: background .15s, color .15s;
}
.tab.active { background: #f8fafc; color: #0b1220; }

/* Dringlichkeits-Zähler am Followup-Tab. Sitzt wie eine Benachrichtigung oben
   rechts an der Beschriftung; die Farbe kommt aus dem Skript (--fu-badge) und
   sagt, wie nah der nächste Termin ist. */
.tab-badge {
  position: absolute; top: -1px; right: 1px;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 999px;
  background: var(--fu-badge, #dc2626); color: var(--fu-badge-ink, #fff);
  font-size: 10.5px; font-weight: 700; line-height: 17px; text-align: center;
  font-variant-numeric: tabular-nums;
  --fu-ring: #0b1220;                    /* Rand in Kopfzeilenfarbe, damit er absetzt */
  box-shadow: 0 0 0 2px var(--fu-ring);
}
.tab.active .tab-badge { --fu-ring: #f8fafc; }
/* Platz für den Zähler, damit er nicht auf der Beschriftung sitzt – aber nur,
   solange er wirklich da ist. */
.tab:has(.tab-badge:not([hidden])) { padding-right: 26px; }

/* Fünf Minuten vor dem Termin (oder überfällig) schlägt der Zähler Alarm: zwei
   kurze Schläge, dann Ruhe. Ein Herzschlag fällt im Augenwinkel stärker auf als
   ein gleichmäßiges Pulsieren und nutzt sich langsamer ab. */
.tab-badge--alarm { animation: fu-alarm 1.4s ease-in-out infinite; }
@keyframes fu-alarm {
  0%   { transform: scale(1);    box-shadow: 0 0 0 2px var(--fu-ring), 0 0 0 0 rgba(220, 38, 38, 0); }
  11%  { transform: scale(1.35); box-shadow: 0 0 0 2px var(--fu-ring), 0 0 16px 6px rgba(220, 38, 38, .95); }
  22%  { transform: scale(1.06); box-shadow: 0 0 0 2px var(--fu-ring), 0 0 9px 3px rgba(220, 38, 38, .5); }
  33%  { transform: scale(1.32); box-shadow: 0 0 0 2px var(--fu-ring), 0 0 16px 6px rgba(220, 38, 38, .95); }
  52%  { transform: scale(1);    box-shadow: 0 0 0 2px var(--fu-ring), 0 0 7px 2px rgba(220, 38, 38, .4); }
  100% { transform: scale(1);    box-shadow: 0 0 0 2px var(--fu-ring), 0 0 0 0 rgba(220, 38, 38, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .tab-badge--alarm { animation: none; box-shadow: 0 0 0 2px var(--fu-ring), 0 0 12px 3px rgba(220, 38, 38, .85); }
}

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.stat-chip { font-size: 12px; color: #7d8da3; white-space: nowrap; font-variant-numeric: tabular-nums; }
.stat-chip b { color: #e8eef6; font-weight: 600; }

/* Der Live-Punkt: steht die Leitung zu den anderen Konten? Ohne sie sieht die
   Karte genauso aus, nur altert sie still – das hier ist die einzige Stelle,
   an der ein Abriss auffällt. */
.live {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px 3px 6px; border-radius: 999px;
  background: rgba(255, 255, 255, .06);
  font-size: 11.5px; font-weight: 600; color: #7d8da3;
  font-variant-numeric: tabular-nums;
}
.live i {
  width: 7px; height: 7px; border-radius: 50%;
  background: #64748b; flex: 0 0 auto;
  transition: background .2s, box-shadow .2s;
}
.live.on { color: #bbf7d0; }
.live.on i { background: #22c55e; box-shadow: 0 0 0 0 rgba(34, 197, 94, .6); animation: live-puls 2.4s ease-out infinite; }
@keyframes live-puls {
  0%   { box-shadow: 0 0 0 0 rgba(34, 197, 94, .55); }
  70%  { box-shadow: 0 0 0 6px rgba(34, 197, 94, 0); }
  100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); }
}
@media (prefers-reduced-motion: reduce) { .live.on i { animation: none; } }

/* ---- Kopfzeile auf dem Telefon: zwei Zeilen ------------------------------
   Sechs Tabs plus Marke, Live-Punkt und Tageszahl passen nicht in eine Zeile
   von 390px. Gelöst ohne Änderung am HTML: die Leiste darf umbrechen, die Tabs
   bekommen die volle Breite der zweiten Zeile und scrollen darin waagerecht.
   Weil sie zusammen breiter sind als der Bildschirm, steht an einer Kante stets
   ein angeschnittener Tab – das ist der Hinweis, dass es weitergeht. Dazu
   scrollt main.js den aktiven Tab in die Mitte. */
@media (max-width: 720px) {
  .topbar {
    height: auto;
    min-height: calc(var(--topbar-h) + var(--safe-top));
    flex-wrap: wrap;
    gap: 0 10px;
    padding: var(--safe-top) 10px 0;
  }
  .tabs {
    order: 2;
    flex: 0 0 100%;
    /* Bis an beide Bildschirmkanten, damit der angeschnittene Tab nicht in
       einem Innenabstand endet und wie ein Fehler aussieht. */
    margin: 3px -10px 0;
    width: calc(100% + 20px);
    border-radius: 0;
    background: transparent;
    /* Der Innenabstand oben/unten hält Platz für den Followup-Zähler und seinen
       Alarmring: overflow-x macht auch die Y-Achse beschneidend. */
    padding: 6px 10px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tab {
    flex: 0 0 auto;
    min-height: 40px;                      /* Daumenziel statt 30px */
    padding: 9px 14px;
    font-size: 13.5px;
  }
  .tab-badge { top: 2px; right: 3px; }
  .brand { padding: 3px 0; }
}
@media (max-width: 400px) {
  .stat-chip { display: none; }            /* der Live-Punkt bleibt */
}

/* ===========================================================================
   Ansichten
   =========================================================================== */

.views { flex: 1 1 auto; position: relative; min-height: 0; }
.view { display: none; position: absolute; inset: 0; }
.view.active { display: block; }

/* Die Karte ist die EINZIGE Ansicht, die nie auf `display:none` fällt.

   Sie zeichnet auf einer WebGL-Fläche (renderingType VECTOR). Ein Kasten mit
   `display:none` hat 0×0 Pixel, und eine WebGL-Fläche ohne Maße ist für den
   Browser eine, die niemand mehr braucht: er kassiert ihren Zeichenkontext ein
   – auf dem iPhone schon nach Sekunden, wenn das Gerät knapp an Speicher ist.
   Zurück auf dem Kartentab stand dann das letzte Bild da und ließ sich nicht
   mehr schieben.

   Also bleibt sie im Layout stehen und wird nur unsichtbar geschaltet:
   `visibility` nimmt sie aus dem Bild UND aus der Trefferprüfung, lässt ihr aber
   ihre Größe – und damit den Zeichenkontext. Der zweite Halt für denselben Fall
   steht in main.js (karteHeilen). */
#view-map { display: block; }
/* Auch alles DARIN, nicht nur die Hülle: `visibility` vererbt sich zwar, ein
   Kind darf sich mit `visibility: visible` aber wieder hervorholen. */
#view-map:not(.active),
#view-map:not(.active) * { visibility: hidden; }

.map-area { position: absolute; inset: 0; }
#map { position: absolute; inset: 0; background: #dde4ed; }

.list-wrap {
  position: absolute; inset: 0;
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 12px 12px calc(24px + var(--safe-bottom));
}

/* Kartenausfall: Google Maps kommt über das Netz, und unterwegs kommt es
   manchmal nicht. Statt einer grauen Fläche, über die man rätselt, steht dann
   hier, was los ist und was trotzdem geht. */
.map-fehler {
  position: absolute; z-index: 18;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(320px, calc(100% - 32px));
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  padding: 20px 18px; border-radius: 16px; text-align: center;
  background: #fff; color: var(--ink-2);
  box-shadow: 0 8px 28px rgba(15, 23, 42, .18), 0 2px 6px rgba(15, 23, 42, .08);
}
.map-fehler strong { font-size: 15px; font-weight: 650; color: var(--ink); }
.map-fehler span { font-size: 13px; line-height: 1.5; }
.map-fehler-btn {
  appearance: none; border: 0; cursor: pointer; margin-top: 3px;
  padding: 9px 16px; border-radius: 11px;
  background: var(--accent); color: #fff; font-size: 13px; font-weight: 600;
}

/* ===========================================================================
   Kartensteuerung
   ===========================================================================
   Liegt mittig unten über der Karte: Joystick (Zoom, Drehen, Standort) und
   daneben der Schalter für die fremden Nadeln. Mittig statt am Rand, damit sie
   im Hoch- wie im Querformat mit beiden Daumen erreichbar ist. Das Blatt legt
   sich beim Aufziehen darüber – ausweichen muss sie ihm also nicht. */

.map-controls {
  position: absolute; z-index: 19;
  left: 50%; bottom: calc(var(--safe-bottom) + 16px);
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 9px;
  transition: left .2s ease, bottom .26s cubic-bezier(.32, .72, 0, 1), opacity .2s;
}

.map-ctrl {
  appearance: none; border: 1px solid rgba(15, 23, 42, .06); cursor: pointer;
  width: 46px; height: 46px; border-radius: 14px; flex: 0 0 auto;
  background: #fff; color: var(--ink-2);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(15, 23, 42, .16), 0 1px 3px rgba(15, 23, 42, .08);
  transition: transform .12s ease, color .15s, background .15s;
}
.map-ctrl:active { transform: scale(.93); }
.map-ctrl.active { color: var(--accent); }

/* Der Schalter für die fremden Nadeln hängt NEBEN der Reihe statt in ihr: sonst
   schöbe er den Joystick um seine halbe Breite aus der Mitte, und der muss
   mittig unter dem Daumen liegen. Ausgeschaltet ist er durchgestrichen – ein
   bloß blasser Knopf sähe aus wie einer, der gerade nicht geht. */
#ctrlFremde { position: absolute; left: calc(100% + 9px); top: 50%; transform: translateY(-50%); }
#ctrlFremde:active { transform: translateY(-50%) scale(.93); }
#ctrlFremde.aus { color: #b4bfcd; background: #f1f5f9; }
#ctrlFremde.aus::after {
  content: ''; position: absolute; left: 9px; right: 9px; top: 50%;
  height: 2px; border-radius: 2px; background: #94a3b8;
  transform: rotate(-38deg);
}

/* Joystick: runder Hebel mit zwei Achsen, die Auslenkung bestimmt das Tempo.
   Hoch/runter zoomt, links/rechts dreht die Karte, ein Druck in die Mitte holt
   den Standort. Er ist größer als die runden Knöpfe und ragt aus der Reihe nach
   oben wie nach unten heraus – die vier Hinweise sitzen an seinen Rändern,
   damit man auch ohne Erklärung sieht, wohin sich der Knopf ziehen lässt. */
.map-ctrl.joystick {
  width: 104px; height: 104px; border-radius: 50%;
  position: relative; padding: 0;
  cursor: grab; touch-action: none;
}
.map-ctrl.joystick:active { transform: none; }   /* nicht das ganze Pad stauchen */
.map-ctrl.joystick.dragging { border-color: rgba(37, 99, 235, .35); cursor: grabbing; }
.joy-hint {
  position: absolute; width: 15px; height: 15px; color: #b3bfcf;
  pointer-events: none; user-select: none; z-index: 1;
}
.joy-up    { top: 7px;    left: 50%; transform: translateX(-50%); }
.joy-down  { bottom: 7px; left: 50%; transform: translateX(-50%); }
/* Beide Dreh-Pfeile sind dasselbe Bild; der linke wird gespiegelt. */
.joy-left  { left: 8px;   top: 50%;  transform: translateY(-50%) scaleX(-1); }
.joy-right { right: 8px;  top: 50%;  transform: translateY(-50%); }
.joy-knob {
  position: absolute; left: 50%; top: 50%;
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 2px 7px rgba(15, 23, 42, .3);
  transform: translate(-50%, -50%);
  transition: transform .14s cubic-bezier(.2, .8, .3, 1);
  display: flex; align-items: center; justify-content: center;
}
/* Das Fadenkreuz im Knopf. Es ersetzt einen eigenen Standort-Knopf: nur daran
   ist zu sehen, dass ein Druck in die Mitte den Standort holt. */
.joy-me {
  width: 20px; height: 20px; color: #fff; opacity: .58;
  pointer-events: none; transition: opacity .18s ease;
}
.map-ctrl.joystick.active .joy-me { opacity: 1; }
/* Während die Ortung läuft, pulst das Fadenkreuz. Das ist die Antwort auf den
   Tipp: ein Fix kann draußen Sekunden dauern, und ohne sichtbares „ich suche"
   hält man den Knopf für kaputt und drückt weiter. */
@keyframes joy-sucht { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.map-ctrl.joystick.sucht .joy-me { animation: joy-sucht 1s ease-in-out infinite; }
.map-ctrl.joystick.dragging .joy-knob {
  transition: none;
  box-shadow: 0 2px 10px rgba(15, 23, 42, .4), 0 0 0 5px rgba(37, 99, 235, .22);
}
@keyframes joy-tap { from { box-shadow: 0 2px 7px rgba(15, 23, 42, .3), 0 0 0 0 rgba(37, 99, 235, .35); }
                     to   { box-shadow: 0 2px 7px rgba(15, 23, 42, .3), 0 0 0 16px rgba(37, 99, 235, 0); } }
.joy-knob.tapped { animation: joy-tap .45s ease-out; }

/* ---- Eigener Standort ----
   Blauer Punkt, bewusst rund und ohne Spitze: er ist keine Nadel, sondern zeigt,
   wo man selbst steht. Nadeln hängen mit der Unterkante am Ort – der Punkt wird
   um seine halbe Höhe nach unten geschoben, damit seine MITTE auf dem Standort
   sitzt. */
.me-dot {
  position: relative;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent);
  border: 3px solid #fff;
  box-shadow: 0 2px 8px rgba(15, 23, 42, .45);
  transform: translateY(50%);
  pointer-events: none;
}
.me-dot::after {
  content: ''; position: absolute; inset: -3px;
  border-radius: 50%; background: rgba(37, 99, 235, .35);
  animation: me-pulse 2s ease-out infinite;
}
@keyframes me-pulse {
  0%   { transform: scale(1);   opacity: .55; }
  70%  { transform: scale(2.6); opacity: 0; }
  100% { transform: scale(2.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .me-dot::after { animation: none; opacity: 0; } }

/* ===========================================================================
   Nadeln
   ===========================================================================
   Tropfenform, mit der Spitze am Ort. Die Füllung ist die Farbe des Ausgangs –
   dieselbe wie auf den Ausgangskacheln und in jeder Liste, damit sich eine
   Nadel ohne Umrechnung lesen lässt. */

.pin {
  position: relative;
  width: 32px; height: 32px; border-radius: 50% 50% 50% 4px;
  transform: rotate(-45deg);
  background: var(--pin-color, #64748b);
  border: 2.5px solid #fff;
  box-shadow: 0 3px 9px rgba(15, 23, 42, .42);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
/* Offene Nadel: weiß gefüllt. Weil der Rand aller Nadeln ebenfalls weiß ist,
   bekäme sie sonst gar keine Kontur – der dunkle Ring übernimmt das. */
.pin.offen {
  box-shadow: 0 0 0 1.5px rgba(15, 23, 42, .55), 0 3px 9px rgba(15, 23, 42, .42);
}

/* ---- Die Nadeln der anderen ----
   Halbe Deckkraft, und darum der Ring in der Farbe ihres Kontos. Die Deckkraft
   sagt „nicht meine" – sie sagt aber nicht, WESSEN, und bei zwei Leuten in
   derselben Straße ist genau das die Frage. Ein Name passt auf 32px nicht, eine
   Farbe schon. Dieselbe Farbe trägt das Konto in der Mannschaftsliste, in der
   Übersicht und am eigenen Schild in der Kopfzeile. */
.pin.fremd {
  opacity: .5;
  box-shadow: 0 0 0 2.5px var(--pin-owner, #64748b), 0 3px 9px rgba(15, 23, 42, .42);
}
.pin.fremd.offen {
  box-shadow: 0 0 0 1.5px rgba(15, 23, 42, .45), 0 0 0 4px var(--pin-owner, #64748b),
              0 3px 9px rgba(15, 23, 42, .42);
}
/* Eine fremde Nadel, die GERADE über die Leitung hereingekommen ist, blitzt
   einmal auf. Ohne das erscheint sie lautlos, und man hält sie beim nächsten
   Blick für eine, die schon immer da war. */
.pin.neu { animation: pin-neu 1.6s cubic-bezier(.22, 1, .36, 1); z-index: 9; }
@keyframes pin-neu {
  0%   { opacity: 0;  transform: rotate(-45deg) scale(.3); }
  35%  { opacity: 1;  transform: rotate(-45deg) scale(1.28); }
  55%  { opacity: 1;  transform: rotate(-45deg) scale(1); }
  100% { opacity: .5; transform: rotate(-45deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) { .pin.neu { animation: none; } }

/* Die Zahl steht auf der Farbe des Ausgangs – die reicht von hellem
   Followup-Gelb bis zum fast schwarzen „Übersprungen". Welche Schriftfarbe
   darauf lesbar ist, rechnet pinInk() je Nadel aus (--pin-ink). */
.pin span {
  transform: rotate(45deg);
  color: var(--pin-ink, var(--ink)); font-size: 12.5px; font-weight: 700; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}
.pin.selected {
  width: 40px; height: 40px; z-index: 10;
  opacity: 1;                                  /* auch eine fremde steht offen voll da */
  box-shadow: 0 0 0 4px rgba(37, 99, 235, .45), 0 5px 14px rgba(15, 23, 42, .45);
}
.pin.selected span { font-size: 14px; }
/* Am Finger: gestrichelter Ring und ein Hauch größer. Der Unterschied muss aus
   dem Augenwinkel erkennbar sein – man schaut beim Ziehen auf die Karte, nicht
   auf den Knopf, den man gerade gedrückt hat. */
.pin.ziehbar { cursor: grab; outline: 2.5px dashed var(--accent); outline-offset: 3px; }
.pin.ziehbar:active { cursor: grabbing; }
/* Während ein Haus am Finger hängt, tritt der Rest der Karte zurück – sonst
   greift man im Gedränge die falsche Nadel. */
body.move-mode .pin:not(.ziehbar), body.move-mode .cluster { opacity: .35; }

/* Die Blase hängt wie jede Nadel mit ihrer Unterkante am Ort – die halbe Höhe
   zurück, damit ihre MITTE auf der Lage sitzt. Ohne das säße sie um ihren halben
   Durchmesser darüber, und der ist je nach Größe verschieden. */
.cluster {
  --fill: #cbd5e1;
  transform: translateY(50%);
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--fill);
  box-shadow: 0 0 0 2px #fff, 0 3px 10px rgba(15, 23, 42, .42);
  color: var(--ink); font-weight: 700; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

/* ===========================================================================
   Das Ausgangs-Blatt
   ===========================================================================
   Das Blatt, das ein Kartentipp aufzieht: oben, wonach gefragt wird, in der
   Mitte die sieben Ausgänge als Kacheln, unten die Wege aus dem Blatt heraus
   (verschieben, löschen, abbrechen).

   Im Hochformat kommt es von unten und deckt gut die halbe Höhe ab – der
   Daumen erreicht jede Kachel, ohne dass die Hand umgreift. Am Schreibtisch
   steht dasselbe Blatt als Kärtchen in der Mitte.

   Es hängt am <body>, nicht in der Kartenansicht: so deckt es auch die
   Kopfzeile ab, und beim Schließen verschwindet es spurlos. */

.blatt {
  position: fixed; inset: 0; z-index: 70;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(15, 23, 42, .45);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  animation: blatt-grund .18s ease;
}
@keyframes blatt-grund { from { opacity: 0; } to { opacity: 1; } }

.blatt-box {
  width: min(460px, 100%);
  max-height: 88%;
  background: var(--card);
  border-radius: 22px 22px 0 0;
  padding: 0 14px calc(14px + var(--safe-bottom));
  display: flex; flex-direction: column; gap: 12px;
  box-shadow: 0 -12px 40px rgba(15, 23, 42, .3);
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  animation: blatt-auf .24s cubic-bezier(.32, .72, 0, 1);
}
@keyframes blatt-auf { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* Beim Schließen gleitet es hinaus, statt schlagartig zu verschwinden – ein
   Abbruch soll nicht aussehen wie ein Fehler. */
.blatt.zu { animation: blatt-grund .18s ease reverse forwards; pointer-events: none; }
.blatt.zu .blatt-box { animation: blatt-auf .18s cubic-bezier(.32, .72, 0, 1) reverse forwards; }

/* Wird nur der INHALT ersetzt (eine Meldung von der Leitung zur offenen Nadel),
   soll das Blatt nicht noch einmal hereinfahren. */
.blatt.ohne-anlauf, .blatt.ohne-anlauf .blatt-box { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .blatt, .blatt-box, .blatt.zu, .blatt.zu .blatt-box { animation: none; }
}

@media (min-width: 640px) {
  .blatt { align-items: center; }
  .blatt-box {
    border-radius: 20px;
    padding: 0 16px 16px;
    max-height: 86%;
    box-shadow: 0 18px 50px rgba(15, 23, 42, .32);
    animation: blatt-mitte .2s cubic-bezier(.2, .9, .3, 1);
  }
  @keyframes blatt-mitte {
    from { transform: translateY(14px) scale(.97); opacity: 0; }
    to   { transform: none; opacity: 1; }
  }
  .blatt.zu .blatt-box { animation: blatt-mitte .16s ease reverse forwards; }
  .blatt-griff { display: none; }
}

/* Der Griff ist hier reine Zierde – gezogen wird am Blatt nicht. Er sagt aber
   auf einen Blick „das kam von unten und geht auch wieder dorthin". */
.blatt-griff {
  flex: 0 0 auto; align-self: center;
  width: 40px; height: 4px; border-radius: 3px; background: #d3dbe5;
  margin: 10px 0 2px;
}

/* Der Kopf klebt oben: bei sieben Kacheln und einem Verlauf darunter scrollt
   das Blatt, und dann muss sichtbar bleiben, worum es geht. */
.blatt-kopf {
  position: sticky; top: 0; z-index: 2;
  flex: 0 0 auto;
  display: flex; align-items: flex-start; gap: 10px;
  padding: 6px 0 10px;
  background: var(--card);
  border-bottom: 1px solid var(--line-soft);
}
.blatt-titel { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.blatt-titel strong { font-size: 16px; font-weight: 650; letter-spacing: -.01em; }
.blatt-titel small {
  font-size: 12px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---- Die sieben Ausgänge ----
   Drei je Reihe. „Übersprungen" nimmt die letzte Reihe ganz – er ist kein
   Ergebnis eines Gesprächs, sondern die Ansage „hier war ich nicht", und
   steht darum auch optisch für sich. */
.ab-raster {
  flex: 0 0 auto;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  padding-bottom: 2px;
}
.ab-kachel {
  appearance: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  min-height: 84px; padding: 10px 6px;
  border: 1px solid var(--line); border-radius: 16px;
  background: #fff; color: var(--ink-2);
  box-shadow: var(--shadow-tile);
  transition: transform .12s ease, border-color .15s, background .15s, box-shadow .15s;
}
.ab-kachel.breit { grid-column: 1 / -1; flex-direction: row; gap: 9px; min-height: 56px; }
/* Der Druck muss am Finger ankommen: die Kachel IST die Antwort, es gibt kein
   „Übernehmen" dahinter. */
.ab-kachel:active { transform: scale(.96); background: var(--line-soft); }
.ab-ic { color: var(--c); display: flex; }
.ab-l { font-size: 11.5px; font-weight: 650; line-height: 1.15; text-align: center;
        overflow-wrap: anywhere; hyphens: auto; }
/* Der gesetzte Ausgang trägt seine Farbe voll – man soll beim Aufschlagen des
   Blattes sehen, was hier schon steht, ohne die Kopfzeile zu lesen. */
.ab-kachel.on {
  background: color-mix(in srgb, var(--c) 8%, #fff);
  border-color: color-mix(in srgb, var(--c) 45%, #fff);
  color: color-mix(in srgb, var(--c) 74%, #0f172a);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--c) 22%, #fff);
}
.ab-kachel.on .ab-ic { color: var(--c); }

/* ---- Fuß des Blattes ---- */
.blatt-fuss {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding-top: 2px;
}
.blatt-fuss .btn { flex: 1 1 0; }
.blatt-fuss.fragt { flex-wrap: wrap; }
.fuss-frage {
  flex: 1 0 100%; font-size: 13px; font-weight: 600; color: #b91c1c;
  padding: 2px 2px 4px;
}
.btn.gefahr { background: #dc2626; border-color: #dc2626; color: #fff; }
.btn.gefahr:active { background: #b91c1c; }

/* ---- Zum Lesen: die Nadel eines anderen Kontos ---- */
.lese-wer { display: flex; align-items: center; gap: 7px; color: var(--c); }
.fremd-punkt {
  flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%;
  background: var(--c); opacity: .4;
}
.fremd-punkt.on { opacity: 1; box-shadow: 0 0 0 3px color-mix(in srgb, var(--c) 22%, transparent); }

.lese-chip {
  display: flex; align-items: center; gap: 11px;
  padding: 12px; border-radius: 16px;
  border: 1px solid color-mix(in srgb, var(--c, #cbd5e1) 35%, #fff);
  background: color-mix(in srgb, var(--c, #cbd5e1) 7%, #fff);
}
.lese-chip .tile-ic { background: var(--c, #94a3b8); color: #fff; width: 34px; height: 34px; border-radius: 11px; }
.lese-l { display: flex; flex-direction: column; min-width: 0; }
.lese-l strong { font-size: 14.5px; font-weight: 650; }
.lese-l small { font-size: 12px; color: var(--muted); }

.lese-verlauf > h4 {
  margin: 0 0 4px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .09em; color: var(--muted);
}
.hist { display: flex; flex-direction: column; gap: 2px; }
.hist-row { display: flex; align-items: center; gap: 9px; padding: 4px 0; }
.hist-ic {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--c) 12%, #fff); color: var(--c);
}
.hist-label { flex: 1 1 auto; font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.hist-time { flex: 0 0 auto; font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* Der gemeinsame Icon-Chip – gebraucht ihn nur noch der Lese-Chip. */
.tile-ic {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  background: var(--line-soft); color: #a5b2c4;
}

/* ===========================================================================
   Eingabefelder mit Icon
   ===========================================================================
   Nur noch die Suche in der Übersicht – an einer Nadel gibt es nichts zu
   tippen. */

.ifield { position: relative; }
.ifield-ic {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  display: flex; color: #a5b2c4; pointer-events: none;
  transition: color .15s;
}
.ifield input {
  width: 100%; display: block; appearance: none;
  border: 1px solid var(--line); border-radius: var(--r-field);
  background: #fff; color: var(--ink);
  padding: 9px 11px 9px 38px; min-height: 40px;
  font-size: 13.5px;
  transition: border-color .15s, box-shadow .15s;
}
.ifield input::placeholder { color: #aab6c6; }
.ifield input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, .12);
}
.ifield:focus-within .ifield-ic { color: var(--accent); }
.ifield-sm .ifield-ic { left: 9px; }
.ifield-sm input { min-height: 36px; padding: 7px 9px 7px 32px; font-size: 13px; font-weight: 600; }

/* ===========================================================================
   Knöpfe
   =========================================================================== */

.icon-btn {
  appearance: none; border: 1px solid var(--line); background: #fff; cursor: pointer;
  width: 34px; height: 34px; border-radius: 10px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center; color: var(--ink-2);
  transition: background .15s, color .15s, border-color .15s;
}
.icon-btn:active { background: var(--line-soft); }

.btn {
  appearance: none; cursor: pointer;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  border-radius: var(--r-tile); padding: 8px 12px; min-height: 44px;
  font-size: 13px; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  transition: background .15s, border-color .15s, color .15s;
}
.btn:active { background: var(--line-soft); }
.btn.block { width: 100%; }
.btn.ghost-danger { color: #e11d48; border-color: #fadfe4; background: #fff; }
.btn.ghost-danger:active { background: #fff1f2; }

.chip {
  appearance: none; cursor: pointer;
  border: 1px solid var(--line); background: #fff; color: var(--ink-2);
  border-radius: 999px; padding: 6px 12px; min-height: 34px;
  font-size: 12.5px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px;
  transition: background .15s, border-color .15s, color .15s;
}
.chip:active { background: var(--line-soft); }
.chip.on { border-color: var(--accent); color: var(--accent); background: rgba(37, 99, 235, .07); }

/* ===========================================================================
   Listen (Übersicht, Mannschaft)
   =========================================================================== */

.filterbar {
  display: flex; flex-direction: column; gap: 8px;
  margin-bottom: 10px;
}
.fkacheln { display: grid; grid-template-columns: repeat(8, 1fr); gap: 5px; }
.fkachel {
  appearance: none; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px; background: #fff;
  min-height: 40px; padding: 4px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-tile);
  transition: border-color .15s, background .15s;
}
.fkachel .tile-ic { width: 26px; height: 26px; border-radius: 8px; background: transparent; color: var(--c); }
.fkachel.on { border-color: color-mix(in srgb, var(--c) 45%, #fff); background: color-mix(in srgb, var(--c) 8%, #fff); }
.fkachel.on .tile-ic { background: var(--c); color: #fff; }

.frow { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.frow-n { margin-left: auto; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

.liste { display: flex; flex-direction: column; gap: 6px; }

/* Eine Zeile: Farbpunkt des Ausgangs, Adresse, Zeit. Als <button>, damit sie
   mit der Tastatur erreichbar ist und auf dem Telefon ein sauberes Touchziel
   abgibt. */
.lz {
  appearance: none; cursor: pointer; text-align: left; width: 100%;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; min-height: 56px;
  border: 1px solid var(--line); border-radius: var(--r-tile);
  background: var(--card); box-shadow: var(--shadow-tile);
  transition: border-color .15s, background .15s;
}
.lz:active { background: var(--line-soft); }
/* Eine fremde Zeile steht leiser da – wie die Nadel auf der Karte, nur nicht
   ganz so blass: in einer Liste muss man sie lesen können. */
.lz.fremd { background: #fbfcfe; border-style: dashed; }
.lz-dot {
  flex: 0 0 auto; width: 12px; height: 12px; border-radius: 50%;
  background: var(--c, #cbd5e1); box-shadow: 0 0 0 1.5px rgba(15, 23, 42, .18);
}
.lz-mid { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lz-mid strong {
  font-size: 13.5px; font-weight: 650; letter-spacing: -.005em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lz-mid small {
  font-size: 11.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lz-right { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
.lz-time { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.lz-time.rot { color: #dc2626; font-weight: 700; }
.lz-wer {
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
  padding: 1px 7px; border-radius: 999px; white-space: nowrap;
  max-width: 10ch; overflow: hidden; text-overflow: ellipsis;
  background: color-mix(in srgb, var(--c) 13%, #fff); color: var(--c);
}
.lz.fu.ueber { border-color: #fca5a5; background: #fff7f7; }

.leer {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 48px 20px; color: var(--muted); text-align: center; font-size: 13px;
}
.leer svg { color: #cbd5e1; }

/* ===========================================================================
   Mannschaft
   =========================================================================== */

.tz-avatar {
  position: relative; flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--c) 14%, #fff);
  color: var(--c); font-size: 12.5px; font-weight: 800; letter-spacing: .02em;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--c) 32%, #fff);
}
/* Der grüne Punkt sagt: dieses Konto hat gerade eine offene Leitung, ist also
   draußen unterwegs. Er kommt vom Server (SSE), nicht aus einer Vermutung. */
.tz-on {
  position: absolute; right: -3px; bottom: -3px;
  width: 11px; height: 11px; border-radius: 50%;
  background: #cbd5e1; box-shadow: 0 0 0 2.5px #fff;
}
.tz-on.an { background: #22c55e; }
.tz.ich { border-color: color-mix(in srgb, var(--accent) 35%, #fff); }
.tz-ich { font-size: 10px; font-weight: 700; color: var(--accent); text-transform: uppercase; letter-spacing: .06em; }
.tz-heute { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.tz-heute b { font-size: 15px; color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
.tz-ab {
  font-size: 10.5px; font-weight: 700; padding: 1px 7px; border-radius: 999px;
  background: #e7f8ee; color: #15803d;
}

/* ===========================================================================
   Statistik
   =========================================================================== */

.sblock { margin: 0 0 18px; }
.sblock > h3 {
  margin: 0 0 8px; padding: 0 2px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}

.skacheln { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; }
.skachel {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 12px 6px; border-radius: var(--r-tile);
  border: 1px solid var(--line); background: var(--card); box-shadow: var(--shadow-tile);
}
.sk-v { font-size: 20px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.sk-l { font-size: 11px; color: var(--muted); text-align: center; }

.vbars { display: flex; flex-direction: column; gap: 4px; }
.vbar {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 10px; border-radius: 10px; background: var(--card);
  border: 1px solid var(--line); box-shadow: var(--shadow-tile);
}
.vbar-ic { flex: 0 0 auto; color: var(--c); display: flex; }
.vbar-l { flex: 0 0 118px; font-size: 12px; font-weight: 600; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vbar-track { flex: 1 1 auto; height: 8px; border-radius: 999px; background: var(--line-soft); overflow: hidden; }
.vbar-fill { display: block; height: 100%; border-radius: 999px; background: var(--c); transition: width .25s ease; }
.vbar-n { flex: 0 0 auto; min-width: 28px; text-align: right;
  font-size: 12.5px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* Tagesstreifen: ein Balken je Tag, Höhe = Türen, der grüne Sockel darin =
   Abschlüsse. Zwei Zahlen in einem Bild, ohne zweite Achse. */
.tstreifen {
  display: flex; align-items: flex-end; gap: 3px;
  height: 130px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: var(--r-tile);
  background: var(--card); box-shadow: var(--shadow-tile);
}
.tsaeule { flex: 1 1 0; height: 100%; display: flex; align-items: flex-end; min-width: 0; }
.ts-bar {
  position: relative; width: 100%; border-radius: 4px 4px 2px 2px;
  background: #cbd5e1; display: flex; align-items: flex-end; overflow: hidden;
}
.ts-gruen { width: 100%; background: #15803d; }
.tfoot {
  display: flex; justify-content: space-between;
  padding: 5px 4px 0; font-size: 11px; color: var(--muted);
}

@media (max-width: 420px) {
  .vbar-l { flex-basis: 92px; font-size: 11.5px; }
  .fkacheln { grid-template-columns: repeat(4, 1fr); }
}

/* ===========================================================================
   Einstellungen
   =========================================================================== */

.set-group { margin: 0 0 18px; }
.set-h {
  margin: 0 0 8px; padding: 0 2px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.set-row {
  appearance: none; width: 100%; text-align: left; cursor: pointer;
  display: flex; align-items: center; gap: 11px;
  padding: 13px 14px; margin-bottom: 8px;
  border: 1px solid var(--line); border-radius: var(--r-tile);
  background: var(--card); box-shadow: var(--shadow-tile);
  transition: background .15s;
}
.set-row:active { background: var(--line-soft); }
.set-row.static { cursor: default; }
.set-ic {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: var(--line-soft); color: var(--ink-2);
}
.set-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.set-text strong { font-size: 13.5px; font-weight: 650; }
.set-text small { font-size: 11.5px; color: var(--muted); line-height: 1.45; }
.set-fuss { margin: 24px 2px 0; font-size: 11.5px; color: var(--muted); text-align: center; }

/* Schiebeschalter – reine Anzeige, geschaltet wird die ganze Zeile. */
.schalter {
  flex: 0 0 auto; position: relative;
  width: 40px; height: 24px; border-radius: 999px; background: #d7dfe9;
  transition: background .18s;
}
.schalter::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 18px; height: 18px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(15, 23, 42, .3);
  transition: transform .18s;
}
.schalter.an { background: var(--accent); }
.schalter.an::after { transform: translateX(16px); }

/* ===========================================================================
   Toast
   =========================================================================== */

#toast {
  position: fixed; left: 50%; bottom: 32px; z-index: 80;
  transform: translate(-50%, 12px);
  /* Ohne max-content bemisst sich die Breite am Platz RECHTS von left:50%, also
     an der halben Bildbreite – „Standort wird gesucht …" brach dadurch mitten im
     Satz um. */
  width: max-content; max-width: min(90vw, 380px);
  padding: 10px 16px; border-radius: 999px;
  background: rgba(15, 23, 42, .92); color: #fff;
  font-size: 14px; font-weight: 600; text-align: center;
  box-shadow: 0 6px 22px rgba(15, 23, 42, .35);
  opacity: 0; pointer-events: none;                 /* schluckt keinen Kartentipp */
  transition: opacity .16s ease, transform .16s ease;
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }
/* Auf der Karte liegt unten der Joystick (104px hoch), und ausgerechnet seine
   Meldungen dürfen ihn nicht zudecken. */
body.view-map #toast { bottom: calc(var(--safe-bottom) + 172px); }
/* Über dem Blatt statt dahinter: die Meldung kommentiert ja gerade das, was im
   Blatt passiert ist – und das Blatt deckt die untere Hälfte ab. */
body.blatt-auf #toast {
  bottom: auto; top: calc(var(--safe-top) + 64px); z-index: 90;
  transform: translate(-50%, -12px);
}
body.blatt-auf #toast.show { transform: translate(-50%, 0); }

/* ===========================================================================
   Anmeldung (views/login.ejs, views/register.ejs)
   =========================================================================== */

.lock {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: #0b1220;
}
.lock-box {
  width: min(340px, 100%);
  display: flex; flex-direction: column; gap: 10px;
  text-align: center;
}
.lock-brand {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-weight: 700; letter-spacing: .14em; font-size: 13px;
  color: #7dd3fc; margin-bottom: 10px;
}
.lock-label {
  font-size: 12px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: #7d8da3; text-align: left;
}
.lock-input {
  appearance: none; width: 100%;
  padding: 13px 15px; border-radius: var(--r-field);
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(255, 255, 255, .06); color: #f8fafc;
  font-size: 17px;                                  /* < 16px zoomt iOS beim Fokus */
  letter-spacing: .1em;
}
/* Der Benutzername ist Text und kein Passwort – gesperrte Zeichen würden ihn
   nur schwerer lesbar machen. */
.lock-input--text { letter-spacing: normal; }
.lock-input:focus { outline: none; border-color: #38bdf8; background: rgba(255, 255, 255, .1); }
.lock-go {
  appearance: none; border: 0; cursor: pointer;
  padding: 13px 15px; border-radius: var(--r-field); min-height: 46px;
  background: var(--accent); color: #fff; font-size: 15px; font-weight: 600;
}
.lock-go:active { transform: scale(.985); }
.lock-err { margin: 2px 0 0; color: #fca5a5; font-size: 13px; font-weight: 600; }
.lock-note { margin: 14px 0 0; color: #64748b; font-size: 12px; line-height: 1.5; }
.lock-alt { margin: 12px 0 0; color: #64748b; font-size: 12.5px; }
.lock-alt a { color: #38bdf8; font-weight: 600; text-decoration: none; }
.lock-alt a:hover { text-decoration: underline; }

.lock.shake .lock-box { animation: lock-shake .3s ease; }
@keyframes lock-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-7px); }
  55% { transform: translateX(6px); }
  80% { transform: translateX(-3px); }
}
@media (prefers-reduced-motion: reduce) { .lock.shake .lock-box { animation: none; } }

/* ===========================================================================
   Querformat-Sperre
   ===========================================================================
   Das Manifest (orientation: portrait) hält die installierte App auf Android
   schon von sich aus aufrecht – iOS ignoriert das Feld aber vollständig, in der
   Lasche wie auf dem Home-Bildschirm. Und in einer normalen Browser-Lasche
   greift es nirgends. Deshalb hier zusätzlich eine reine CSS-Sperre. Sie gilt
   nur für Geräte mit grobem Zeiger und flachem Fenster – ein Laptop im
   Querformat ist gemeint, ein Telefon in der Hand nicht. */
.hochkant { display: none; }

@media (orientation: landscape) and (max-height: 560px) and (pointer: coarse) {
  .hochkant {
    display: flex; position: fixed; inset: 0; z-index: 200;
    align-items: center; justify-content: center; padding: 24px;
    background: #0b1220; color: #cbd5e1;
  }
  .hochkant-box {
    display: flex; flex-direction: column; align-items: center; gap: 10px;
    text-align: center; max-width: 320px;
  }
  .hochkant-box strong { font-size: 15px; color: #f8fafc; }
  .hochkant-box span { font-size: 13px; line-height: 1.5; }
  .hochkant-box svg { color: #38bdf8; }
}
