#msgDialog {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 10;
    background-color: #00000016;
}
body#page_connectivityCenter:not(.isMobile) #msgDialog {
    background-color: unset;
    top: 7rem;
    margin-top: -7rem;
    pointer-events: none;
}

/* Nur auf index.php ist das Hauptmenü-Grid (#menuBackground, z-index:1000)
   dauerhaft offen — showMenu() läuft beim Laden und die Schließen-Handler
   werden in bodyHeader.tpl entfernt. Das Menü verdeckt damit die Kopfzeile
   inkl. Chat-Icon. Das Icon wird dort bewusst NICHT über das Overlay gehoben:
   auf der Menüseite soll nichts über dem Menü schweben. Ohne die Regel bliebe
   es als abgedunkelter Fleck hinter dem Blur sichtbar, deshalb display:none.

   Wichtig: nur der CONTAINER wird ausgeblendet, das <img id="mailboxIcon">
   bleibt im DOM. mailbox.js hängt seinen kompletten document.ready-Block
   (initMailbox, Nachrichten-Polling, initWebPushNotifications) an
   doesElementExist("#mailboxIcon") — eine reine .length-Prüfung. Würde das
   Element auf index.php gar nicht gerendert, liefe auf der Landeseite nach dem
   Login keine Push-Registrierung. Der Chat ist von jeder anderen Seite aus
   erreichbar (dort ist das Menü geschlossen und die Kopfzeile sichtbar).

   Auf allen anderen Seiten (inkl. connectivityCenter, eingebettet) NICHT
   anfassen — deshalb strikt auf body#page_index gescoped. */
body#page_index #mailboxIconContainer {
    display: none;
}

/* ST11a (#15, 2026-06-29): Höhen wachsen mit der Viewport, statt fixe
   45rem/40rem stehen zu bleiben. Auf großen Bildschirmen wird der Chat
   spürbar höher, ohne dass kleine Bildschirme leiden (max-height schützt). */
#chatList {
    width: 24rem;
    height: calc(100vh - 12rem);
    max-height: 75rem;
    overflow-y: auto;
    overflow-x: hidden;
    flex: 0 0 auto;
}

/* Überschriften "Angepinnt" / "Übrige Chats". Sie stehen als Geschwister zwischen
   den Listeneinträgen, damit die bestehenden Selektoren auf .chatListItem weiter
   greifen; renderChatListSections() setzt sie nur, wenn wirklich etwas angepinnt
   ist. Der Strich rechts füllt die Restbreite und trennt die Blöcke optisch,
   ohne eine eigene Trennlinie zwischen den Einträgen einzuführen (die hat ST11a
   bewusst entfernt). */
/* Textfarbe bewusst anthracite und NICHT darkgrey: 0.75rem sind bei html-
   font-size 14px nur 10,5px, da greift die Ausnahme fuer grossen Text nicht
   (die beginnt bei 18,7px fett). darkgrey kaeme auf 1,86:1 und verfehlte die
   4,5:1 aus WCAG 1.4.3 deutlich. Die Hierarchie gegenueber dem Chatnamen
   traegt der Groessensprung samt Versalien. Nicht per opacity abmildern --
   das blasst auch den ::after-Strich mit aus und landet wieder unter 4,5:1. */
#chatList .chatListSectionLabel {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.5rem 0.25rem;
    font-size: 0.75rem;
    font-weight: bold;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--atlantis-anthracite);
}
#chatList .chatListSectionLabel::after {
    content: "";
    flex: 1;
    height: 1px;
    background-color: var(--atlantis-lightgrey);
}

/* Push-Opt-in-Leiste über der Chatliste. Bedienelemente baugleich zum PWA-Hinweis
   im Menü (#pwaInstallHint, fullMenu.css): gleiche Touch-Targets, gleiches Dismiss-×.
   Textfarbe bewusst anthracite statt blue-text — blue-text auf blue-trans käme nur
   auf ~3,6:1 und verfehlte die 4,5:1 für Fließtext (WCAG 1.4.3). */
#pushOptInBar {
    display: none;   /* renderPushOptInBar() schaltet auf flex */
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
    box-sizing: border-box;
    margin-bottom: 0.5rem;
    padding: 0 0.25rem 0 0.75rem;
    border-radius: 1rem;
    background-color: var(--atlantis-blue-trans);
    color: var(--atlantis-anthracite);
    font-size: 1rem;
}

#pushOptInAction {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 3.15rem;   /* Touch-Target 44,1px — Root-Font ist 14px (design_2026.css:53) */
}
#pushOptInAction:hover,
#pushOptInAction:focus-visible {
    text-decoration: underline;
}

#pushOptInAction img {
    width: 1.5rem;
    height: 1.5rem;
    flex-shrink: 0;
}

#pushOptInDismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: 3.15rem;    /* Touch-Target 44,1px, Aktion ist permanent (localStorage) */
    min-height: 3.15rem;
    color: #8a8d90;        /* >=3:1 auf dem hellen Grund (WCAG 1.4.11) */
    font-size: 1.25rem;
    line-height: 1;
}
#pushOptInDismiss:hover {
    color: var(--atlantis-anthracite);
}

/* Tap-Rückmeldung: auf Touch gibt es keinen :hover, ohne :active bliebe der Tap
   bis zum Öffnen des Dialogs bzw. des nativen Prompts völlig unquittiert. */
#pushOptInAction:active,
#pushOptInDismiss:active {
    opacity: 0.6;
}
#pushOptInAction:focus-visible,
#pushOptInDismiss:focus-visible {
    outline: 0.25rem solid #1f6feb;   /* wie .menuItemTile:focus-visible */
    outline-offset: 0.25rem;
}

/* ST11a (#1a, 2026-06-29): Suche + "Neuer Chat" brauchten gap. */
#chatListToolbar {
    gap: 0.5rem;
    margin-bottom: 0.5rem;
    padding-right: 0.5rem;
}

#chatListSearch {
    background-color: unset;
    height: 100%;
    padding: 0 0.5rem;
    border-radius: 1rem;
}

/* ST11a (AK6): Hierarchie Name vs. Lastmsg. */
#chatList .chatGroupNameList {
    font-weight: bold;
    font-size: 1rem;
    color: var(--atlantis-anthracite);
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

#chatList .chatListItem {
    box-sizing: border-box;
    width: 100%;
    min-height: 3rem;
    padding: 0.5rem;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
    border-radius: 0.75rem;
}
/* ST11a (2026-06-30): Name+LastMsg-Spalte (2. child) bekommt flex:1,
   damit alle Namen linksbündig an derselben Stelle starten. Der ursprüngliche
   :first-child-Selector hatte gar nicht gematcht — Avatar ist erstes Kind. */
#chatList .chatListItem > .flexBetweenColumn:nth-child(2) {
    flex: 1;
    min-width: 0;
}
/* ST11a (AK7): Trennlinien zwischen Listen-Items entfernt — Hover + Selected
   liefern die Trennung jetzt rein über Hintergrund-Farben. */
body:not(.isMobile) #chatList .chatListItem:hover {
    background-color: var(--atlantis-blue-trans);
}
#chatList .chatListItem.selected {
    background-color: var(--atlantis-blue-trans);
    border-left: 0.1875rem solid var(--atlantis-blue-text);
}

/* ST11a (AK6): Sekundäre Lastmsg-Zeile (regular, gedämpft). */
#chatList .lastMsg {
    font-size: 0.875rem;
    color: var(--atlantis-anthracite);
    opacity: 0.65;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

#chatList .lastMsgDateTime {
    min-width: 4rem;
    flex: 0 0 auto;
    white-space: nowrap;
    text-align: right;
}

/* ST11a (2026-06-29): Bottom-Row für Unread-Counter + Mute/Block-Indikatoren.
   Verhindert vertikales Übereinander-Stapeln im flexBetweenColumn und lässt
   die Datum-Zeile oben sauber abgesetzt. Items sind rechtsbündig in einer Zeile. */
#chatList .chatListItemBottomRow {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: 0.375rem;
}
#chatList .chatListItem.hasNewMsg .lastMsgDateTime {
    font-weight: bold;
}

/* ST5: Per-item muted-indicator (bell_off icon on chat list rows).
   ST11a fix (2026-06-29): aus absolute Position raus — überdeckte sonst die
   Uhrzeit. Jetzt als normales flex-item rechts unten gestapelt unter dem
   unreadCounter. */
#chatList .chatMutedIndicator {
    display: none;
    height: 0.875rem;
    width: 0.875rem;
    opacity: 0.6;
}
#chatList .chatListItem.muted .chatMutedIndicator {
    display: unset;
}

/* ST5: Chat-header bell-toggle. */
#chatMuteToggle {
    width: 1.25rem;
    height: 1.25rem;
    margin-left: auto;
    margin-right: 0.5rem;
    cursor: pointer;
}
#chatMuteToggle.disabled {
    opacity: 0.4;
    pointer-events: none;
}

/* Angepinnt-Anzeige je Zeile, gleiche Logik und Groesse wie die beiden
   Nachbarn darunter. Sie ergaenzt die Sektionsueberschrift, weil die Liste
   scrollt und die Ueberschriften waehrend einer Suche ausgeblendet sind. */
#chatList .chatPinnedIndicator {
    display: none;
    height: 0.875rem;
    width: 0.875rem;
    opacity: 0.6;
}
#chatList .chatListItem.pinned .chatPinnedIndicator {
    display: unset;
}

/* ST6: Per-item blocked-by-me indicator (block icon on chat list rows).
   ST11a fix (2026-06-29): aus absolute Position raus, gleiche Logik wie
   chatMutedIndicator. Beide stapeln sich rechts unten als flex-items. */
#chatList .chatBlockedByMeIndicator {
    display: none;
    height: 0.875rem;
    width: 0.875rem;
    opacity: 0.6;
}
#chatList .chatListItem.blockedByMe .chatBlockedByMeIndicator {
    display: unset;
}

/* ST-Avatar: pupil photo inside the list avatar circle. Scoped to #chatList so
   the shared global .avatarCircle (header + participant avatars) stays intact.
   The photo overlays the initials (which remain as onerror fallback). */
#chatList .avatarCircle {
    position: relative;
    overflow: hidden;
}
/* Task 2026-09-17: dieselbe Overlay-Regel traegt auch den Panel-Avatar des Gruppenbilds. */
#chatList .avatarPhoto,
.chatGroupPanelAvatar .avatarPhoto {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
}

/* ST6: Chat-header block-toggle. Sits right of #chatMuteToggle when both
   visible (1-on-1 with pupil/parent opposite). */
#chatBlockToggle {
    width: 1.25rem;
    height: 1.25rem;
    margin-right: 0.5rem;
    cursor: pointer;
}
#chatBlockToggle.disabled {
    opacity: 0.4;
    pointer-events: none;
}

#chatMsgContainer {
    width: 44rem;
    border-left: var(--atlantis-std-border);
    padding: 0 0.5rem;
}

/* Close-X icon top-right of a dialog header (used in main + sub-dialogs). */
.dialogCloseIcon {
    height: 2rem;
    position: absolute;
    right: 0;
}

/* Group-info header section. */
.chatGroupNameClickable {
    width: -webkit-fill-available;
    width: -moz-available;
}

.chatGroupSubHeading {
    font-size: 1.2em;
}

/* Teilnehmer-Name einzeilig mit Ellipsis. Bewusst NICHT global auf
   .noBreakEllipsis, weil die Klasse (undefiniert) auch in Klassenbuch/
   abwesenheit.js genutzt wird — Scope hier auf die Chat-Teilnehmer. */
.chatParticipantMain .noBreakEllipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.participantContainerScroll {
    height: 40rem;
    overflow-y: auto;
    overflow-x: hidden;
}

/* ST12: File-Preview-Strip — Chips der zum Versand vorgemerkten Anhänge. */
.filePreviewHeader {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.5rem;
}
.previewLabel {
    font-size: 0.8125rem;
    color: var(--atlantis-anthracite);
    opacity: 0.7;
}
.filePreviewCloseIcon {
    height: 1rem;
    width: 1rem;
}

/* Unread notification badge on the mailbox icon (bottom-right). */
#mailboxIconContainer {
    position: relative;
    align-self: center;
    line-height: 0;
}
.notificationBadge {
    position: absolute;
    /* In der Icon-Ecke statt darunter: als Überhang war das Badge das am
       weitesten unter die Kopfzeilenkante ragende Element. */
    bottom: 0;
    right: -0.25rem;
    min-width: 1rem;
    height: 1rem;
    padding: 0 0.25rem;
    background-color: var(--atlantis-red);
    color: white;
    border-radius: 0.5rem;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1rem;
    text-align: center;
    box-sizing: border-box;
}

/* Empty-state shown when the chat list has no groups. */
.chatListEmptyState {
    width: 24rem;
    padding: 2rem;
    text-align: center;
    color: var(--atlantis-anthracite);
    font-style: italic;
}

/* CSS-only spinner replacing the 2010-era loading.gif. */
.atlSpinner {
    display: inline-block;
    width: 3rem;
    height: 3rem;
    border: 0.25rem solid var(--atlantis-lightgrey);
    border-top-color: var(--atlantis-blue-text);
    border-radius: 50%;
    animation: atlSpin 0.8s linear infinite;
    box-sizing: border-box;
}
@keyframes atlSpin {
    to { transform: rotate(360deg); }
}

/* Loading spinner overlay (centered in chat container). */
.loadingSpinnerCentered {
    height: 4rem;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1;
}
.loadingSpinnerInline {
    height: 4rem;
}

/* New-chat filter dialog: search input + selection table. */
/* Task-1: Fenster auf den border-radius clippen — sonst stehen Titelleiste /
   Inhalt über die Rundung und die Ecken wirken eckig. */
#newChatFilterDialog .dialogWindow {
    overflow: hidden;
}
.newChatSelectionSearchInput {
    line-height: 1.5em;
    margin-bottom: 0.75rem;
    width: 100%;
    box-sizing: border-box;
    border: var(--atlantis-std-border);
    border-radius: 1rem;
    padding: 0.5rem 0.75rem;
    font-family: inherit;
    font-size: 1rem;
}
.newChatSelectionContainerScroll {
    max-height: 70vh;
    overflow-y: auto;
}
.newChatSelectionTable {
    border-collapse: separate;
    border-spacing: 0 2px;
    min-width: 16rem;
    width: 100%;
}

/* Override Picmo emoji-picker positioning: the library adds an inline
   transform: translate(...) that shifts the picker off-screen relative
   to the viewport. Force a fixed position above the typing area and
   disable the library's transform. */
.emoji-picker {
    position: fixed !important;
    transform: none !important;
    z-index: 100;
}
/* F5: Die frühere index-spezifische Anhebung des Emoji-Pickers (z:1002 über dem
   angehobenen Chat-Stack) ist entfallen — der Dialog liegt jetzt auf seinem
   natürlichen z (#msgDialog:10), der an <body> gehängte Picker (z:100) darüber. */
/* content läuft ~18px über seine Box (picmo-Layout) und spillt mit
   overflow:visible in den Preview-Footer → dessen border-top schneidet die
   letzte Emoji-Zeile. clippen (NICHT scrollen, sonst 2. Scrollbar neben der
   inneren .emoji-picker__emojis-Scrollbar). */
.emoji-picker__content {
    overflow: hidden;
}
/* Lupe im Such-Feld vertikal zentrieren — der block-Span erbt eine große
   line-height, die das inline-SVG nach unten drückt. */
.emoji-picker__search-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

/* Avatar-Initialen-Kreis (Fallback, wenn kein User-Foto vorhanden).
   ST11a (AK1): default-color bleibt --atlantis-blue-text; deterministisch
   überschrieben durch eine .hue1..8-Klasse aus dem getAvatarHueForId-Hash. */
.avatarCircle {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background-color: var(--atlantis-blue-text);
    color: white;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 2.5rem;
    text-align: center;
    text-transform: uppercase;
    flex: 0 0 auto;
}
.avatarCircle.hue1 { background-color: var(--avatarHue1); }
.avatarCircle.hue2 { background-color: var(--avatarHue2); }
.avatarCircle.hue3 { background-color: var(--avatarHue3); }
.avatarCircle.hue4 { background-color: var(--avatarHue4); }
.avatarCircle.hue5 { background-color: var(--avatarHue5); }
.avatarCircle.hue6 { background-color: var(--avatarHue6); }
.avatarCircle.hue7 { background-color: var(--avatarHue7); }
.avatarCircle.hue8 { background-color: var(--avatarHue8); }

.chatBubble {
    max-width: 75%;
    align-self: flex-start;
    margin: 0.25rem 0;
}
.chatBubble .msgContainer {
    padding: 0.75rem 1rem;
    background-color: var(--atlantis-lightgrey);
    color: var(--atlantis-anthracite);
    /* ST11a (AK10): Other-Bubble Tail unten-links. */
    border-radius: 1rem 1rem 1rem 0.25rem;
    white-space: pre-wrap;
}
/* Lange Woerter ohne Trennstelle (Links, Dateinamen) brechen innerhalb der Blase um. Ohne das
   liefen sie seitlich aus der Blase -- genau in den Raum der Uhrzeit -- und erzeugten einen
   waagerechten Scrollbalken im Verlauf. */
#msgDialog .chatBubble .msg,
#msgDialog .chatBubble .orgAttachmentName,
#msgDialog .chatBubble .attachmentUnavailable {
    overflow-wrap: anywhere;
}
.chatBubble .attachment {
    text-align: center;
}
.chatBubble .attachment .imgAttachment {
    object-fit: contain;
    max-width: 100%;
}
.chatBubble.self {
    align-self: flex-end;
}
/* ST11a (AK9): Self-Bubble in sattem Atlantis-Blau mit weisser Schrift.
   AK10: Tail unten-rechts. Token `--atlantis-blue-text` als Spec-Default
   (WCAG-AA gegen weiss, ~4.6:1) — UI-Experten-Review T2-6. */
.chatBubble.self .msgContainer {
    background-color: var(--atlantis-blue-text);
    color: white;
    border-radius: 1rem 1rem 0.25rem 1rem;
}

/* Uhrzeit + Lese-Haken stehen NEBEN der Sprechblase auf Hoehe ihrer Unterkante: rechts von
   fremden, links von eigenen Bubbles -- im freien Raum, den max-width 75 % laesst. So kostet die
   Angabe keine eigene Zeile; das Datum traegt allein der Tages-Trenner. Im DOM bleibt .msgMeta
   Kind von .msgContainer (siehe Template): der Container ist der Anker fuer die Unterkante, die
   Reaktionsleiste darunter zaehlt nicht mit. nowrap, weil die absolut gesetzte Box sonst auf ihre
   schmalste Breite umbricht. Die Deckkraft liegt auf den Kindern, nicht auf .msgMeta, damit der
   Haken "von allen gelesen" kraeftiger sein darf als die Uhrzeit. Anthrazit mit 0.7 auf dem
   weissen Chatgrund = 4,7:1.
   Feste Hoehe 1rem (= Haken): ohne sie waere die Box eigener Blasen 14 px, die fremder 10,5 px
   hoch und die Uhrzeit stuende auf zwei verschiedenen Grundlinien. bottom 0 laesst dem
   Menue-Chip darueber (top 0, 25 px) bei der einzeiligen Blase (46 px) rund 7 px Abstand. */
#msgDialog .chatBubble .msgContainer {
    position: relative;
}
#msgDialog .chatBubble .msgContainer .msgMeta {
    position: absolute;
    bottom: 0;
    left: 100%;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    height: 1rem;
    margin-left: 0.5rem;
    font-size: 0.75rem;
    line-height: 1;
    white-space: nowrap;
    color: var(--atlantis-anthracite);
}
#msgDialog .chatBubble.self .msgContainer .msgMeta {
    left: auto;
    right: 100%;
    margin-left: 0;
    margin-right: 0.5rem;
}
#msgDialog .chatBubble .msgContainer .msgMeta .msgDateTime {
    opacity: 0.7;
}

/* ST11a (AK12): Sender-Header über Other-Bubbles in Gruppen-Chats. */
.bubbleSenderHeader {
    font-size: 0.75rem;
    font-weight: 600;
    margin-bottom: 0.25rem;
    color: var(--avatarHue1);
}
.bubbleSenderHeader.hue1 { color: var(--avatarHue1); }
.bubbleSenderHeader.hue2 { color: var(--avatarHue2); }
.bubbleSenderHeader.hue3 { color: var(--avatarHue3); }
.bubbleSenderHeader.hue4 { color: var(--avatarHue4); }
.bubbleSenderHeader.hue5 { color: var(--avatarHue5); }
.bubbleSenderHeader.hue6 { color: var(--avatarHue6); }
.bubbleSenderHeader.hue7 { color: var(--avatarHue7); }
.bubbleSenderHeader.hue8 { color: var(--avatarHue8); }

/* ST11a (AK13): Read-Status-Häkchen eigener Nachrichten, neben der Sprechblase hinter der
   Uhrzeit. Icon via mask + background-color:currentColor — die SVGs sind farbig bzw.
   currentColor und kämen als background-image nicht in der Textfarbe.
   sent = einfacher Haken, seen/all = Doppelhaken. sent/seen in der Farbe der Uhrzeit
   (Anthrazit 0.7 = 4,7:1 auf Weiß); all = Atlantis-Blau bei voller Deckkraft (3,9:1, für
   Grafik reichen 3:1). Die frühere Unterscheidung allein über 0.6 gegen 1.0 Deckkraft trug
   nur auf der blauen Bubble — auf Weiß läge der blasse Haken bei rund 2,3:1.
   check_single.svg ist der einfache Haken im Strich von check_double.svg; das allgemeine
   check.svg (gefüllt, fetter) ließ „gesendet" kräftiger wirken als „gelesen". */
.readStatus {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    vertical-align: middle;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-size: contain;
            mask-size: contain;
}
.readStatus[data-read-state=""]      { display: none; }
.readStatus[data-read-state="sent"]  {
    -webkit-mask-image: url("../images/2025/check_single.svg");
            mask-image: url("../images/2025/check_single.svg");
    opacity: 0.7;
}
.readStatus[data-read-state="seen"]  {
    -webkit-mask-image: url("../images/2025/check_double.svg");
            mask-image: url("../images/2025/check_double.svg");
    opacity: 0.7;
}
.readStatus[data-read-state="all"]   {
    -webkit-mask-image: url("../images/2025/check_double.svg");
            mask-image: url("../images/2025/check_double.svg");
    color: var(--atlantis-blue-text);
    opacity: 1;
}
/* Noch nicht bestaetigte Nachricht (tmp-cm_id): neben "Sende" steht kein Haken -- er hiesse
   "gesendet". Der Reconcile benennt die cm_id um, dann erscheint er von selbst. */
#msgDialog .chatBubble[cm_id^="tmp"] .msgContainer .msgMeta .readStatus {
    display: none;
}

/* ST11a (AK11): Tages-Trenner. */
.dayDivider {
    display: flex;
    justify-content: center;
    margin: 0.5rem 0;
}
.dayDividerPill {
    padding: 0.25rem 0.75rem;
    background-color: var(--atlantis-lightgrey);
    color: var(--atlantis-anthracite);
    border-radius: 1rem;
    font-size: 0.75rem;
}

/* Mitlaufende Datumsanzeige (Chat-Feinschliff 30.09.2026): die Trenner-Pille oben ueber dem
   Verlauf, sichtbar, solange ein Tages-Trenner ueber ihr liegt (updateStickyDay, mailbox.js,
   setzt auch left auf die Mitte des Inhaltsbereichs). Kein Mausziel, damit Blasen darunter
   bedienbar bleiben. z-index ueber dem ruhenden Menue-Chip der Blasen (1), unter dem aktiven
   Chip (3) und dem Drop-Overlay (5). Der weisse Ring trennt sie von grauen Blasen und
   Systemzeilen (gleicher Fond); auf dem weissen Chatgrund ist er unsichtbar. */
#chatMessagePane {
    position: relative;
}
#chatStickyDay {
    position: absolute;
    top: 0.5rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    white-space: nowrap;
    pointer-events: none;
    box-shadow: 0 0 0 2px white, 0 1px 0.25rem 2px rgba(0, 0, 0, 0.12);
    visibility: hidden;
}
#chatStickyDay.visible {
    visibility: visible;
}
/* Der Trenner, ueber dem die Anzeige liegt, scrollt unter ihr weiter und schaute sonst im
   Spalt ueber ihrem Ring hervor. opacity statt visibility: Screenreader lesen den echten
   Trenner weiter, die Anzeige selbst ist aria-hidden. */
#chatContent .dayDividerPill.coveredBySticky {
    opacity: 0;
}

/* Task 2026-09-17: Systemzeile im Verlauf -- zentrierte graue Pille wie der Tages-Trenner,
   ohne Avatar, Sprechblase, Zeitstempel und Menue-Chip. */
.chatBubble.chatSystemRow {
    align-self: center;
    max-width: 90%;
    margin: 0.5rem 0;
}

.chatSystemRowText {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    background-color: var(--atlantis-lightgrey);
    color: var(--atlantis-anthracite);
    border-radius: 1rem;
    font-size: 0.75rem;
    text-align: center;
}

/* Dieselbe Zeile als Listenvorschau (kursiv, gesetzt von buildLastMsgText). */
#chatList .sysLastmsg {
    color: var(--atlantis-anthracite);
}

/* ST11a (AK3): Numerischer Unread-Counter rechts. Pill mit voll-runden Enden:
   bei 1 Ziffer (min-width = height) ergibt border-radius: 999px einen runden
   Kreis; bei mehrstelligen Zahlen wird die Pille horizontal länger, behält
   aber halbkreis-förmige Enden. Kein box-sizing-Trick nötig — content-box
   lässt das Padding korrekt wirken. */
.unreadCounter {
    display: none;
    min-width: 1.25rem;
    width: fit-content;
    height: 1.25rem;
    padding: 0 0.375rem;
    background-color: var(--atlantis-blue-text);
    color: white;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.25rem;
    text-align: center;
    box-sizing: border-box;
}
#chatList .chatListItem.hasNewMsg .unreadCounter,
.unreadCounter.show {
    display: inline-block;
}

/* ST11a (AK4): Empty-Lastmsg italic-gedämpft. */
.lastMsg .emptyLastmsg {
    font-style: italic;
    opacity: 0.65;
}

/* ST11a (AK14): MIME-Icon-Hook für File-Attachments. */
.fileAttachmentIcon img {
    width: 2rem;
    height: 2rem;
}

/* ST11a (#18, 2026-06-29): Chat-Header höher mit Avatar 3rem (vorher 2.5rem)
   und 2-Zeilen-Text-Stack (Name + Sub-Zeile mit Rolle/Klasse bzw. Teilnehmer-
   Zahl). Vertikales padding + min-height geben dem Header sichtbar mehr
   Präsenz; align-items center hält Avatar/Stack/Actions auf einer Linie. */
#chatHeader {
    border-bottom: var(--atlantis-std-border);
    padding: 0.5rem 0.5rem;
    min-height: 4rem;
    align-items: center;
    box-sizing: border-box;
    gap: 0.5rem;
}

#backToChatistButton {
    height: 2rem;
    width: 2rem;
    padding-right: 1rem;
    margin-right: 1rem;
    border-right: var(--atlantis-std-border);
    display: none;
}

/* ST11a (#18, 2026-06-29): Avatar im Header. 3rem-Kreis, image-Variante
   ebenso quadratisch + abgerundet, beide vertikal zentriert. */
#chatHeaderAvatarWrapper {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
}
#chatHeader #chatHeaderAvatar.avatarCircle {
    width: 3rem;
    height: 3rem;
    line-height: 3rem;
    font-size: 1rem;
}
#customPupilChatImage {
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    object-fit: cover;
}

/* Task 2026-09-17: Gruppenbild im Header -- gleiche Groesse wie Initialen-Kreis und
   Schuelerfoto, damit der Header beim Wechsel nicht springt. */
#chatGroupImageHeader {
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    object-fit: cover;
}

/* ST11a (#18/#20, 2026-06-29): Name oben, Sub-Zeile (Rolle/Klasse bzw.
   "N Teilnehmer") darunter. Kein Margin am Stack — Padding/Gap regeln
   den Abstand zum Avatar links und den Actions rechts. */
#chatHeaderTextStack {
    flex: 1;
    min-width: 0;
    margin-left: 0.75rem;
    gap: 0;
}

/* Der Textstapel ist so hoch wie der Avatar daneben. Mit flex-start klebt sein
   Inhalt oben — bei zwei Zeilen (Name + Subline) faellt das nicht auf, weil sie
   die Hoehe fuellen, bei leerer Subline (#chatHeaderSubline:empty ist display:
   none) sass der Name dagegen 12px ueber der Avatar-Mitte. Zentriert sitzt er
   in beiden Faellen richtig. */
#chatHeaderTextStack {
    justify-content: center;
}

#chatGroupNameHeader {
    font-weight: bold;
    font-size: 1.0625rem;
    line-height: 1.25rem;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}

#chatHeaderSubline {
    font-size: 0.8125rem;
    line-height: 1.125rem;
    color: var(--atlantis-anthracite);
    opacity: 0.65;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}
#chatHeaderSubline:empty {
    display: none;
}

/* ST11a (#19, 2026-06-29): 3-Punkt-Menü-Popup im Header. */
#chatHeaderMenuToggle {
    width: 1.5rem;
    height: 1.5rem;
    margin-right: 0.5rem;
    cursor: pointer;
}
.chatHeaderMenuPopup {
    position: absolute;
    top: 2rem;
    right: 0.5rem;
    background-color: white;
    border: var(--atlantis-std-border);
    border-radius: 0.5rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
    z-index: 20;
    min-width: 12rem;
    padding: 0.25rem 0;
}
.chatHeaderMenuItem {
    padding: 0.5rem 1rem;
    cursor: pointer;
    white-space: nowrap;
    font-size: 0.9375rem;
}
.chatHeaderMenuItem:hover {
    background-color: var(--atlantis-blue-trans);
}

#chatGroupInfo {
    width: 16rem;
    border-right: var(--atlantis-std-border);
    margin: 0.5rem 0.5rem 4.5rem 0;
    padding-right: 0.5rem;
}

.chatGroupParticipantsContainer {
    margin-top: 0.5rem;
}

.chatGroupParticipants {
    margin-left: 0.5rem;
}

.chatGroupParticipants>div {
    margin-top: 0.5rem;
}

/* ST11a redesign: Teilnehmer-Zeile — Avatar-Kreis + Name links, Aktions-Icons
   rechts. Flex statt float; Name mit min-width:0 → Ellipsis statt H-Überlauf. */
.chatParticipantRow {
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0;
}
.chatParticipantMain {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
    flex: 1 1 auto;
    /* an oversized label must never run under the action icons */
    overflow: hidden;
}
/* Role label of a reference row ("· Eltern" after "09C"): never wrapping, takes no space
   away from the name (ellipsis). Hierarchy to the name comes from the smaller size, NOT
   from a lighter colour: --atlantis-darkgrey would be 1.86:1 on white (see the section
   labels above) — anthracite gives 11.7:1. */
.chatParticipantRole {
    color: var(--atlantis-anthracite);
    font-size: 0.75rem;
    flex: 0 0 auto;
    white-space: nowrap;
}
.participantAvatar {
    width: 1.75rem;
    height: 1.75rem;
    line-height: 1.75rem;
    font-size: 0.7rem;
}
.chatParticipantActions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    flex: 0 0 auto;
}
/* Alle Aktions-Icons gleich groß + ohne Alt-Margins → die Spalten (Krone /
   Stift / Entfernen) richten sich sauber aus; der Self-Platzhalter matcht die
   Breite des Entfernen-X (überschreibt die Legacy-.placeholderIcon-Regel). */
.chatParticipantActions > img,
.chatParticipantActions > .placeholderIcon {
    width: 1.25rem;
    height: 1.25rem;
    margin: 0;
    flex: 0 0 auto;
}
/* Krone: Admin voll sichtbar, Nicht-Admin gedimmt (Klick = zum Admin machen). */
.chatGroupNoAdminIcon {
    opacity: 0.3;
}
#chatMsgContainer[isAdmin='true'] .chatGroupAdminIcon,
#chatMsgContainer[isAdmin='true'] .chatGroupNoAdminIcon {
    cursor: pointer;
}

/* F19: totes float:right entfernt — die Icons sind flex-Kinder von
   .chatParticipantActions (siehe .chatParticipantActions > img), float wirkt
   dort nicht. */
#chatMsgContainer[isAdmin='true'] .chatGroupCommentingAllowedIcon,
#chatMsgContainer[isAdmin='true'] .chatGroupCommentingDisallowedIcon {
    cursor: pointer;
}
/* Gesperrt zusätzlich zum durchgestrichenen Stift gedimmt — gleiche Sprache wie
   bei der Krone (gedimmt = Recht nicht erteilt) und wie im Neuen-Chat-Dialog. */
.chatGroupCommentingDisallowedIcon {
    opacity: 0.7;
}

/* Task 2026-09-17: Gruppenbild-Block im Gruppeninfo-Panel. Der Block selbst ist fuer alle
   Teilnehmer sichtbar (er zeigt das Bild); Stift-Badge und "Bild entfernen" haengen am
   Admin-Attribut des Containers -- ein Nicht-Admin sieht keine Aktion. "Bild entfernen"
   zusaetzlich nur, wenn ueberhaupt ein Bild gesetzt ist (.hasImage). */
#chatGroupImageBlock {
    align-items: center;
    flex: 0 0 auto;
    margin-bottom: 0.5rem;
}

.chatGroupPanelAvatar {
    width: 6rem;
    height: 6rem;
    line-height: 6rem;
    font-size: 2rem;
    position: relative;
    overflow: hidden;
}

#chatGroupImageClickTarget {
    position: relative;
}

/* UI-Fix 29.09.2026 (Befund 3): Der Gross-Link umschliesst nur den Panel-Avatar. Als <a>
   wuerde er die Initialen unterstreichen und in der Verweisfarbe einfaerben -- beides
   ausdruecklich zurueckgesetzt; display: block verhindert zusaetzlich die Zeilenbox-Hoehe
   der Inline-Darstellung unter dem absolut gesetzten Stift-Symbol. */
#chatGroupImageLargeLink {
    display: block;
    text-decoration: none;
    color: inherit;
}

/* Zeigefinger, wo der Klick etwas tut: mit gesetztem Bild fuer JEDEN Teilnehmer (Grossansicht).
   Den Fall "kein Bild, aber Gruppenadmin" deckt die Klick-Ziel-Regel weiter unten ab. */
#chatGroupImageLargeLink[href] {
    cursor: pointer;
}

#chatGroupImageEditBadge {
    display: none;
    position: absolute;
    right: 0;
    bottom: 0;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0.25rem;
    background-color: white;
    border: var(--atlantis-std-border);
    border-radius: 50%;
}

#chatGroupImageRemove {
    display: none;
    margin-top: 0.25rem;
    color: var(--atlantis-blue-text);
    font-size: 0.75rem;
}

#chatMsgContainer[isAdmin='true'] #chatGroupImageClickTarget {
    cursor: pointer;
}

#chatMsgContainer[isAdmin='true'] #chatGroupImageEditBadge {
    display: block;
}

#chatMsgContainer[isAdmin='true'] #chatGroupImageBlock.hasImage #chatGroupImageRemove {
    display: inline;
}

.removeParticipantIcon {
    margin-left: 0.5rem;
    cursor: pointer;
    display: none;
}
#chatMsgContainer[isAdmin='true'] .removeParticipantIcon,
#chatMsgContainer[isAdmin='true'] .placeholderIcon,
#chatMsgContainer[isAdmin='true'] #addParticipantButton {
    display: unset;
}

#addParticipantButton {
    display: none;
}

.placeholderIcon {
    height: 1rem;
    width: 1rem;
    margin-left: 0.5rem;
    display: none;
}

#filePreview {
    border-top: var(--atlantis-std-border);
    padding: 0.5rem;
}

#filePreviewStrip {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.25rem;
}
.filePreviewItem {
    position: relative;
    flex: 0 0 auto;
    width: 5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
}
.filePreviewItemThumb,
.filePreviewItemIcon {
    width: 4rem;
    height: 4rem;
    object-fit: contain;
    border: var(--atlantis-std-border);
    border-radius: 0.5rem;
    background-color: white;
}
.filePreviewItemName {
    width: 100%;
    font-size: 0.75rem;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.filePreviewItemRemove {
    position: absolute;
    top: -0.375rem;
    right: 0.25rem;
    height: 1rem;
    width: 1rem;
    padding: 0.125rem;
    background-color: white;
    border: var(--atlantis-std-border);
    border-radius: 50%;
}
.filePreviewItemRemove:hover,
.filePreviewCloseIcon:hover {
    background-color: var(--atlantis-blue-trans);
    border-color: var(--atlantis-blue-text);
}
/* Größere Touch-Fläche für die destruktiven Entfernen-Icons auf Mobile. */
body.isMobile .filePreviewItemRemove {
    padding: 0.5rem;
    box-sizing: content-box;
    top: -0.5rem;
}
body.isMobile .filePreviewCloseIcon {
    padding: 0.5rem;
    box-sizing: content-box;
}

/* ST13: Drag&Drop-Overlay über dem Chat-Panel. */
#chatContentContainer {
    position: relative;
}
#chatDropOverlay {
    display: none;
    position: absolute;
    inset: 0;
    z-index: 5;
    /* Overlay darf keine Drag-Events schlucken, sonst flackert dragleave/drop. */
    pointer-events: none;
    align-items: center;
    justify-content: center;
    background-color: var(--atlantis-blue-trans);
    border: 2px dashed var(--atlantis-blue-text);
    border-radius: 1rem;
}
#chatDropOverlay.visible {
    display: flex;
}
.chatDropOverlayInner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    color: var(--atlantis-blue-text);
    font-size: 1rem;
    pointer-events: none;
    /* Eigene Karte, damit Icon/Text auch über blauen Self-Bubbles lesbar bleiben. */
    background-color: white;
    padding: 1.5rem 2rem;
    border-radius: 1rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
}
.chatDropOverlayIcon {
    height: 3rem;
    width: 3rem;
}

/* ST1: --mbx-reply-bar-height (syncReplyBarSpace, mailbox.js) zieht die Hoehe der
   Zitat-Leiste ab, damit der Composer bei offener Antwort nicht unter den Dialogrand rutscht. */
#chatContent {
    height: calc(100vh - 17rem - var(--mbx-reply-bar-height, 0px));
    max-height: 70rem;
    overflow-y: auto;
    margin: 2px 0;
    padding: 0 0.5rem;
    /* ST3 (ST2-Nebenbefund, per E2E belegt): in column-reverse hielt Chromes Scroll-Anchoring beim
       prepend einer Poll-Bubble den alten Inhalt fest, sobald scrollTop nicht exakt 0 war (damals
       -4 direkt nach dem Oeffnen; seit scrollChatToBottom nur noch bei leicht hochgescrolltem
       Verlauf) -- jede neue Nachricht landete unterhalb des sichtbaren Bereichs
       (scrollTop -86/-168/-250). Ohne Anchoring bleibt der Stand am unteren Rand. */
    overflow-anchor: none;
}

/* ST11a (2026-06-29): Empty-State für komplett leere Chats — zentrierte
   dezente Hinweis-Box anstelle einer komplett weißen Fläche. */
#chatContent .chatEmptyState {
    margin: auto;
    text-align: center;
    color: var(--atlantis-anthracite);
    opacity: 0.6;
    padding: 1.5rem;
    font-size: 0.9375rem;
    line-height: 1.4;
}
#chatContent .chatEmptyState .chatEmptyStateCreated {
    margin-bottom: 0.5rem;
}
#chatContent .chatEmptyState .chatEmptyStatePrompt {
    font-style: italic;
}

/* ST11a (2026-06-30): Hinweistext für nicht-mehr-verfügbare Anhänge in
   einer Bubble (Server lieferte 404/Error). Keine Klickfläche mehr,
   nur dezenter italic-Text mit Dateinamen. */
.chatBubble .attachmentUnavailable {
    font-style: italic;
    opacity: 0.7;
    padding: 0.5rem;
    cursor: default;
}
#chatContent.previewOpen {
    height: calc(50vh - 8rem - var(--mbx-reply-bar-height, 0px));
    max-height: 32rem;
}

/* ST11a (AK8/AK12): The old pipe-separator `.chatBubble:not(.self) .msgSender`
   has been removed — sender names now live in `.bubbleSenderHeader` ABOVE the
   bubble for Other-Bubbles in group chats, and `.msgMeta` (time + read-status)
   is a DOM child of the bubble, rendered BESIDE it. */

/* ===========================================================================
   ST1 (Chat-Interaktionen): Nachrichten-Menue, Antworten mit Zitat, Sprung-Highlight.
   Alle Selektoren unter #msgDialog bzw. .chatBubble gescoped (meta.tpl laedt das
   Modul-CSS app-weit), Mobile ausschliesslich ueber body.isMobile (keine Media-Query,
   keine Important-Regel). Stand nach UI-Review (zwei Agents, Desktop + iPhone 13).
   =========================================================================== */

/* Hover-Symbol (Desktop) als weisser Chip NEBEN der Bubble -- rechts von fremden, links
   von eigenen Bubbles, also im freien Raum neben der Sprechblase (max-width 75 %): so
   verdeckt es weder Text noch Zeitstempel und ist auf grauer wie blauer Bubble lesbar.
   Den Raum teilt er sich mit der Uhrzeit (.msgMeta): der Chip sitzt buendig an der Oberkante
   der Sprechblase, die Uhrzeit an der Unterkante.
   Unsichtbar bis Hover/Fokus, damit die Bubble ruhig bleibt; das Symbol ist Kind der Bubble,
   :hover der Bubble gilt deshalb auch, wenn der Zeiger auf dem Chip steht. Bleibt sichtbar,
   solange das Menue dieser Bubble offen ist (.menuOpen), sonst verliert das Popover seinen
   Anker. Mobil ausgeblendet -- dort oeffnet der Long-Press.
   Die Chip-Optik (1rem-Glyphe, 0.25rem Padding, weisser Fond, Standardrand, rund) teilt sich
   das Symbol mit dem X der Zitat-Leiste (#chatReplyBarClose, unten). */
#msgDialog .chatBubble {
    position: relative;
}
#msgDialog .chatBubble .bubbleMenuToggle,
#chatReplyBarClose {
    width: 1rem;
    height: 1rem;
    padding: 0.25rem;
    box-sizing: content-box;
    background-color: white;
    border: var(--atlantis-std-border);
    border-radius: 50%;
}
#msgDialog .chatBubble .bubbleMenuToggle {
    position: absolute;
    top: 0;
    right: -2.125rem;
    box-shadow: 0 1px 0.25rem rgba(0, 0, 0, 0.12);
    opacity: 0;
    cursor: pointer;
    transition: opacity 0.15s;
    z-index: 1;
    scroll-margin-top: 3rem;
}
#msgDialog .chatBubble.self .bubbleMenuToggle {
    right: auto;
    left: -2.125rem;
}
/* Fremde Gruppen-Bubble mit sichtbarem Absender-Header: der Chip gehoert neben die graue
   Sprechblase, nicht neben den Namen (Header 1.75rem + 0.25rem Abstand). */
#msgDialog .chatBubble.hasSenderHeader .bubbleMenuToggle {
    top: 2rem;
}
/* Sichtbar ist der Chip ein Bedienelement und liegt dann ueber der mitlaufenden Datumsanzeige
   (#chatStickyDay, z-index 2). scroll-margin-top: muss der Tastaturfokus scrollen, haelt er
   unterhalb der Anzeige an; steht der Chip schon im Bild, bleibt er ueber ihr sichtbar. */
body:not(.isMobile) #msgDialog .chatBubble:hover .bubbleMenuToggle,
#msgDialog .chatBubble.menuOpen .bubbleMenuToggle,
#msgDialog .chatBubble .bubbleMenuToggle:focus-visible {
    opacity: 1;
    z-index: 3;
}
/* Das offene Menue haengt unter dem Chip und deckt den Raum neben der Blase ab -- die Uhrzeit
   ragte sonst angeschnitten ueber die Menuekante. Mobil ist das Menue ein Bottom-Sheet.
   Eigene Klasse .bubbleMenuOpen (openBubbleMenu/closeBubbleMenu): .menuOpen tragen auch das
   Namen-Popover der Reaktionen und der Emoji-Picker. Die sitzen an der Reaktionsleiste bzw.
   am "+", nicht neben der Blase -- nur nach oben geklappt schneiden sie die Uhrzeit wie den
   Blasentext an, das ist gewoehnliche Ueberdeckung und die Uhrzeit bleibt dort stehen. */
body:not(.isMobile) #msgDialog .chatBubble.bubbleMenuOpen .msgContainer .msgMeta {
    visibility: hidden;
}
/* Toenung als Schicht ueber dem weissen Fond statt an seiner Stelle: der Chip kann ueber der
   mitlaufenden Datumsanzeige liegen, deren Text sonst durchschiene. */
#msgDialog .chatBubble .bubbleMenuToggle:hover {
    background-image: linear-gradient(var(--atlantis-blue-trans), var(--atlantis-blue-trans));
}
/* Noch nicht bestaetigte Nachricht (tmp-cm_id): kein Menue moeglich, also kein Chip. Ebenso
   bei Blockade durch die Gegenseite (KF 5: dort bleibt auch die Reaktions-Schnellleiste leer,
   openBubbleMenu haelt das Menue zu -- der Chip waere ein totes Bedienelement). Betrachter
   (commentingAllowed='false') sehen den Chip seit ST3: das Menue zeigt ihnen die
   Schnellleiste ohne "Antworten". */
#msgDialog .chatBubble[cm_id^="tmp"] .bubbleMenuToggle,
#chatMsgContainer[blockedByOther='true'] .chatBubble .bubbleMenuToggle,
body.isMobile #msgDialog .chatBubble .bubbleMenuToggle {
    display: none;
}
/* KF 9: Long-Press braucht user-select: none -- Textkopie aus Bubbles entfaellt mobil
   (WhatsApp-Verhalten), das iOS-Callout ebenso. */
body.isMobile #msgDialog .chatBubble {
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}
/* Rueckmeldung waehrend des Long-Press (ab ~120 ms, siehe initBubbleMenu). */
body.isMobile #msgDialog .chatBubble.pressing .msgContainer {
    filter: brightness(0.93);
    transition: filter 0.1s;
}

/* Das Menue: EINE Instanz direkt unter #msgDialog, position fixed (Lage setzt
   positionChatPopover aus getBoundingClientRect, begrenzt auf #chatContent). z-index
   innerhalb des #msgDialog-Stacking-Contexts ueber dem .dialogWindow und dem
   Chat-Header-Menue (z:20). Das Namen-Popover der Reaktionen (ST3, #reactionWhoPopover)
   ist dasselbe Gefaess -- Grundregeln und Bottom-Sheet gelten fuer beide, eigene Regeln
   des Popovers stehen im ST3-Block. */
#bubbleMenu,
#reactionWhoPopover {
    position: fixed;
    z-index: 30;
    background-color: white;
    border: var(--atlantis-std-border);
    border-radius: 1rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.15);
    min-width: 12rem;
    padding: 0.5rem;
    box-sizing: border-box;
}
#bubbleMenuBackdrop {
    position: fixed;
    inset: 0;
    z-index: 29;
    background-color: rgba(0, 0, 0, 0.3);
}
/* Mobil als Bottom-Sheet: volle Breite am unteren Rand, oben gerundet, kein Rand an den
   Viewportkanten, kurz von unten eingeblendet. */
body.isMobile #bubbleMenu,
body.isMobile #reactionWhoPopover {
    left: 0;
    right: 0;
    bottom: 0;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
    border-radius: 1rem 1rem 0 0;
    padding-bottom: 1.5rem;
    animation: mbxSheetUp 0.18s ease-out;
}
@keyframes mbxSheetUp {
    from {
        transform: translateY(100%);
    }
    to {
        transform: translateY(0);
    }
}
/* ST3: dieselben Eintraege im Namen-Popover (#reactionWhoRemoveMine traegt .bubbleMenuItem). */
#bubbleMenu .bubbleMenuItem,
#reactionWhoPopover .bubbleMenuItem {
    padding: 0.75rem 1rem;
    cursor: pointer;
    border-radius: 0.5rem;
    font-size: 0.9375rem;
    color: var(--atlantis-anthracite);
    white-space: nowrap;
}
body:not(.isMobile) #bubbleMenu .bubbleMenuItem:hover,
body:not(.isMobile) #reactionWhoPopover .bubbleMenuItem:hover {
    background-color: var(--atlantis-blue-trans);
}
#bubbleMenu .bubbleMenuItem:focus-visible,
#reactionWhoPopover .bubbleMenuItem:focus-visible {
    background-color: var(--atlantis-blue-trans);
    outline: 2px solid var(--atlantis-blue-text);
    outline-offset: -2px;
}
body.isMobile #bubbleMenu .bubbleMenuItem,
body.isMobile #reactionWhoPopover .bubbleMenuItem {
    padding: 1rem;
    font-size: 1.0625rem;
}

/* Zitat in der Bubble: farbige Kante links, gekuerzter Text (max. 2 Zeilen), klickbar
   fuer den Sprung zum Original. In der eigenen (blauen) Bubble weisse Kante und dunkler
   Fond (Weiss auf rgba(0,0,0,.14) ueber Atlantis-Blau = 5,0:1; der helle Fond lag bei 2,8:1). */
#msgDialog .chatBubble .replyQuote {
    border-left: 0.25rem solid var(--atlantis-blue-text);
    background-color: rgba(0, 0, 0, 0.06);
    border-radius: 0.5rem;
    padding: 0.25rem 0.5rem;
    margin-bottom: 0.5rem;
    cursor: pointer;
    white-space: normal;
    line-height: 1.35;
}
#msgDialog .chatBubble .replyQuote:not(.unavailable):hover {
    background-color: rgba(0, 0, 0, 0.1);
}
#msgDialog .chatBubble.self .replyQuote {
    border-left-color: white;
    background-color: rgba(0, 0, 0, 0.14);
}
#msgDialog .chatBubble.self .replyQuote:not(.unavailable):hover {
    background-color: rgba(0, 0, 0, 0.22);
}
#msgDialog .chatBubble .replyQuoteSender {
    font-size: 0.75rem;
    font-weight: 600;
}
#msgDialog .chatBubble .replyQuoteText {
    font-size: 0.875rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}
/* Anhang-Zitat einzeilig: Icon + Dateiname nebeneinander, Dateiname mit Ellipsis (sonst
   rutscht ein langer Name unter das Icon und der 2-Zeilen-Clamp schneidet ihn ab). */
#msgDialog .chatBubble .replyQuote.isFile .replyQuoteText {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}
#msgDialog .chatBubble .replyQuoteFileName {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Datei-Icon des Anhang-Zitats -- dasselbe Markup (buildReplyQuoteFileIcon) in der Bubble
   und in der Zitat-Leiste des Composers; flex greift nur im Flex-Kontext der Bubble. */
#msgDialog .chatBubble .replyQuoteFileIcon,
#chatReplyBarText .replyQuoteFileIcon {
    width: 1rem;
    height: 1rem;
    vertical-align: middle;
    margin-right: 0.25rem;
    flex: 0 0 auto;
}
#msgDialog .chatBubble .replyQuote.unavailable {
    cursor: default;
    font-style: italic;
    opacity: 0.8;
}
#msgDialog .chatBubble.self .replyQuote.unavailable {
    opacity: 1;
}

/* Zitat-Leiste im Composer: erstes Kind von #chatTypingArea, nimmt eine volle Zeile
   (flex-wrap), darunter die bestehende Zeile Emoji/Anhang/Textarea/Senden. min-width: 0
   ist Pflicht: als Flex-Item behielte die Leiste sonst die Min-Content-Breite ihres
   nowrap-Texts und liefe mit dem X aus Dialog bzw. Viewport. Die Hoehenaenderung erfasst
   syncMobileComposerHeight (PR #145) ueber offsetHeight, am Desktop syncReplyBarSpace. */
#chatTypingArea {
    flex-wrap: wrap;
}
#chatReplyBar {
    flex: 1 1 100%;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border-left: 0.25rem solid var(--atlantis-blue-text);
    background-color: var(--atlantis-lightgrey);
    border-radius: 0.5rem;
    padding: 0.25rem 0.5rem;
    box-sizing: border-box;
    line-height: 1.35;
}
#chatReplyBar .chatReplyBarBody {
    flex: 1 1 auto;
    min-width: 0;
}
#chatReplyBarSender {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--atlantis-anthracite);
}
#chatReplyBarText {
    font-size: 0.875rem;
    color: var(--atlantis-anthracite);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* X als weisser Chip wie das Menue-Symbol (das nackte cross.svg war auf dem grauen Fond
   kaum zu sehen) -- die Chip-Optik steht in der Gruppe mit .bubbleMenuToggle (oben);
   Tastatur: Enter/Space, siehe initBubbleMenu. */
#chatReplyBarClose {
    flex: 0 0 auto;
}
#chatReplyBarClose:hover,
#chatReplyBarClose:focus-visible {
    background-color: var(--atlantis-blue-trans);
    border-color: var(--atlantis-blue-text);
}
/* Touch-Ziel ~42,5 px (wie der Senden-Knopf), ohne die Leiste hoeher zu machen; Glyphe
   1.5rem wie die Composer-Symbole, sonst bleibt vom Kreuz auf der grossen Scheibe wenig. */
body.isMobile #chatReplyBarClose {
    width: 1.5rem;
    height: 1.5rem;
    padding: 0.625rem;
    margin: -0.5rem -0.25rem -0.5rem 0;
}

/* Sprung zum Original: die Ziel-Bubble leuchtet 1,5 s auf; auf der blauen Bubble mit
   weissem Innenring, sonst geht der blaue Ring im Blau unter. */
#msgDialog .chatBubble.highlightFlash .msgContainer {
    animation: mbxHighlightFlash 1.5s ease-out;
}
#msgDialog .chatBubble.self.highlightFlash .msgContainer {
    animation-name: mbxHighlightFlashSelf;
}
@keyframes mbxHighlightFlash {
    0%, 60% {
        box-shadow: 0 0 0 0.25rem var(--atlantis-blue-selected);
    }
    100% {
        box-shadow: none;
    }
}
@keyframes mbxHighlightFlashSelf {
    0%, 60% {
        box-shadow: 0 0 0 2px white, 0 0 0 0.375rem var(--atlantis-blue-selected);
    }
    100% {
        box-shadow: none;
    }
}

/* ===========================================================================
   ST2 (Chat-Interaktionen): @Erwaehnen -- Chip in der Bubble, Teilnehmer-Picker im
   Composer, Backdrop-Hervorhebung der Namen in der Textarea (KF 6). Gescoped unter
   #msgDialog / .chatBubble, Mobile nur ueber body.isMobile.
   =========================================================================== */

/* Chip in der Bubble: Name des Erwaehnten hervorgehoben; .self = der Betrachter selbst ist
   gemeint. Kontraste nach UI-Review (Desktop + iPhone 13): blauer Text auf blauem Fond lag bei
   2,8:1 -- deshalb Anthrazit auf blau getoentem Fond (color-mix aus dem Token, 7,4:1); auf der
   eigenen blauen Bubble abgedunkelter Fond wie beim Zitat (weiss darauf >= 5,4:1) statt weiss
   halbtransparent (2,6:1). box-decoration-break: clone rundet beide Fragmente eines am
   Zeilenende umbrochenen Namens; das schmale Padding laesst Satzzeichen direkt anschliessen. */
#msgDialog .chatBubble .mentionChip {
    background-color: color-mix(in srgb, var(--atlantis-blue-text) 22%, transparent);
    color: var(--atlantis-anthracite);
    border-radius: 0.5rem;
    padding: 0 0.125rem;
    font-weight: 600;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
}
#msgDialog .chatBubble.self .mentionChip {
    background-color: rgba(0, 0, 0, 0.22);
    color: white;
}
#msgDialog .chatBubble .mentionChip.self {
    text-decoration: underline;
}

/* Picker: volle Composer-Zeile direkt ueber der Eingabezeile (flex-wrap in #chatTypingArea,
   im Template NACH der Zitat-Leiste -- UI-Review: die Kandidatenliste gehoert an die Textarea,
   nicht ueber das Zitat), scrollbar ab 14rem mit schmaler Scrollbar (die klassische lief in
   die Rundung). position: relative, damit offsetTop der Zeilen sich auf den Picker bezieht
   (setMentionPickerActive scrollt ohne scrollIntoView). */
#msgDialog #mentionPicker {
    position: relative;
    flex: 1 0 100%;
    min-width: 0;
    max-height: 14rem;
    overflow-y: auto;
    scrollbar-width: thin;
    background-color: white;
    border: var(--atlantis-std-border);
    border-radius: 1rem;
    padding: 0.25rem;
    box-sizing: border-box;
}
/* overscroll-behavior: am Listenende darf der Touch-Scroll nicht auf #chatContent durchreichen. */
body.isMobile #msgDialog #mentionPicker {
    max-height: 40vh;
    overscroll-behavior: contain;
}
#msgDialog #mentionPicker .mentionPickerItem {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    cursor: pointer;
    color: var(--atlantis-anthracite);
    line-height: 1.35;
}
/* Aktive Zeile (Tastatur, Enter waehlt sie) blau mit Balken links (Muster .chatListItem.selected);
   blosser Mauszeiger grau, damit beide Zustaende unterscheidbar bleiben (der Zeiger kann still
   ueber dem aufgehenden Picker stehen). */
#msgDialog #mentionPicker .mentionPickerItem:hover {
    background-color: var(--atlantis-lightgrey);
}
#msgDialog #mentionPicker .mentionPickerItem.active {
    background-color: var(--atlantis-blue-trans);
    box-shadow: inset 0.1875rem 0 0 var(--atlantis-blue-text);
}
#msgDialog #mentionPicker .mentionPickerName {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
#msgDialog #mentionPicker .mentionPickerRole {
    flex: 0 0 auto;
    font-size: 0.75rem;
    opacity: 0.85;
}
#msgDialog #mentionPicker .mentionPickerEmpty {
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    font-style: italic;
    color: var(--atlantis-anthracite);
    opacity: 0.7;
}
/* Kappungs-Hinweis klebt am unteren Rand des scrollenden Pickers (sonst erst nach dem Scrollen
   hinter 30 Zeilen sichtbar); opacity 1 + weisser Fond, damit die darunter scrollenden Zeilen
   nicht durchscheinen. */
#msgDialog #mentionPicker .mentionPickerMore {
    position: sticky;
    bottom: -0.25rem;
    margin: 0 -0.25rem -0.25rem;
    padding: 0.375rem 1rem 0.5rem;
    border-top: 1px solid var(--atlantis-lightgrey);
    background-color: white;
    opacity: 1;
    color: var(--atlantis-anthracite);
}
/* Touch-Zeilen >= 44 px hoch (1.0625rem * 1.35 + 2 * 0.875rem = 44,6 px); auf Touch-Geraeten
   bleibt :hover nach einem Tipp haengen -- dort keine graue Zeile. */
body.isMobile #msgDialog #mentionPicker .mentionPickerItem {
    padding: 0.875rem 1rem;
    font-size: 1.0625rem;
}
body.isMobile #msgDialog #mentionPicker .mentionPickerItem:hover:not(.active) {
    background-color: transparent;
}
body.isMobile #msgDialog #mentionPicker .mentionPickerRole {
    font-size: 0.875rem;
}
body.isMobile #msgDialog #mentionPicker .mentionPickerEmpty {
    padding: 0.75rem 1rem;
    font-size: 1rem;
}

/* Backdrop (ST2-10, Sollte): #chatTextareaWrap tritt an die Flex-Stelle der Textarea; der
   Backdrop liegt dahinter mit demselben Text in transparenter Schrift, nur die Namen tragen
   einen Fond. Schrift, Padding, Rand (transparent, gleiche Breite) und Zeilenhoehe MUESSEN
   mit #chatTextarea uebereinstimmen, sonst verschiebt sich die Hervorhebung gegen den Text.
   Weisser Fond und Radius wandern von der Textarea auf den Wrapper.
   flex-basis 0 wie zuvor die Textarea (flex: 1): mit auto zaehlte die Eigenbreite der
   Textarea (cols 20, rund 210 px) als Wunschbreite, und #chatTypingArea (flex-wrap fuer
   Zitat-Leiste und Picker) brach bis 357 px Breite den Senden-Knopf in eine zweite Zeile. */
#msgDialog #chatTextareaWrap {
    position: relative;
    display: flex;
    flex: 1 1 0;
    min-width: 0;
    background-color: white;
    border-radius: 1rem;
}
#msgDialog #chatTextareaWrap #chatTextarea {
    position: relative;
    display: block;
    width: 100%;
    background-color: transparent;
}
#msgDialog #chatTextareaBackdrop {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    color: transparent;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    /* Randbreite aus demselben Token wie #chatTextarea, damit beide zusammen wandern. */
    border: var(--atlantis-std-border);
    border-color: transparent;
    border-radius: 1rem;
    padding: 0.5rem 0.75rem;
    box-sizing: border-box;
    line-height: 1.4;
    font-family: inherit;
    font-size: 1rem;
}
body.isMobile #msgDialog #chatTextareaBackdrop {
    font-size: 1.2rem;
}
/* Fond kraeftiger als --atlantis-blue-trans (1,14:1 auf Weiss war kaum wahrnehmbar); kein
   Padding, das wuerde die Zeilenmessung gegen die Textarea verschieben. */
#msgDialog #chatTextareaBackdrop .mentionChipBg {
    background-color: color-mix(in srgb, var(--atlantis-blue-opaque) 35%, transparent);
    border-radius: 0.5rem;
}

/* ===========================================================================
   ST3 (Chat-Interaktionen): Reaktionen -- Pills unter der Bubble, Schnellleiste im
   #bubbleMenu, Namen-Popover. Gescoped unter #msgDialog / #bubbleMenu /
   #reactionWhoPopover, Mobile nur ueber body.isMobile.
   =========================================================================== */

/* Leiste unter .msgContainer: Pills umbrechen, bei eigenen Bubbles rechtsbuendig (die Bubble
   selbst sitzt rechts). Sichtbarkeit steuert renderReactionBar (leer -> display: none). */
#msgDialog .chatBubble .reactionBar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: 0.25rem;
    margin-bottom: 0.25rem;
    /* UI-Review D-S4: die Leiste darf die Sprechblase nicht verbreitern -- ohne contain zaehlte
       ihre max-content-Breite (alle Pills in einer Zeile) in die Bubble-Breite. */
    contain: inline-size;
}
#msgDialog .chatBubble.self .reactionBar {
    justify-content: flex-end;
}
/* Sehr kurze Nachricht mit mehreren Pills: ohne Mindestbreite stuende je Zeile eine Pill
   (UI-Review D2-K3). */
#msgDialog .chatBubble:has(.reactionPill) {
    min-width: 10rem;
}
/* Pill: Emoji + Anzahl, grau getoent mit Standardrand; die eigene Reaktion traegt einen
   blauen Fond und eine blaue Zahl, aber den grauen Rand -- ein blauer Rand las sich wie ein
   Fokus-Rahmen (User 30.09.2026). Klick/Enter -> Namen-Popover. */
#msgDialog .chatBubble .reactionPill {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    height: 1.5rem;
    padding: 0 0.5rem;
    border-radius: 1rem;
    /* leicht getoent statt weiss: auf dem weissen Chatgrund zeichnete sich die fremde Pill
       nur ueber den 1,27:1-Rand ab (UI-Review D-K7/M-K2) */
    background-color: color-mix(in srgb, var(--atlantis-lightgrey) 40%, white);
    border: var(--atlantis-std-border);
    font-size: 0.875rem;
    line-height: 1;
    color: var(--atlantis-anthracite);
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}
/* Hover ueber den Rand, nicht ueber den Fond -- der Fond ist das Kennzeichen der eigenen
   Reaktion (D-K3). Nur mit Maus (auf Touch bliebe :hover nach dem Tipp haengen). */
body:not(.isMobile) #msgDialog .chatBubble .reactionPill:hover {
    border-color: var(--atlantis-darkgrey);
}
/* Fond wie das eigene Emoji der Schnellleiste (.quickReaction.mine); --atlantis-blue-trans
   hob sich nur 1,04:1 von der fremden Pill ab. Die Zahl dunkler als --atlantis-blue-text
   (dort 3,4:1 auf dem Fond), damit sie als kleiner Text 4,5:1 erreicht (UI-Review 30.09.). */
#msgDialog .chatBubble .reactionPill.self {
    background-color: color-mix(in srgb, var(--atlantis-blue-text) 22%, transparent);
}
#msgDialog .chatBubble .reactionPill.self .reactionCount {
    color: color-mix(in srgb, var(--atlantis-blue-text) 75%, black);
}
#msgDialog .chatBubble .reactionPill:focus-visible {
    outline: 2px solid var(--atlantis-blue-text);
    outline-offset: 1px;
}
#msgDialog .chatBubble .reactionPill .reactionEmoji {
    font-size: 1rem;
}
#msgDialog .chatBubble .reactionPill .reactionCount {
    font-weight: 600;
    min-width: 0.5rem;
}
/* Touch: Pills als Ziele 2.25rem hoch (31,5 px + Rand = 35,5 px), etwas mehr Luft dazwischen
   (UI-Review M-S2). */
body.isMobile #msgDialog .chatBubble .reactionBar {
    gap: 0.375rem;
}
body.isMobile #msgDialog .chatBubble .reactionPill {
    height: 2.25rem;
    padding: 0 0.75rem;
    font-size: 0.9375rem;
}

/* Schnellleiste im Menue: sechs Emojis + "+" (voller Picker), durch eine Linie vom
   "Antworten" getrennt. Bei Betrachtern ist sie der einzige Inhalt -- dann ohne Linie. */
#bubbleMenu .bubbleMenuReactions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem 0.25rem 0.5rem;
    border-bottom: var(--atlantis-std-border);
    margin-bottom: 0.25rem;
}
/* Betrachter: kein "Antworten" -> keine Trennlinie (Klasse setzt openBubbleMenu; :last-child
   griffe nicht, der ausgeblendete Eintrag bleibt im DOM -- UI-Review D-S1/M-S6). */
#bubbleMenu.reactionsOnly .bubbleMenuReactions {
    border-bottom: 0;
    margin-bottom: 0;
    padding-bottom: 0.25rem;
}
/* Sechs Emojis und das "+" sind gleich grosse, gleich gerundete Ziele mit demselben Hover. */
#bubbleMenu .quickReaction,
#bubbleMenu .quickReactionMore {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 1rem;
}
#bubbleMenu .quickReaction {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}
#bubbleMenu .quickReactionMore {
    padding: 0.5rem;
    box-sizing: border-box;
    margin-left: 0.25rem;
}
body:not(.isMobile) #bubbleMenu .quickReaction:hover,
body:not(.isMobile) #bubbleMenu .quickReactionMore:hover {
    background-color: var(--atlantis-blue-trans);
}
body:not(.isMobile) #bubbleMenu .quickReaction.mine:hover {
    background-color: color-mix(in srgb, var(--atlantis-blue-text) 30%, transparent);
}
/* Eigenes Emoji: kraeftiger Fond ohne Ring -- der Ring bleibt dem Tastaturfokus vorbehalten,
   sonst waeren .mine und :focus-visible nicht unterscheidbar (UI-Review D-S3). */
#bubbleMenu .quickReaction.mine {
    background-color: color-mix(in srgb, var(--atlantis-blue-text) 22%, transparent);
}
#bubbleMenu .quickReaction:focus-visible,
#bubbleMenu .quickReactionMore:focus-visible {
    outline: 2px solid var(--atlantis-blue-text);
    outline-offset: 1px;
}
/* Mobil (Bottom-Sheet): Leiste ueber die volle Breite verteilt, groessere Touch-Ziele. */
body.isMobile #bubbleMenu .bubbleMenuReactions {
    justify-content: space-between;
    padding: 0.5rem 0.75rem 0.75rem;
}
body.isMobile #bubbleMenu.reactionsOnly .bubbleMenuReactions {
    padding-bottom: 0.5rem;
}
/* Mobil ist der Chip ausgeblendet -- die Ziel-Bubble des offenen Sheets/Pickers zeigt sich
   ueber einen blauen Rahmen mit weissem Zwischenring, damit er auch auf der eigenen (blauen)
   Sprechblase sichtbar bleibt (UI-Review M2-K3, Runde 3). */
body.isMobile #msgDialog .chatBubble.menuOpen .msgContainer {
    box-shadow: 0 0 0 2px white, 0 0 0 4px var(--atlantis-blue-text);
}
body.isMobile #bubbleMenu .quickReaction,
body.isMobile #bubbleMenu .quickReactionMore {
    width: 3.25rem;
    height: 3.25rem;
}
body.isMobile #bubbleMenu .quickReaction {
    font-size: 1.75rem;
}
body.isMobile #bubbleMenu .quickReactionMore {
    margin-left: 0;
    padding: 0.625rem;
}

/* Namen-Popover (KF 10): EINE Instanz wie #bubbleMenu -- Desktop fixed an der Pill, mobil als
   Bottom-Sheet mit dem gemeinsamen Backdrop (Grundregeln und Sheet gemeinsam mit #bubbleMenu im
   ST1-Block). Flex-Spalte, damit nur die Liste scrollt; Liste ab halber Viewporthoehe. */
#reactionWhoPopover {
    display: flex;
    flex-direction: column;
    max-width: 20rem;
    max-height: 50vh;
    color: var(--atlantis-anthracite);
}
#reactionWhoPopover .reactionWhoTitle {
    flex: 0 0 auto;
    font-weight: 600;
    padding: 0.25rem 1rem 0.5rem;
    border-bottom: var(--atlantis-std-border);
    margin-bottom: 0.25rem;
    outline: none;
}
/* Nur die Namensliste scrollt -- Titel und "Meine Reaktion entfernen" bleiben stehen
   (UI-Review M-S4/D-K5). */
#reactionWhoPopover .reactionWhoList {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
}
#reactionWhoPopover .reactionWhoRow {
    padding: 0.25rem 1rem;
    font-size: 0.9375rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
#reactionWhoPopover #reactionWhoRemoveMine {
    flex: 0 0 auto;
    margin-top: 0.25rem;
    border-top: var(--atlantis-std-border);
    border-radius: 0 0 0.5rem 0.5rem;
}
body.isMobile #reactionWhoPopover {
    max-width: none;
}
body.isMobile #reactionWhoPopover .reactionWhoRow {
    padding: 0.75rem 1rem;
    font-size: 1.0625rem;
    white-space: normal;
}

/* Chat typing area: emoji + attach + textarea + send-button in one row.
   ST11a (#24, 2026-06-30): Klare Trennung zum Chat-Bereich über border-top —
   kein zusätzlicher Hintergrund-Strip, der mit den runden Dialog-Ecken
   bricht. Horizontal mehr padding damit die Icons nicht am Rand kleben. */
#chatTypingArea {
    border-top: var(--atlantis-std-border);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    box-sizing: border-box;
}

.chatTypingIcon {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
}

/* ST11a (#22, 2026-06-30): Textarea wächst mit dem Inhalt (autoGrow via JS).
   min-height = 2.5rem, max-height begrenzt auf ~6 Zeilen damit der Composer
   nicht den Chat-Bereich überrollt. line-height auf normales Verhältnis
   damit mehrzeilig vernünftig aussieht. */
#chatTextarea, #chatTextareaDummy {
    flex: 1;
    min-width: 0;
    min-height: 2.5rem;
    max-height: 9rem;
    resize: none;
    border: var(--atlantis-std-border);
    border-radius: 1rem;
    padding: 0.5rem 0.75rem;
    box-sizing: border-box;
    line-height: 1.4;
    font-family: inherit;
    font-size: 1rem;
    background-color: white;
}
#chatTextareaDummy {
    outline: none;
    text-align: center;
}

/* ST11a (#3, 2026-06-29): Send-Button als sauberer runder Atlantis-blauer
   Kreis mit klar erkennbarem Pfeil — Pfeil-Icon kleiner, damit es nicht den
   Button-Rand berührt; volle --atlantis-blue-text-Farbe statt blass. */
#sendChatMsgButton {
    flex: 0 0 auto;
    width: 3.5rem;
    height: 3.5rem;
    padding: 0;
    border-radius: 50%;
    background: var(--atlantis-blue-text);
    border: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
#sendChatMsgButton:hover:not(:disabled) {
    background: var(--atlantis-blue-selected);
    border: 0;
}
#sendChatMsgButton img {
    width: 2.5rem;
    height: 2.5rem;
    filter: brightness(0) invert(1);
}

/* Mobile: typing area pinned to viewport bottom. position:sticky alone
   does not work when the chat scroll-container is taller than the viewport
   (the bar then sits at the container bottom, below the visible area).
   position:fixed guarantees visibility regardless of scroll state. */
body.isMobile #chatTypingArea {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: white;
    border-top: var(--atlantis-std-border);
    box-sizing: border-box;
    z-index: 11;
}
/* B2 fix: Im Mobile-Listen-View (kein Chat offen, .mobileChatOpen fehlt) darf
   der position:fixed-Composer nicht sichtbar sein — sonst entkommt er dem
   overflow:hidden-Clip der weggeschobenen Chat-Spalte und klebt in der Liste. */
body.isMobile #msgDialog:not(.mobileChatOpen) #chatTypingArea {
    display: none;
}
/* #chatContent laeuft nicht unter den fixen Composer: #chatMessagePane endet an dessen
   Oberkante (siehe body.isMobile #chatMessagePane). Unten bleibt nur etwas Luft. */
body.isMobile #chatContent {
    padding-bottom: 0.5rem;
    box-sizing: border-box;
}
/* Die Desktop-Kappung bei offener Anhang-Vorschau (#chatContent.previewOpen, max-height
   32rem) liess mobil zwischen Verlauf und Vorschau rund 140 px frei. Mobil teilen sich beide
   den Nachrichtenbereich ohne Kappung. */
body.isMobile #chatContent.previewOpen {
    max-height: none;
}
body.isMobile #sendChatMsgButton {
    width: 3rem;
    height: 3rem;
}

/* ST11a (#27, 2026-06-30): Touch-Targets ≥44px (3rem ≈ 42px bei 14px base,
   reicht knapp; padding um das Icon vergrössert die hitbox). */
body.isMobile .chatTypingIcon {
    width: 1.75rem;
    height: 1.75rem;
    padding: 0.5rem;
    box-sizing: content-box;
}

/* iOS Safari zoomt beim Fokus in jedes Eingabefeld mit font-size < 16px in die
   Seite hinein (Auto-Zoom, nicht abschaltbar ohne den Viewport zu sperren).
   App-Standard fuer Eingabefelder ist 1.2rem (design_2026.css) — Composer und
   Teilnehmer-Suche setzen 1rem (= 14px) und lagen darunter. Mobil auf den
   Standard anheben; Desktop behaelt das ST11a-Mass. */
body.isMobile #chatTextarea,
body.isMobile #chatTextareaDummy,
body.isMobile .newChatSelectionSearchInput {
    font-size: 1.2rem;
}

/* Der Dummy tritt an die Stelle der echten Bedienelemente, sobald einer der drei
   Sperrgruende greift. Sein :not() muss deshalb ALLE drei ausnehmen — sonst waere
   bei fehlender Chat-Auswahl weder das echte Textfeld (unten ausgeblendet) noch
   der Dummy sichtbar und die Zeile bliebe leer.
   ST2: gesperrt wird der Wrapper #chatTextareaWrap (Textarea + Backdrop), nicht mehr die
   Textarea allein -- sonst bliebe ein leerer Flex-Wrapper neben dem Dummy stehen. */
#chatMsgContainer[commentingAllowed='false'] #emoji-button,
#chatMsgContainer[commentingAllowed='false'] #addAttachmentButton,
#chatMsgContainer[commentingAllowed='false'] #chatTextareaWrap,
#chatMsgContainer[commentingAllowed='false'] #sendChatMsgButton,
#chatMsgContainer[commentingAllowed='true']:not([blockedByOther='true']):not([noChatSelected='true']) #chatTextareaDummy,
#chatMsgContainer[blockedByOther='true'] #emoji-button,
#chatMsgContainer[blockedByOther='true'] #addAttachmentButton,
#chatMsgContainer[blockedByOther='true'] #chatTextareaWrap,
#chatMsgContainer[blockedByOther='true'] #sendChatMsgButton,
#chatMsgContainer[noChatSelected='true'] #emoji-button,
#chatMsgContainer[noChatSelected='true'] #addAttachmentButton,
#chatMsgContainer[noChatSelected='true'] #chatTextareaWrap,
#chatMsgContainer[noChatSelected='true'] #sendChatMsgButton {
    display: none;
}

/* Task-1: Auswahl-Liste an den programmweiten Standard angeglichen — identisch
   zu #genericFilteredSelection (Klassenbuch/Schülerliste): graues Zebra, volle
   Blau-Auswahl mit weißer Schrift; die runden Zeilenecken liefert .tableDesign. */
#newChatSelection tr {
    vertical-align: top;
    cursor: pointer;
}

#newChatSelection tr.oddRow {
    background-color: var(--atlantis-lightgrey);
}

#newChatSelection tr.selected {
    background-color: var(--atlantis-blue);
    color: white;
}

#newChatSelection td {
    padding: 0.25rem 0.5rem;
}

/* Erste SICHTBARE Zelle links runden: .tableDesign td:first-child trifft die
   ausgeblendete .hidden-Zelle (display:none), daher hier explizit auf
   .displayValue — sonst bleiben die linken Ecken eckig. */
#newChatSelection td.displayValue {
    border-top-left-radius: 1rem;
    border-bottom-left-radius: 1rem;
}

#newChatSelection .classDisplay,
#newChatSelection .courseDisplay {
    white-space: pre-wrap;
}

.newChatFilterDisplay {
    /* Die ganze Box öffnet die Auswahl (Handler in initMailbox), nicht nur die
       Lupe daneben — sie sieht aus wie ein Eingabefeld. */
    cursor: pointer;
    width: 16rem;
    border: var(--atlantis-std-border);
    border-radius: 1rem;
    white-space: pre-wrap;
    max-height: 6rem;
    /* Leere Box genauso hoch wie eine mit einem Teilnehmer — sonst sind die
       Felder untereinander unterschiedlich hoch, obwohl sie wie gleichartige
       Eingabefelder aussehen. Der Wert MUSS der line-height der Box
       entsprechen: hier die geerbte 2.5rem aus der globalen td-Regel, auf
       Mobile die dort gesetzten 2.2em (siehe body.isMobile-Block weiter unten).
       line-height hier explizit, obwohl sie dieselbe ist wie die geerbte
       td-Regel: sonst haengt die Box-Hoehe unsichtbar an design_2026.css. */
    line-height: 2.5rem;
    min-height: 2.5rem;
    float: left;
    overflow-y: auto;
    padding: 0.25rem 0.75rem;
    margin: 0.5rem 0.75rem;
}

.newChatGroupNameRow > td {
    border-top: var(--atlantis-std-border);
    padding-top: 1rem;
}

.newChatGroupNameRow > td:nth-child(2) {
    padding-right: 0.75rem;
}

.newChatGroupNameInput {
    width: 100%;
    box-sizing: border-box;
    margin: 0.5rem 0;
}

/* Eine Teilnehmerzeile in den Auswahl-Boxen (#newParticipantTemplate-Klon):
   Name links, Kommentier-Toggle rechtsbündig auf gleicher Höhe.
   Bewusst KEIN float für die Icons: die Icons sind 32px hoch, eine Zeile aber
   nur ~31px — der 1px Überstand ragte in die nächste Zeile und schob deren
   Float um eine volle Icon-Breite nach links (je Zeile ein anderer rechter
   Rand). Flex hat das Problem nicht und zentriert das Icon zum Namen. */
.newChatFilterDisplay > div[selectionID] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

/* Namen einzeilig mit Ellipsis — gleiche Behandlung wie in der Gruppen-
   Teilnehmerliste (.chatParticipantMain .noBreakEllipsis). Umbrechende Namen
   wären hier schädlich: das Icon zentriert dann gegen die GESAMTE mehrzeilige
   Zeile und schwebt mitten im Namen statt neben der ersten Zeile.
   min-width: 0 hebt die Flex-Mindestbreite auf, sonst greift text-overflow
   nicht und der Name drückt das Icon aus der Box. */
.newChatFilterDisplay > div[selectionID] > .displayName {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.allowCommentButton,
.disallowCommentButton {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    /* Padding statt größerem Icon: vergrößert die Trefferfläche auf 2rem,
       ohne die Zeile optisch aufzublähen. */
    padding: 0.25rem;
    cursor: pointer;
}

/* Gesperrt-Zustand zusätzlich zum durchgestrichenen Stift leicht abgedunkelt —
   der Unterschied bleibt so auch ohne Farbwahrnehmung erkennbar. */
.disallowCommentButton {
    opacity: 0.7;
}

/* Erklärt den Toggle im Dialog selbst — aber NUR auf Mobile und nur, solange
   Teilnehmer ausgewählt sind (Klasse von updateNewChatCommentHint). Auf Desktop
   liefert der Tooltip am Stift dieselbe Erklärung; initTooltip (global.js)
   haengt Tooltips ausschliesslich ausserhalb von isMobile ein, deshalb braucht
   es die Zeile genau dort, wo der Tooltip fehlt. */
.newChatCommentHint {
    display: none;
    align-items: center;
    gap: 0.5rem;
    /* linksbündig mit der Label-Spalte der Filter-Tabelle */
    margin: 0.5rem 0.75rem 0 0;
    font-size: 0.8rem;
    /* eigene line-height: die geerbten 1.8rem der Tabelle ergeben bei 0.8rem
       Schrift Faktor 2,25 — die zwei Zeilen wirken dann zusammenhanglos. */
    line-height: 1.4;
    /* NICHT --atlantis-darkgrey: auf Weiß nur 1,86:1 Kontrast. Dieser Text soll
       gelesen werden, deshalb dieselbe Farbe wie die Feld-Labels daneben. */
    color: grey;
    /* Der Dialog ist Shrink-to-fit: ohne Deckel setzt diese Zeile auf Desktop
       die Dialogbreite (gemessen 694px statt 453px) und reisst ein totes Feld
       rechts neben dem Formular auf. Der Wert MUSS unter der Breite der
       Filter-Tabelle (26,5rem) bleiben — auch bei längeren Übersetzungen. */
    max-width: 26rem;
}

body.isMobile .newChatCommentHint.hasParticipants {
    display: flex;
}

.newChatCommentHint > img {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
}

.loadingMoreMsgsIndicator {
    text-align: center;
}

#customPupilChatImageClone {
    max-height: 10rem;
    max-width: 100%;
    object-fit: contain;
    margin-bottom: 0.5rem;
}

#chatContentContainer {
    width: -webkit-fill-available;
    width: -moz-available;
}


/* Task 2026-09-17: Zuschneide-Dialog des Gruppenbilds.
   Die Stage ist quadratisch und nimmt die kleinste der drei Grenzen: 18rem als Normalfall,
   die Fensterbreite abzueglich Rand, und 50vh -- die vh-Kappung haelt auf einem niedrigen
   Telefon-Viewport (390x667) den Footer mit den beiden Schaltflaechen erreichbar.
   touch-action: none, weil die Stage Zeiger selbst auswertet (ohne sie zoomt die Seite).
   Die Maske ist kein Designelement, sondern die Abdunklung ausserhalb des runden Ausschnitts
   -- deshalb ein rgba-Wert statt einer atlantis-Variablen. */
#cropStage {
    position: relative;
    width: min(18rem, calc(100vw - 4rem), 50vh);
    aspect-ratio: 1;
    margin: 0 auto;
    overflow: hidden;
    background-color: var(--atlantis-lightgrey);
    border-radius: 1rem;
    touch-action: none;
    cursor: grab;
}

#cropCanvas {
    display: block;
    width: 100%;
    height: 100%;
}

#cropMask {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.45);
    pointer-events: none;
}

#cropZoomRow {
    margin-top: 0.75rem;
    gap: 0.5rem;
}

/* UI-Fix 29.09.2026 (Befund 1): Die app-weite Regel `input, select, textarea, button
   { padding: 5px 1rem; }` aus design_2026.css greift auch bei <input type="range">. Der
   native Regler laesst den Knopf dann nur innerhalb der Content-Box laufen, waehrend die
   Spur ueber die ganze Border-Box gezeichnet wird -- am linken Anschlag (Wert 0) standen
   dadurch 17 px Spur links neben dem Knopf. Ohne Innenabstand deckt der Knopf den Anschlag,
   wie es der native Regler vorsieht. Der Aussenabstand (UA-Standard 2 px) entfaellt mit:
   den Abstand zu den Beschriftungen +/- setzt der gap von #cropZoomRow. */
#cropZoom {
    flex: 1 1 auto;
    accent-color: var(--atlantis-blue-text);
    margin: 0;
    padding: 0;
}

.cropZoomLabel {
    color: var(--atlantis-anthracite);
}

#cropHint {
    margin-top: 0.5rem;
    color: var(--atlantis-anthracite);
    font-size: 0.75rem;
    text-align: center;
}

/* Mindestbreite der beiden Footer-Schaltflaechen. Bewusst hier und nicht inline im Template:
   eine Inline-Deklaration liesse sich von der Mobil-Regel weiter unten (min-width: 0) nur mit
   !important ueberschreiben. */
#chatGroupImageDialog .dialogWindowFooter .ui_like_button {
    min-width: 10rem;
}

/* UI-Fix 29.09.2026 (Befund 2): {strip} im Template entfernt den Zeilenumbruch zwischen den
   beiden Schaltflaechen -- ohne gap kleben sie aneinander. Hausmuster wie
   #createTimesheetDialog/#assignAllTimesheetDialog in timekeeping_mgmt.css. Gilt auch auf
   dem Telefon: dort teilen sich beide Schaltflaechen die Zeile (flex: 1 1 auto), und
   0.75rem bleibt im Fenster von calc(100vw - 2rem) bequem drin. */
#chatGroupImageDialog .dialogWindowFooter {
    gap: 0.75rem;
}

/* --------------------------- Mobile Start --------------------------------------------- */


body.isMobile #fullMenu {
    overflow-y: scroll;
    max-height: 97vh;
}

/* ST11a (#26): Auf Mobile sitzt der Chat-Dialog UNTER der (sticky) globalen
   App-Kopfzeile statt sie zu überlappen — Offset via --mobile-header-height
   (in global.js aus #head.offsetHeight gesetzt). Gilt gleichermaßen für die
   connectivityCenter-Seite und den Header-Icon-Dialog (identische View). */
body.isMobile #msgDialog {
    top: var(--mobile-header-height, 80px);
    margin-top: 0;
    width: 100%;
    height: calc(100% - var(--mobile-header-height, 80px));
    box-sizing: border-box;
}

/* F17 (UIUX-N2): Chat auf Mobile ECHT vollflächig, solange er offen ist
   (Body-Marker mbxDialogOpen — gesetzt in afterOpenMailboxDialog, entfernt in
   hideMailboxDialog, auch auf dem Zurück-Button-Pfad, siehe mailbox.js History-
   Swap). Der Dialog rückt auf top:0 und deckt die volle Viewport ab.
   Die darunterliegenden Sticky-Header haben ein höheres z als der Dialog
   (#msgDialog z:10) und würden sonst als Streifen über der dunklen Chat-
   Titelleiste durchstechen:
     #head               (z:200, global auf allen Seiten)
     #pupilListToggleRow (z:101, "Auswahl ◀"-Umschalter auf Listen-Seiten wie stundenplan)
     #pupilTabs          (z:50,  Schüler-Tabs)
   → für die Dauer des offenen Chats ausblenden; beim Schließen kommt alles zurück.
   Der Chat hat auf Mobile eine eigene Titelleiste, #head ist also entbehrlich.
   Der Dialog-Stack wird bewusst NICHT angehoben (wie F5): die Confirms
   (jQuery-UI .ui-front z:100) liegen so weiterhin über dem Dialog (z:10).
   Rest-Grenze: eine Seite mit einer EIGENEN, anders benannten Sticky-Top-Toolbar
   (z>10) außerhalb dieser drei IDs würde weiterhin einen Streifen zeigen — auf
   den heute existierenden Seiten decken diese drei alle persistenten Top-Stickies ab.

   connectivityCenter ausgenommen: dort IST der Chat die Seite (kein Schließen-X),
   #head bleibt als einzige Navigation stehen und der Chat sitzt bewusst darunter
   (Review N2: von connectivityCenter aus bereits sauber). */
body.isMobile.mbxDialogOpen:not(#page_connectivityCenter) #msgDialog {
    top: 0;
    height: 100%;
}
body.isMobile.mbxDialogOpen:not(#page_connectivityCenter) #head,
body.isMobile.mbxDialogOpen:not(#page_connectivityCenter) #pupilListToggleRow,
body.isMobile.mbxDialogOpen:not(#page_connectivityCenter) #pupilTabs {
    display: none;
}

/* Auf connectivityCenter ist der Chat die Seite selbst, kein Dialog: das
   Schliessen-X blendet initConnectivityCenterPage aus, uebrig bliebe eine
   53px hohe Leiste mit dem blossen Wort "Chat" — waehrend #head darueber die
   Seite ohnehin schon benennt. Auf einem 412x915-Geraet gingen so 123px (13 %
   der Viewport-Hoehe) verloren, bevor der erste Listeneintrag beginnt.
   Nur mobil: auf Desktop ist der Platz da und die Leiste rahmt den Dialog. */
body#page_connectivityCenter.isMobile #msgDialog > .dialogWindow > .dialogWindowTitle {
    display: none;
}

body.isMobile #msgDialog.customDialog .dialogWindow {
    max-height: unset;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    box-sizing: border-box;
    /* Mobil fuellt das Chat-Fenster die volle Flaeche — die 1rem-Rundung der
       globalen .dialogWindow-Regel hat dann nichts mehr zu runden und legt in
       den vier Ecken den Overlay-Schleier von #msgDialog (rgba(0,0,0,0.086))
       frei. Vorher verdeckte die dunkle Titelleiste das oben; seit sie auf
       connectivityCenter entfaellt, sassen dort vier graue Flecken. */
    border-radius: 0;
}

body.isMobile #msgDialog .dialogWindow .dialogHeader:not(.dialogScrollable) {
    display: none;
}

body.isMobile #msgDialog .dialogWindow .dialogScrollable,
body.isMobile #mailboxDialogContent,
body.isMobile #chatSplitView,
body.isMobile #chatList,
body.isMobile #chatContent {
    height: 100%;
}

body.isMobile #chatList {
    width: 100%;
}

body.isMobile #chatListContainer,
body.isMobile #chatListToolbar,
body.isMobile #chatMsgContainer,
body.isMobile #msgNewChatDialog .dialogWindow,
body.isMobile #newChatFilterDialog .dialogWindow {
    width: 100%;
    box-sizing: border-box;
}

/* Listen- und Chat-Spalte liegen beide mit width: 100% im nowrap-Flex
   #chatSplitView (overflow: hidden traegt die Slide-Animation). Der Bedarf
   betraegt damit 200 % der Containerbreite, und ohne flex-shrink: 0 schrumpft
   Flexbox beide bis auf ihre min-content-Breite. Wie breit die Liste dann
   tatsaechlich rendert, haengt allein an der Textlaenge der Eintraege: bei
   langen Chatnamen liegt min-content ueber der Viewportbreite und die Spalte
   sieht zufaellig korrekt aus, bei kurzen Namen bleibt sie sichtbar zu schmal
   (min-content von #chatListToolbar) und der Zurueck-Pfeil ragt heraus. */
body.isMobile #chatListContainer,
body.isMobile #chatMsgContainer {
    flex-shrink: 0;
}

/* Mi2 fix: "Neuen Chat erstellen" auf Mobile unter die App-Kopfzeile setzen
   (statt vertikal zentriert dahinter), damit die Kopfzeile den Dialog nicht
   überlappt. Fenster behält Titelleiste, X und natürliche Höhe. */
body.isMobile #msgNewChatDialog {
    align-items: flex-start;
    /* F16 (UIUX-N1): etwas mehr Abstand nach oben, damit die Titelzeile nicht
       am oberen Rand angeschnitten wirkt. */
    padding-top: calc(var(--mobile-header-height, 80px) + 1rem);
    box-sizing: border-box;
}

/* F18 (UIUX-N3): "Neuer Chat"-Button auf Mobile einzeilig halten (bricht sonst
   zu "Neuer" / "Chat"). */
body.isMobile #newChatButtonWrapper .ui_like_button {
    white-space: nowrap;
}

/* F19: Empty-State-Box hat eine feste Breite (24rem = 384px inkl. Padding) und
   läuft auf schmalen Viewports (≤375px) horizontal über — auf Mobile die
   Spaltenbreite übernehmen. */
body.isMobile .chatListEmptyState {
    width: 100%;
    box-sizing: border-box;
}

/* ST11a (#25, 2026-06-30): Mobile — der äussere #chatSplitView-Wrapper soll
   auf einem schmalen Viewport NICHT scrollen, sondern die List- und Chat-
   Spalte exklusiv anzeigen. overflow:hidden cuts der Slide-Animation den
   Restschwanz ab, sodass die Liste nicht "links angeschnitten" sichtbar
   bleibt. */
body.isMobile #chatSplitView {
    overflow: hidden;
}

/* F20: Filter-Tabelle auf Mobile als Flex-Zeilen statt als Tabelle.

   Ausgangsproblem: .newChatFilterDisplay IST die mittlere Tabellenzelle; erst
   float: left macht daraus eine Block-Box, damit margin/border-radius greifen.
   Zusammen mit der festen Box-Breite (16rem, 249px inkl. Rahmen), der
   nowrap-Label-Spalte (120px) und der Lupe (32px) brauchte die Tabelle 424px
   Mindestbreite — in einem 384px breiten Dialoginhalt (412px Viewport) lag die
   Lupe damit ausserhalb des sichtbaren Bereichs und war auf Touch praktisch
   nicht erreichbar. Ohne Lupe ist der Dialog nicht bedienbar.

   Loesung: Tabelle und tbody werden zu Bloecken, jede Zeile zu einem
   Flex-Container. Flex-Items werden blockifiziert — die Box bleibt also eine
   Block-Box mit wirksamen Margins. (Wuerde man stattdessen nur float: none
   setzen, faellt die Zelle auf display: table-cell zurueck, Margins wirken
   nicht mehr und die Boxen kleben randlos als Gitter aneinander.)
   Label und Lupe behalten ihre Breite, die Box bekommt den Rest (flex: 1) und
   darf beliebig schmal werden (min-width: 0, zusaetzlich eigener
   Scroll-Container durch overflow-y) — die Zeile passt damit bei JEDER
   Viewport-Breite in den Dialog.

   Das nowrap der frueheren Label-Regel (F16) entfaellt: es war noetig, weil ein
   zweizeiliges Label die Lupe in der Tabellenzeile nach unten schob. Mit
   align-items: center sitzt die Lupe unabhaengig von der Label-Hoehe mittig. */
body.isMobile #newChatFilterTable,
body.isMobile #newChatFilterTable > tbody {
    display: block;
    width: 100%;
}

body.isMobile #newChatFilterTable .newChatFilterContainer,
body.isMobile #newChatFilterTable .newChatGroupNameRow {
    display: flex;
    align-items: center;
}

/* Label-Spalte: feste Breite statt Tabellenspalte — nur so bleiben die Boxen
   aller Zeilen buendig (Flex-Zeilen kennen einander nicht). 9rem traegt das
   laengste Label "Eltern einer Klasse" (120px) einzeilig. Kein min-width: 0 —
   die automatische Mindestbreite (laengstes Wort) ist hier erwuenscht: das
   Label bricht um, statt seinen Text aus der Zelle laufen zu lassen. */
body.isMobile #newChatFilterTable .newChatFilterContainer > td:first-child,
body.isMobile #newChatFilterTable .newChatGroupNameRow > td:first-child {
    flex: 0 1 9rem;
}

/* Auswahl-Box und Gruppenname-Feld bekommen den gesamten Rest der Zeile
   (flex-basis 0) und duerfen dabei beliebig schmal werden (min-width: 0).
   Genau das ersetzt die feste 16rem-Breite: statt die Zeile zu sprengen,
   schrumpft die Box mit dem Viewport. Ihr Inhalt kann sie nicht aufblaehen —
   sie ist durch overflow-y ein eigener Scroll-Container. */
body.isMobile #msgNewChatDialog .newChatFilterDisplay,
body.isMobile #newChatFilterTable .newChatGroupNameRow > td:nth-child(2) {
    flex: 1;
    min-width: 0;
}

/* float: left und width: 16rem aus der Desktop-Basisregel bleiben stehen, sind
   hier aber wirkungslos: an einem Flex-Item wird float ignoriert, und flex: 1
   (flex-basis 0) schlaegt die width. Bewusst nicht zurueckgesetzt — beides
   traegt auf Desktop weiterhin das Layout. */
body.isMobile #msgNewChatDialog .newChatFilterDisplay {
    margin: 0.75rem;
    line-height: 2.2em;
    /* muss der line-height dieser Regel folgen, siehe Basisregel */
    min-height: 2.2em;
}

/* Lupen-Spalte behaelt ihre natuerliche Breite (32px Touch-Ziel). */
body.isMobile #newChatFilterTable .newChatFilterContainer > td:last-child {
    flex: none;
}

/* Trennlinie ueber der Gruppenname-Zeile: als border-top je Zelle saesse sie
   wegen align-items: center auf unterschiedlichen Hoehen und waere
   unterbrochen — deshalb auf die Zeile selbst. */
body.isMobile #newChatFilterTable .newChatGroupNameRow {
    border-top: var(--atlantis-std-border);
    padding-top: 1rem;
}

body.isMobile #newChatFilterTable .newChatGroupNameRow > td {
    border-top: 0;
    padding-top: 0;
}

body.isMobile #newChatSelection td {
    padding: 0.75rem 0.5rem;
}

body.isMobile #chatMsgContainer {
    border-left: 0;
}

/* Die Trennlinie unter dem Chat-Header soll wie die ueber der Eingabezeile bis
   an beide Raender laufen. #chatTypingArea schafft das, weil es mobil fixed und
   volle Viewport-Breite ist; #chatHeader steht dagegen im Fluss und erbt seinen
   Einzug von .dialogScrollable (1rem je Seite) und #chatMsgContainer (0.5rem).

   Ein negativer Margin am Header allein reicht NICHT: #chatSplitView hat mobil
   overflow: hidden (fuer die Slide-Animation) und schneidet alles ab, was ueber
   seine Kante hinausragt — die Layout-Box laege bei 0..412, gezeichnet wuerde
   trotzdem nur 14..398. Deshalb faellt das seitliche Padding von
   .dialogScrollable mobil weg; den Abstand tragen die Elemente, die ihn wirklich
   brauchen (Suchzeile, Listeneintraege, Bubbles) selbst. */
body.isMobile #msgDialog > .dialogWindow > .dialogScrollable {
    padding-left: 0;
    padding-right: 0;
}

/* Auch die Spalten selbst laufen mobil bis an den Rand — den Innenabstand
   bringt jede Zeile mit (Listeneintrag 0.5rem, #chatHeader 0.5rem aus seiner
   Grundregel, Suchzeile siehe unten). So stehen Zurueck-Pfeil, Avatare der
   Listeneintraege und Suchfeld auf derselben Kante, und keine Trennlinie hoert
   vor dem Rand auf. */
body.isMobile #chatMsgContainer {
    padding-left: 0;
    padding-right: 0;
}

/* #chatListToolbar traegt nur rechts Padding (fuer den Scrollbalken der Liste
   daneben). Randbuendig gestellt fehlt links jeder Abstand, waehrend rechts
   zu viel bleibt — deshalb mobil symmetrisch auf die Kante der Listeneintraege. */
body.isMobile #chatListToolbar {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
}

body.isMobile #chatList .chatListItem {
    margin-right: unset;
}

body.isMobile #chatMsgContainer {
    padding-bottom: 0.5rem;
}

/* min-height 0: als Flex-Kind von #chatMsgContainer schrumpfte die Zeile sonst nicht unter
   ihre Inhaltshoehe. Bei langen Verlaeufen blieb sie deshalb bei 100 % - 2.5rem stehen und
   ragte um den Unterschied zum echten Chat-Header (rund 4rem) unter den Bildschirmrand. */
body.isMobile #chatPaneRow {
    height: calc(100% - 2.5rem);
    min-height: 0;
}

/* Der Nachrichtenbereich endet an der Oberkante des fixen Composers. Dessen Hoehe liefert
   syncMobileComposerHeight() (mailbox.js) als --mbx-composer-height und zieht sie nach,
   sobald die Textarea waechst oder Zitat-Leiste bzw. Erwaehnungsliste aufgehen; 4.25rem ist
   der Startwert fuer den einzeiligen Composer. So stehen neueste Nachricht und
   Anhang-Vorschau immer direkt ueber dem Composer. Frueher reichte #chatContent je nach
   Verlauf unterschiedlich weit unter ihn, ein padding-bottom in voller Composer-Hoehe liess
   dann bis zu 72 px Leerraum (User 30.09.2026) bzw. scrollIntoView die Blase darunter. */
body.isMobile #chatMessagePane {
    height: calc(100% - var(--mbx-composer-height, 4.25rem));
}

/* Kein eigener Rechts-Abstand mehr: den bringt jetzt das symmetrische Padding
   von #chatListToolbar mit. Sonst endete der "Neuer Chat"-Button 10px vor der
   rechten Kante der Datumsspalte darunter. */
body.isMobile #newChatButtonWrapper {
    margin-right: 0;
}

/* ST11a (#28, 2026-06-30): Back-Button im Mobile-Chat-Header — sichtbar
   mit hervorgehobenem runden Hintergrund (touch-Target ≥44px). */
body.isMobile #backToChatistButton {
    display: block;
    height: 2rem;
    width: 2rem;
    padding: 0.375rem;
    box-sizing: content-box;
    border-right: 0;
    margin-right: 0.5rem;
    flex: 0 0 auto;
    cursor: pointer;
}

body.isMobile #chatContentContainer {
    width: 100%;
    box-sizing: border-box;
}

body.isMobile #chatGroupInfo {
    width: 0vw;
    margin-top: 1rem;
    border-right: 0;
}

body.isMobile .chatGroupParticipantsContainer,
body.isMobile .chatGroupParticipants>div {
    margin-top: 1rem;
}

body.isMobile #addParticipantButton,
body.isMobile .chatGroupAdminIcon,
body.isMobile .chatGroupNoAdminIcon,
body.isMobile .chatGroupCommentingAllowedIcon,
body.isMobile .chatGroupCommentingDisallowedIcon,
body.isMobile .removeParticipantIcon,
body.isMobile .placeholderIcon {
    margin-right: 1.25rem;
}

/* Task 2026-09-17: Zuschneide-Dialog auf dem Telefon. Das Fenster nimmt die Breite bis auf
   einen Rand von je 1rem; die beiden Footer-Schaltflaechen teilen sich die Zeile, statt mit
   ihrer Mindestbreite aus dem Fenster zu laufen. */
body.isMobile #chatGroupImageDialog .dialogWindow {
    width: calc(100vw - 2rem);
}

body.isMobile #chatGroupImageDialog .dialogWindowFooter .ui_like_button {
    flex: 1 1 auto;
    min-width: 0;
}


/* --------------------------- Mobile End ----------------------------------------------- */
