/* ===================================================================
 * Gemeinsame Bausteine für alle drei Oberflächen.
 *
 * Hier steht, was auf Desktop, Android und iOS gleich aussehen MUSS:
 * Marker, Statusfarben, Einheitenliste, Alarmleiste. Was sich je
 * Plattform unterscheidet, steht in desktop.css, android.css, ios.css —
 * und nicht als Sonderfall hier.
 * =================================================================== */

* { box-sizing: border-box; }

/* HIDDEN HEISST HIDDEN.
 *
 * Das Attribut `hidden` bekommt sein `display: none` nur aus dem
 * Vorgabestylesheet des Browsers — und das verliert gegen JEDE eigene
 * Regel mit einem `display`. Sobald ein Element eine Klasse wie `.field`
 * (display: flex) oder `.button` (display: inline-flex) trägt, ist es
 * sichtbar, obwohl im HTML `hidden` steht.
 *
 * Gefunden auf dem Testgerät am 16.08.2026: In der Anmeldemaske standen
 * die Fahrzeugtyp-Auswahl und der Knopf „Einsatz eröffnen" von Anfang an
 * da, obwohl beide als `hidden` ausgeliefert wurden. Im Quelltext sah
 * alles richtig aus; erst der Bildschirm hat es gezeigt.
 *
 * Deshalb einmal zentral und mit !important — sonst wiederholt sich das
 * bei jeder neuen Komponente, die ein `display` setzt.
 */
[hidden] { display: none !important; }

html, body {
    margin: 0;
    min-height: 100%;
    background: var(--bg);
    color: var(--text);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    -webkit-text-size-adjust: 100%;
}

/* Kein Doppeltippen-Zoom und keine Textauswahl beim Halten: Beides
   stört an einem Gerät, das im Einsatz mit nassen Fingern bedient wird. */
body.is-touch {
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
    overscroll-behavior: none;
}

h1, h2, h3 { margin: 0; font-weight: 700; line-height: 1.2; }
p { margin: 0; line-height: 1.5; }

.muted { color: var(--text-muted); }
.visually-hidden {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* --- Symbole -------------------------------------------------------- */

.icon {
    width: 1.25em;
    height: 1.25em;
    flex: none;
    fill: none;
    stroke: none;
    color: inherit;
}

.icon-lg { width: 1.75em; height: 1.75em; }

/* --- Knöpfe ---------------------------------------------------------
 *
 * Mindestens --touch-min hoch. Das ist kein Gestaltungswunsch: Am
 * 12.08.2026 waren drei unabhängig gemeldete Fehler in Wahrheit einer —
 * Bedienelemente, die von der Alarmleiste verdeckt wurden. Seither prüft
 * eine Probe für jedes Element, ob elementFromPoint auf seine Mitte auch
 * wirklich dieses Element liefert.
 * ------------------------------------------------------------------- */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: var(--touch-min);
    padding: 0 1.1rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    color: var(--text);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.button:active { transform: translateY(1px); }
.button:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.button[disabled] { opacity: 0.5; cursor: not-allowed; }

.button-primary {
    background: var(--accent);
    border-color: var(--accent-strong);
    color: #fff;
}

.button-danger {
    background: var(--status-alarm);
    border-color: var(--status-alarm);
    color: #fff;
}

.button-ghost { background: transparent; }

.button-icon {
    min-width: var(--touch-min);
    padding: 0;
}

/* --- Flächen -------------------------------------------------------- */

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}

/* Die Zähler SIND der Filter. Deshalb sind es Knöpfe und keine
   Beschriftungen — eine Zahl, die etwas benennt, das man dann nicht
   aufrufen kann, ist eine Sackgasse. */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.25rem 0.6rem;
    border: 1px solid transparent;
    border-radius: 999px;
    background: var(--status-soft, var(--surface-sunken));
    color: var(--status, var(--text-muted));
    font: inherit;
    font-size: 0.8rem;
    font-weight: 700;
}

button.pill { cursor: pointer; -webkit-tap-highlight-color: transparent; }
button.pill[aria-pressed="true"] { border-color: var(--status, var(--accent)); }
button.pill:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* --- Karte ---------------------------------------------------------- */

.map {
    width: 100%;
    height: 100%;
    background: var(--bg-deep);
}

.leaflet-container { background: var(--bg-deep); font: inherit; }
.leaflet-control-attribution { display: none; }

/* Nachtschema: Die Straßenkarte ist für Tageslicht gezeichnet. Ein
   Filter ist kein schöner Weg, aber der einzige ohne eigenen Kartensatz —
   und ein blendend weißer Bildschirm im dunklen Fahrzeug ist schlechter
   als eine leicht flaue Karte. Das Luftbild bleibt unangetastet: Dort
   wäre eine Umkehrung sinnlos. */
[data-scheme="night"] .leaflet-tile-pane .tiles-map {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.94) saturate(0.7);
}

/* --- Marker ---------------------------------------------------------
 *
 * DIE ARTFARBE IST DIE FLÄCHE, NICHT EIN DETAIL.
 *
 * Sie folgt dem, was am Einsatzort leuchtet: gelbe Warnweste beim
 * Einsatzleiter, rotes Blinklicht bei der Einsatzleitung, Blaulicht am
 * Fahrzeug, weiß bei der Mannschaft. Wer vom Bildschirm aufsieht, findet
 * dieselbe Farbe wieder.
 *
 * Bis Fassung 0.9.2 zeigte der RAHMEN den Zustand und die Artfarbe nur
 * das Zeichen darin. Damit war das Auffällige der Zustand und die
 * Identität ein Detail — verkehrt herum. Die Vorgabe lautet „immer gelb",
 * nicht „gelb, solange nichts los ist". Der Zustand sitzt jetzt auf einem
 * kleinen Punkt an der Ecke: weiterhin da, aber nicht mehr im Weg.
 *
 * Ausgenommen ist der Notruf. Der darf alles überschreiben.
 * ------------------------------------------------------------------- */

.unit-marker {
    position: relative;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    margin: -19px 0 0 -19px;
    border-radius: 12px;
    /* Der Rand trennt das Plättchen von der Karte — nötig, weil ein
       weißes Plättchen sonst in einem Schneefeld verschwindet und ein
       dunkles nachts im Wald. */
    border: 2px solid var(--marker-edge);
    background: var(--unit-color, var(--accent));
    color: var(--unit-ink, #fff);
    box-shadow: var(--shadow-sharp);
}

.unit-marker .icon { width: 22px; height: 22px; }

/* Fahrzeuge sind breiter als hoch — das Grundzeichen ist ein liegendes
   Rechteck, und ein quadratischer Rahmen darum sähe aus wie ein Fehler. */
.unit-marker[data-vehicle="1"] {
    width: 50px;
    height: 34px;
    margin: -17px 0 0 -25px;
    border-radius: 8px;
}

.unit-marker[data-vehicle="1"] .icon { width: 34px; height: 21px; }

/* Der Zustandspunkt. Nicht gezeichnet, solange alles in Ordnung ist:
   Ein Punkt, der immer da ist, sagt nichts. */
.unit-marker::after {
    content: "";
    position: absolute;
    top: -4px;
    right: -4px;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--status, var(--status-offline));
    border: 2px solid var(--marker-edge);
}

.unit-marker[data-status="active"]::after { display: none; }

.unit-marker[data-status="alarm"] { animation: marker-alarm 0.9s steps(1) infinite; }
.unit-marker[data-status="alarm"]::after { display: none; }

@keyframes marker-alarm {
    0%, 49% {
        background: var(--status-alarm);
        color: #fff;
        border-color: #fff;
    }
    50%, 100% {
        background: #fff;
        color: var(--status-alarm);
        border-color: var(--status-alarm);
    }
}

/* Ohne Animation muss der Notruf trotzdem herausstechen — und zwar
   anders als jede ruhige Art, auch anders als die rote Einsatzleitung. */
@media (prefers-reduced-motion: reduce) {
    .unit-marker[data-status="alarm"] {
        animation: none;
        background: var(--status-alarm);
        color: #fff;
        border: 4px solid #fff;
        outline: 3px solid var(--status-alarm);
    }
}

/*
 * Das Schild hängt am MARKERPUNKT, nicht am Textfluss.
 *
 * Vorher stand es ohne `top` da und landete über seine statische Lage
 * unter dem Markerkasten — wo genau, hing davon ab, wie hoch der Kasten
 * gerade war. Die Verschiebung in spreadLabels rechnet aber vom
 * Markerpunkt aus; beides stimmte nur zufällig überein, und bei
 * Fahrzeugen (34 statt 38 Pixel hoch) schon nicht mehr.
 *
 * Jetzt liegt der Nullpunkt auf dem Marker, und die Verschiebung setzt
 * das Schild von dort aus — gerechnete und gezeichnete Lage sind
 * dieselbe.
 */
.unit-label {
    position: absolute;
    left: 0;
    top: 0;
    transform: translate(-50%, -50%) translate(0, 27px);
    padding: 1px 6px;
    border-radius: 6px;
    background: var(--surface-raised);
    border: 1px solid var(--line);
    color: var(--text);
    font-size: 0.72rem;
    font-weight: 700;
    white-space: nowrap;
    pointer-events: none;
}

.unit-marker-wrapper { background: none; border: 0; }

/* --- Einheitenliste -------------------------------------------------- */

.unit-list { display: flex; flex-direction: column; gap: 0.5rem; }

.unit-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: var(--touch-min);
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--line);
    border-left: 5px solid var(--status, var(--status-offline));
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.unit-row[aria-pressed="true"] { outline: 2px solid var(--focus); outline-offset: -2px; }

/* Dasselbe Plättchen wie auf der Karte, nur kleiner. Wer in der Liste
   das gelbe Zeichen sucht, findet es auf der Karte wieder — und nicht
   dort gelb und hier nur ein gelber Strich. */
.unit-row .unit-badge {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    border: 2px solid var(--marker-edge);
    background: var(--unit-color, var(--accent));
    color: var(--unit-ink, #fff);
}

.unit-row .unit-badge .icon { width: 18px; height: 18px; }
.unit-row[data-vehicle="1"] .unit-badge { width: 38px; border-radius: 7px; }
.unit-row[data-vehicle="1"] .unit-badge .icon { width: 26px; height: 16px; }

.unit-row[data-status="alarm"] .unit-badge {
    background: var(--status-alarm);
    color: #fff;
    animation: badge-alarm 0.9s steps(1) infinite;
}

@keyframes badge-alarm {
    0%, 49% { background: var(--status-alarm); color: #fff; }
    50%, 100% { background: #fff; color: var(--status-alarm); }
}

@media (prefers-reduced-motion: reduce) {
    .unit-row[data-status="alarm"] .unit-badge { animation: none; }
}

/* Name und Zusatz sind ZWEI Zeilen. Als Inline-Elemente klebten sie
   aneinander — „ELtgKein Kontakt · 21 min" —, weil zwischen zwei
   benachbarten Spans kein Leerraum steht. */
.unit-row .unit-text { display: flex; flex-direction: column; min-width: 0; }
.unit-row .unit-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Die eigene Einheit steht mit in der Liste — sie fehlte dort, während
   die Zähler oben sie mitzählten. Wer sich selbst nicht findet, sucht
   den Fehler zuerst bei der eigenen Anmeldung. */
.unit-row .unit-self {
    margin-left: 0.4rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background: var(--accent-soft);
    color: var(--accent-strong);
    font-size: 0.68rem;
    font-weight: 700;
    vertical-align: 1px;
}

[data-scheme="night"] .unit-row .unit-self { color: var(--accent); }
.unit-row .unit-meta { font-size: 0.8rem; color: var(--text-muted); }
.unit-row .unit-range { font-variant-numeric: tabular-nums; font-weight: 700; text-align: right; }

/* --- Alarmleiste -----------------------------------------------------
 *
 * Bewusst aufdringlich: In der Einsatzleitung darf der Alarm nicht davon
 * abhängen, dass gerade jemand hinsieht.
 *
 * Ihr HTML wird NICHT bei jedem Durchlauf neu gesetzt. Genau das hat am
 * Handy dazu geführt, dass das Element unter dem Finger zwischen
 * pointerdown und click zerstört wurde — am Rechner mit der Maus liegen
 * wenige Millisekunden dazwischen, am Handy dauert ein Tipper länger.
 * ------------------------------------------------------------------- */

.alarm-bar {
    position: sticky;
    top: 0;
    z-index: 900;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem calc(0.75rem + var(--safe-right)) 0.6rem calc(0.75rem + var(--safe-left));
    background: var(--status-alarm);
    color: #fff;
    font-weight: 700;
}

.alarm-bar[hidden] { display: none; }
.alarm-bar .button { background: rgba(0, 0, 0, 0.25); border-color: rgba(255, 255, 255, 0.5); color: #fff; }
/* Ein Tipp auf die Leiste führt zur alarmierenden Einheit. */
.alarm-bar-text { flex: 1; min-width: 0; cursor: pointer; }

/* Jeder Name ist für sich anklickbar und führt zu SEINER Einheit. Bei
   zwei Notrufen landete ein Tipp auf die Leiste sonst immer bei
   derselben, und die zweite war von hier aus nicht erreichbar. Sieht aus
   wie Text, ist aber ein Knopf — auch für die Tastatur. */
.alarm-unit {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.alarm-unit:hover { text-decoration-thickness: 2px; }
.alarm-unit:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.alarm-sep, .alarm-tail { white-space: pre; }

/* --- Verbindungshinweis ---------------------------------------------- */

.connection-note {
    position: fixed;
    left: 50%;
    bottom: calc(1rem + var(--safe-bottom));
    transform: translateX(-50%);
    z-index: 950;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.9rem;
    border-radius: 999px;
    background: var(--surface-raised);
    border: 1px solid var(--line-strong);
    box-shadow: var(--shadow);
    font-size: 0.85rem;
    font-weight: 600;
}

.connection-note[hidden] { display: none; }

/* --- Anmeldung -------------------------------------------------------- */

.sheet {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: grid;
    place-items: center;
    padding: 1rem;
    background: rgba(4, 7, 12, 0.72);
    backdrop-filter: blur(3px);
}

.sheet[hidden] { display: none; }

.sheet-card {
    width: min(30rem, 100%);
    /* dvh statt vh: Auf dem Handy ist vh die Höhe OHNE eingeblendete
       Browserleisten - die Karte wäre damit höher als der sichtbare
       Bereich, und die unterste Zeile läge unter der Kante. */
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    /* Die festgeheftete Knopfleiste liegt ÜBER dem Rollbereich.
       scrollIntoView() weiß nichts davon und schiebt ein Feld genau
       darunter — auf dem Testgerät stand die Beschriftung
       „Fahrzeugtyp" da, die Auswahl selbst lag hinter „Anmelden".
       scroll-padding sagt dem Browser, wie viel unten belegt ist. */
    scroll-padding-bottom: 6rem;
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}

/* Die Knöpfe bleiben am unteren Rand der Karte stehen, auch wenn die
   Liste darüber scrollt. Sonst muss man erst suchen, wo „Anmelden" ist —
   und im Einsatz sucht niemand. */
.sheet-actions {
    position: sticky;
    bottom: -1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0 -1.25rem -1.25rem;
    padding: 0.75rem 1.25rem 1.25rem;
    background: var(--surface);
    box-shadow: 0 -12px 16px -12px rgba(0, 0, 0, 0.5);
}

.field { display: flex; flex-direction: column; gap: 0.35rem; }
.field label { font-size: 0.85rem; font-weight: 700; color: var(--text-muted); }

.input, .select {
    min-height: var(--touch-min);
    padding: 0 0.9rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    color: var(--text);
    font: inherit;
}

.choice-list { display: flex; flex-direction: column; gap: 0.5rem; border: 0; margin: 0; padding: 0; }

.choice {
    display: grid;
    grid-template-columns: auto auto minmax(0, 1fr);
    align-items: center;
    gap: 0.75rem;
    min-height: var(--touch-min);
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    cursor: pointer;
}

.choice:has(input:checked) { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.choice input { width: 1.2rem; height: 1.2rem; accent-color: var(--accent); }
.choice .choice-symbol { color: var(--unit-color, var(--accent)); }
.choice strong { display: block; }
.choice small { color: var(--text-muted); }

.notice { padding: 0.6rem 0.75rem; border-radius: var(--radius-md); background: var(--status-soft); color: var(--status); font-weight: 600; }
.notice[hidden] { display: none; }
.notice-error { --status: var(--status-alarm); --status-soft: var(--status-alarm-soft); }

/* --- Einstieg weitergeben --------------------------------------------
 *
 * Das Blatt steht auf allen drei Oberflächen (partials/qr.php). Der Code
 * bekommt die Breite, die da ist, hört aber bei 20 rem auf: Ein
 * QR-Code, der über den Bildschirm hinausragt, lässt sich nicht
 * abscannen, weil die Kamera das ganze Quadrat sehen muss.
 * ------------------------------------------------------------------- */

.qr-card { text-align: center; }

.qr-card #qrImage {
    display: flex;
    justify-content: center;
    margin: 0.75rem 0;
}

/* Weiß hinterlegt, auch im Nachtschema: Ein QR-Code wird dunkel auf
   hell gelesen. Auf dunklem Grund scheitern viele Kameras. */
.qr-card #qrImage svg {
    width: min(72vw, 20rem);
    height: auto;
    background: #fff;
    padding: 0.6rem;
    border-radius: 0.5rem;
}

.qr-card #qrUrl {
    display: block;
    word-break: break-all;
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 0.9rem;
}

.qr-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* Teilen ist der Regelfall und bekommt die ganze Zeile; Kopieren und
   Schließen teilen sich die zweite. Am Handy zählt der Daumen. */
.qr-actions #qrShare { flex: 1 0 100%; justify-content: center; }
.qr-actions #qrCopy,
.qr-actions #qrClose { flex: 1; justify-content: center; }

#qrHint { margin-top: 0.6rem; font-size: 0.85rem; }

/* --- Auffächern im Gedränge ------------------------------------------
 *
 * Vier Fahrzeuge im Rüsthaus stehen auf demselben Fleck. Übereinander
 * gestapelt sieht man eines und ahnt drei. Das Entzerren in app.js
 * schiebt die Plättchen auseinander; diese beiden Elemente sagen, wo
 * die Einheit WIRKLICH steht.
 * ------------------------------------------------------------------- */

.unit-anchor,
.unit-leader {
    position: absolute;
    left: 0;
    top: 0;
    pointer-events: none;
}

/* Der echte Standort: ein kleiner Punkt, der immer da ist. */
.unit-anchor {
    width: 6px;
    height: 6px;
    margin: -3px 0 0 -3px;
    border-radius: 50%;
    background: var(--unit-color, var(--accent));
    box-shadow: 0 0 0 1.5px var(--marker-edge);
}

/* Die Fahne dorthin. Breite und Winkel setzt app.js; ohne Verschiebung
   ist die Breite 0 und die Linie damit unsichtbar. */
.unit-leader {
    width: 0;
    height: 2px;
    margin-top: -1px;
    transform-origin: 0 50%;
    background: var(--unit-color, var(--accent));
    opacity: 0.55;
}

/* Das Plättchen wandert; die Bewegung soll man sehen, aber nicht
   abwarten müssen. */
.unit-marker { transition: transform 140ms ease-out; }

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

/* --- Fassung in der Kartenecke ---------------------------------------
 *
 * Klein, blass, unten rechts — und ohne Anspruch auf Aufmerksamkeit.
 * Sie beantwortet genau eine Frage, die im Einsatz sonst über
 * Einstellungen → Apps → Details geht: „Welcher Stand läuft auf DIESEM
 * Gerät?" Bei vier Tablets und einem Handy ist das keine Kleinigkeit —
 * am 17.08.2026 lief eines zwei Fassungen hinterher, ohne dass man es
 * ihm ansah.
 * ------------------------------------------------------------------- */

.app-map, .desk-map { position: relative; }

.map-version {
    position: absolute;
    right: 0.5rem;
    bottom: 0.35rem;
    z-index: 450;
    padding: 0.1rem 0.35rem;
    border-radius: 0.35rem;
    background: var(--surface);
    color: var(--text-muted);
    font-size: 0.66rem;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    opacity: 0.45;
    pointer-events: none;
    user-select: none;
}

/* Die Einsatz-PIN auf dem QR-Blatt: zum Vorlesen, nicht zum Suchen. */
.qr-code-hint { margin-top: 0.2rem; font-size: 0.8rem; }

.qr-code {
    margin: 0.1rem 0 0.6rem;
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: 0.3em;
    font-variant-numeric: tabular-nums;
    /* Der Buchstabenabstand schiebt optisch nach rechts; das holt es
       zurück, damit die Ziffern mittig unter dem Code stehen. */
    text-indent: 0.3em;
}

/* Ein Knopf, der aussieht wie ein Verweis.
 *
 * „Zurücksetzen" neben dem gemerkten Namen ist keine Navigation — es
 * passiert etwas, also ein <button>. Aussehen darf er trotzdem wie ein
 * Verweis: Er steht mitten im Satz, und ein Kasten dort wäre lauter als
 * das, was er tut. */
.link-button {
    background: none;
    border: 0;
    padding: 0.25rem 0.15rem;
    margin: 0;
    font: inherit;
    color: var(--accent);
    text-decoration: underline;
    cursor: pointer;
    min-height: 1.75rem;
}

.link-button:hover,
.link-button:focus-visible { color: var(--text); }

.join-hint { margin: 0.35rem 0 0; font-size: 0.88rem; }
