/* =============================================================================
   app.css — Geteilte UI-Bausteine (früher pro Seite dupliziert)
   Wird in allen Layouts NACH bootstrap.min.css geladen.
   ============================================================================= */

/* Footer-Abschwächung (dunkler Footer) */
.text-white-80 { color: rgba(255, 255, 255, 0.8) !important; }

/* Sanftes Pulsieren für "offen/live"-Status-Indikatoren */
.animate-pulse { animation: pulse-op 2s infinite; }
@keyframes pulse-op {
    0%   { opacity: 1; }
    50%  { opacity: 0.4; }
    100% { opacity: 1; }
}

/* Gedämpfte Statusfarben (einheitlich, früher je Seite neu definiert)

   Die Vordergrundfarben sind auf WCAG AA abgedunkelt (Kontrast ≥ 4,5:1 gegen den
   jeweiligen Hintergrund). Vorher lagen vier der fünf Paare darunter — gemessen
   3,94:1 (primary), 4,03:1 (success), 4,18:1 (secondary) und 4,31:1 (warning).
   Das ist keine Kleinigkeit: Die Farben tragen Statusbadges in 0,75 rem, also
   kleinen Text, und stehen in Kurslisten und Protokollen genau dort, wo man im
   Vorbeigehen etwas erkennen können muss.

   Die Hintergründe blieben unverändert — nur die Schrift wurde dunkler, der
   Farbeindruck bleibt derselbe.

   Belegt von tests/Feature/Ui/ContrastPaletteTest.php (Sollwerte dort fest
   hinterlegt, damit der Test bei einer Änderung auffällt statt mitzuwandern). */
.bg-success-subtle   { background-color: #e8f5e9 !important; color: #157347 !important; } /* 5,22:1 */
.bg-warning-subtle   { background-color: #fff8e1 !important; color: #8a6100 !important; } /* 5,21:1 */
.bg-secondary-subtle { background-color: #f0f2f5 !important; color: #5c636a !important; } /* 5,43:1 */
.bg-primary-subtle   { background-color: #e3f2fd !important; color: #0a58ca !important; } /* 5,64:1 */
.bg-info-subtle      { background-color: #e0f7fa !important; color: #066474 !important; } /* 6,12:1 */
/* danger fehlte hier bislang ganz — die Badges „Gesperrt", „Fehler" und
   „Administrator" liefen deshalb mit Bootstraps eigenem Paar und kamen auf 3,39:1.
   Nachgemessen vom Browser-Sweep (Regel kontrast-zu-gering in e2e/util.ts). */
.bg-danger-subtle    { background-color: #fdecee !important; color: #9b1c23 !important; } /* 7,12:1 */

/* Bootstraps .btn-outline-warning trägt Schrift und Rahmen in #ffc107 — auf Weiß sind das
   1,63:1, gemessen vom Browser-Sweep am „2FA zurücksetzen"-Knopf in der Benutzerverwaltung.
   Für einen Bedienknopf verlangt WCAG 3:1, für seine 14-px-Beschriftung 4,5:1.

   Dieselbe gehärtete Warnfarbe wie in .bg-warning-subtle oben: #8a6100 erreicht auf Weiß
   5,54:1. Gesetzt über Bootstraps eigene Button-Variablen statt per !important — sonst
   überschriebe die Regel auch den Hover-Zustand, in dem die Fläche gelb wird und die Schrift
   laut Bootstrap schwarz sein muss (mit #8a6100 darauf wären es nur 3,57:1). */
.btn-outline-warning {
    --bs-btn-color: #8a6100;
    --bs-btn-border-color: #8a6100;
    --bs-btn-hover-border-color: #8a6100;
}

/* Knopf mit laufendem Spinner. Gesetzt von public/js/absende-riegel.js beim Absenden.

   WARUM EINE KLASSE UND NICHT `disabled`: Der sichtbare Zustand muss SYNCHRON gesetzt
   werden, noch vor dem Startschuss der Navigation — WebKit malt danach kein Bild mehr (die
   Messung dazu steht im Kopf von absende-riegel.js). Ein `disabled` an dieser Stelle nähme
   dem Formular aber name/value des Auslösers. Die Klasse sperrt deshalb nur die Bedienung;
   das echte `disabled` folgt einen Tick später, wenn die Formdaten eingesammelt sind.

   Aussehen wie Bootstraps :disabled, damit der Übergang zwischen beiden Zuständen nicht zu
   sehen ist. Steht in app.css, weil das ein allgemeiner Knopf-Zustand ist und kein Signup-Aussehen —
   und weil jedes Layout der Anwendung diese Datei lädt. */
.btn-busy {
    pointer-events: none;
    opacity: var(--bs-btn-disabled-opacity, 0.65);
}

/* =============================================================================
   Kompakte Eingabefelder OHNE die iOS-Zoom-Falle
   Ersatz für .form-control-sm auf echten Eingabefeldern.

   iOS Safari zoomt beim Fokus in jedes Feld hinein, dessen Schriftgröße unter
   16 px liegt, und lässt die Seite danach verschoben stehen — der Anwender
   tippt weiter und sieht die Hälfte des Formulars nicht mehr. Abschalten lässt
   sich das nicht: user-scalable=no ignoriert iOS seit Version 10 aus
   Barrierefreiheitsgründen, zu Recht.

   .form-control-sm setzt font-size auf 0.875rem (14 px) und tappt damit genau
   in diese Falle. Hier bleibt die knappe Innenabstands-Optik erhalten, die
   Schriftgröße aber auf dem Standardwert. Für Knöpfe ist .btn-sm weiterhin
   richtig — die bekommen keinen Fokus-Zoom.

   Belegt von e2e/layout.spec.ts (Regel 'eingabefeld-zoomt-ios').
   ============================================================================= */
.form-control-kompakt {
    padding: 0.25rem 0.5rem;
    border-radius: var(--bs-border-radius-sm, 0.25rem);
}

/* .input-group-sm stellt DIESELBE Falle, nur eine Etage höher: Bootstrap setzt die
   Schriftgröße nicht am Feld, sondern über den Container an allem, was darin liegt. Wer
   `input-group-sm` schreibt, sieht seinem Markup deshalb nicht an, dass er sich 14-px-Felder
   einhandelt — `.form-control-kompakt` am Feld hilft dort nicht, weil die Container-Regel
   gewinnt.

   Gefunden am 2026-09-09 im Dokumentgestalter: 22 Zahlenfelder für Maße in Zentimetern, alle
   auf 14 px, alle mit demselben Fokus-Zoom. Sie entstehen im Skript und tragen im Markup nur
   `form-control` — in der Blade-Datei war nichts zu sehen.

   Global und nicht als Opt-in, weil `input-group-sm` im ganzen Projekt ausschließlich dort
   vorkommt (nachgezählt: 9 Stellen, alle im Gestalter). Die Regel ändert damit heute nichts
   anderes und nimmt die Falle für jeden weg, der später danach greift. Der knappe Innenabstand
   von Bootstrap bleibt; nur die Schriftgröße geht auf den Normalwert zurück.

   `.input-group-text` ist bewusst NICHT dabei: Ein Anhang wie „cm" bekommt keinen Fokus und
   löst deshalb auch keinen Zoom aus. */
.input-group-sm > .form-control,
.input-group-sm > .form-select {
    font-size: 1rem;
}

/* =============================================================================
   Tap-Fläche für textlose Bedienelemente
   Ein Symbol ohne Beschriftung muss von sich aus groß genug sein — bei einem
   Knopf mit Text hilft notfalls die Wortfläche, hier gibt es nichts anderes zu
   treffen. Die Grenze liegt bei 32×32 px; das ist bewusst weniger als Apples
   empfohlene 44 px, weil Bootstraps eigener .btn nur 38 px hoch ist und eine
   44er-Regel jeden Knopf der Anwendung beträfe (nachgemessen: 41–74 Treffer je
   Seite — ein Gate, das niemand befolgt).

   Der Innenabstand bleibt beim Aufrufer; hier steht nur die Mindestgröße samt
   Zentrierung, damit das Symbol nicht in der Ecke klebt.

   Belegt von e2e/taptargets.spec.ts.
   ============================================================================= */
.tap-ziel {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    min-height: 32px;
}

/* Seitenlinks der Blätterleiste (Bootstrap-Pagination: Admin-Protokoll, Mail-Protokoll,
   Support im Backoffice). Eine einstellige Seitenzahl ergab 31 × 38 px — unter der 32-px-Regel
   oben. Aufgefallen am 2026-10-14, als die E2E-Mandanten zum ersten Mal mehr als 50
   Protokolleinträge hatten (ActivityLogController::paginate(50)): Vorher hatte der Sweep nie
   eine Blätterleiste gesehen, ein echter Mandant dagegen hat sie im Normalfall. */
.page-link {
    min-width: 38px;
    text-align: center;
}

/* =============================================================================
   Responsive Datentabelle
   CSS-Grid, das UNTER dem lg-Breakpoint (992px) zu beschrifteten Karten
   zusammenklappt. Jede Tabelle setzt ihre Spalten über --rtable-cols auf dem
   Container (.rtable). So bleiben Datenlisten bis inkl. iPad-Portrait als Karten
   bedienbar und werden erst ab ≥992px zur echten Tabelle.
   ============================================================================= */
.rtable-row {
    display: grid;
    grid-template-columns: 1fr;   /* mobil: eine Spalte = Karte */
    gap: 12px;
    padding: 16px;
    border-bottom: 1px solid #edf2f7;
}
.rtable-row:last-child { border-bottom: 0; }

/* Grid-Kinder haben von Haus aus min-width:auto: eine lange E-Mail-Adresse
   würde ihre Spalte über den fr-Anteil hinaus aufblähen und damit alle
   folgenden Spalten dieser Zeile verschieben — die Spalten stünden dann nicht
   mehr untereinander. min-width:0 hält jede Spur exakt auf ihrer Sollbreite;
   overflow-wrap sorgt dafür, dass überlange Wörter dann umbrechen statt in die
   Nachbarspalte zu laufen. */
.rtable-row > * {
    min-width: 0;
    overflow-wrap: break-word;
}

.rtable-head {
    font-size: 0.75rem;
    text-transform: uppercase;
    color: #6c757d;
    font-weight: 600;
    border-bottom: 1px solid #edf2f7;
}

.rtable-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: #6c757d;
    margin-bottom: 2px;
}

@media (min-width: 992px) {
    .rtable-row {
        grid-template-columns: var(--rtable-cols, 1fr);
        align-items: center;
        padding: 12px 16px;
    }
    .rtable-row.rtable-hover:hover { background-color: #f8fafc; }
}

/* Variante .rtable-xl: für breite Tabellen (viele Spalten + Aktionsbuttons),
   die auf 992–1199px nur gequetscht aussähen. Sie bleiben dort im Kartenlayout
   und werden erst ab 1200px zur Tabelle. Das Markup nutzt dafür die
   xl-Varianten der Bootstrap-Utilities (d-xl-none, text-xl-center …) statt der
   lg-Varianten — für Kopfzeile, Feldlabels und Aktionen. */
@media (min-width: 992px) and (max-width: 1199.98px) {
    .rtable-xl .rtable-row {
        grid-template-columns: 1fr;
        align-items: stretch;
        padding: 16px;
    }
}

/* =============================================================================
   Mobiles Bottom-Sheet-Dropdown (Aktionsmenüs auf dem Handy)
   Früher identisch in dashboard.blade.php UND courses/list.blade.php dupliziert.
   Verhalten (max-width: 767px): das Dropdown fährt als Sheet von unten ein.
   Auf Tablet/Desktop rendert dasselbe Markup als normales Bootstrap-Dropdown.
   Gesteuert von public/res/customjs.js.
   ============================================================================= */
@media (max-width: 767px) {
    .mobile-dropdown {
        position: fixed !important;
        bottom: 0 !important;
        top: auto !important;
        left: 0 !important;
        right: 0 !important;
        transform: translateY(100%) !important;
        transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
        border-radius: 16px 16px 0 0 !important;
        width: 100% !important;
        margin: 0 !important;
        padding: 10px 0 25px 0 !important; /* Platz für iOS Home-Bar */
        background-color: #fff !important;
        box-shadow: 0 -5px 25px rgba(0, 0, 0, 0.15) !important;
        z-index: 1060;
        display: block !important;
        visibility: hidden;
        max-height: 85vh;
        overflow-y: auto;
    }
    .mobile-dropdown.show {
        transform: translateY(0) !important;
        visibility: visible;
    }
    .mobile-dropdown .dropdown-item {
        padding: 14px 20px;
        font-size: 1rem;
    }
    .mobile-dropdown-backdrop {
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.4);
        opacity: 0;
        transition: opacity 0.2s ease;
        z-index: 1055; /* muss unter 1060 (aktive Zeile) liegen */
    }
    .mobile-dropdown-backdrop.show { opacity: 1; }
}

/* =============================================================================
   Scroll-Affordanz für scrollbare Modals (.modal-dialog-scrollable)
   Weicher Schatten am Footer + Fade mit Chevron am unteren Body-Rand, solange
   darunter noch Inhalt liegt. Die Klasse .modal-has-more wird per JS in
   customjs.js gesetzt/entfernt (auch bei dynamisch wachsendem Inhalt); das
   .modal-scroll-hint-Element wird dort in den Footer injiziert und ragt absolut
   über dessen Oberkante hinaus.
   ============================================================================= */
.modal-content.modal-has-more > .modal-footer,
.modal-content.modal-has-more > form > .modal-footer {
    box-shadow: 0 -0.6rem 0.75rem -0.5rem rgba(0, 0, 0, 0.18);
}
.modal-dialog-scrollable .modal-footer { position: relative; }
.modal-scroll-hint {
    position: absolute;
    bottom: 100%;
    left: 0;
    right: 0;
    height: 2.75rem;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 0.1rem;
    background: linear-gradient(to top, #fff 15%, rgba(255, 255, 255, 0));
    color: var(--bs-primary, #0d6efd);
    font-size: 1.05rem;
    pointer-events: none;        /* Felder unter dem Fade bleiben bedienbar */
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 4;
}
.modal-content.modal-has-more .modal-scroll-hint { opacity: 1; }
.modal-scroll-hint .bi { animation: modal-scroll-hint-bounce 1.6s ease-in-out infinite; }
@keyframes modal-scroll-hint-bounce {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(3px); }
}
@media (prefers-reduced-motion: reduce) {
    .modal-scroll-hint .bi { animation: none; }
}

/* =============================================================================
   Einstellungs-Übersicht (der Hub unter /admin/settings)

   Aufbau und Klassennamen sind absichtlich dieselben wie im ERP (dort in
   public/css/theme.css). Beide Anwendungen stehen beim selben Kunden auf demselben
   Bildschirm; wer die eine bedienen kann, soll die andere nicht neu lernen müssen.

   Die Werte sind hier auf Bootstrap-Variablen umgeschrieben statt auf die
   Marken-Tokens des ERP: Dieses Projekt hat keine brand-tokens.css, und die vier
   Farbwerte dafür einzuschleppen hieße, eine halbe Design-Sprache zu pflegen,
   deren andere Hälfte fehlt.
   ============================================================================= */
.settings-card {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    height: 100%;
    padding: 1.25rem;
    background: #fff;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    text-decoration: none;
    box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.settings-card:hover,
.settings-card:focus-visible {
    border-color: var(--bs-primary, #0d6efd);
    box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
    transform: translateY(-1px);
}
.settings-card__icon {
    flex: 0 0 2.5rem;
    height: 2.5rem;
    display: grid;
    place-items: center;
    border-radius: 0.375rem;
    background: #e3f2fd;
    color: #0a58ca;
    font-size: 1.15rem;
}
.settings-card__body { flex: 1 1 auto; min-width: 0; }
.settings-card__title {
    font-weight: 600;
    color: var(--bs-emphasis-color, #212529);
    margin-bottom: 0.25rem;
}
.settings-card__text {
    font-size: 0.875rem;
    color: #5c636a;
    margin: 0;
}
.settings-card__topics {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: 1rem;
}
.settings-card__topic {
    font-size: 0.75rem;
    color: #5c636a;
    background: #f8f9fa;
    border: 1px solid #e9ecef;
    border-radius: 0.25rem;
    padding: 0.1em 0.45em;
}
.settings-card__chevron {
    flex: 0 0 auto;
    align-self: center;
    color: #adb5bd;
}


/* =============================================================================
   Horizontal scrollbare Reiterleisten mit Rand-Indikator

   Die Gruppenseiten der Einstellungen tragen bis zu drei Reiter mit Symbol und
   Text; auf 375 px passen sie nicht nebeneinander. Die native Scrollleiste ist
   ausgeblendet (.hide-scrollbar) — ohne Ersatzhinweis sieht die Leiste dann aus,
   als wäre sie vollständig, und der letzte Reiter ist unauffindbar. Deshalb an
   den Rändern ein Fade samt Chevron, sobald dort noch etwas liegt.

   Gesteuert von initTabScroll() in public/res/customjs.js über
   .can-scroll-left / .can-scroll-right.
   ============================================================================= */
.tab-scroll { position: relative; }
.tab-scroll__hint {
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    width: 2.5rem;
    z-index: 4;
    pointer-events: none;            /* Reiter am Rand bleiben klickbar */
    opacity: 0;
    transition: opacity 0.15s ease;
    color: var(--bs-primary, #0d6efd);
    font-size: 1.15rem;
}
.tab-scroll__hint--start {
    left: 0;
    justify-content: flex-start;
    padding-left: 0.15rem;
    background: linear-gradient(to right, #fff 45%, rgba(255, 255, 255, 0));
}
.tab-scroll__hint--end {
    right: 0;
    justify-content: flex-end;
    padding-right: 0.15rem;
    background: linear-gradient(to left, #fff 45%, rgba(255, 255, 255, 0));
}
.tab-scroll.can-scroll-left  .tab-scroll__hint--start { opacity: 1; }
.tab-scroll.can-scroll-right .tab-scroll__hint--end   { opacity: 1; }

.hide-scrollbar::-webkit-scrollbar { display: none; }
.hide-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

/* Reiterleiste in der Kartenkopfzeile: kein Rahmen, nur die Unterstreichung.
   Stand bis zum Umbau des Einstellungs-Hubs als <style>-Block in settings.blade.php
   und galt dort für JEDE .nav-tabs der Seite. */
.settings-tabs .nav-link {
    color: #6c757d;
    font-weight: 500;
    border: 0;
    border-bottom: 3px solid transparent;
    white-space: nowrap;
}
.settings-tabs .nav-link:hover:not(.active) { border-bottom-color: #dee2e6; }
.settings-tabs .nav-link.active {
    color: var(--bs-primary, #0d6efd);
    font-weight: 700;
    background: transparent;
    border-bottom-color: var(--bs-primary, #0d6efd);
}


/* ── Mitteilungs-Glocke ─────────────────────────────────────────────────────
   Das Läuten ist KEIN Schmuck: Es unterscheidet „hier ist eine Information" von
   „hier steht die Arbeit still" (Abo beendet, Testphase ausgeschöpft, Zugang gesperrt).
   Kurze Ausschläge statt Dauerwackeln, damit es nach ein paar Sekunden nicht nervt. */
.bell-ring {
    transform-origin: top center;
    animation: bell-ring 3.2s ease-in-out infinite;
}
@keyframes bell-ring {
      0% { transform: rotate(0); }
      3% { transform: rotate(16deg); }
      6% { transform: rotate(-14deg); }
      9% { transform: rotate(12deg); }
     12% { transform: rotate(-10deg); }
     15% { transform: rotate(7deg); }
     18% { transform: rotate(-4deg); }
     21% { transform: rotate(0); }
    100% { transform: rotate(0); }
}
.cta-pulse { animation: cta-pulse 1.8s ease-in-out infinite; }
@keyframes cta-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
    50%      { box-shadow: 0 0 0 0.28rem rgba(220, 53, 69, 0.28); }
}

/* 340 px lesen sich gut — passen aber bei 320 px Viewport nicht in den Container.
   Der Deckel verhindert den waagerechten Seiten-Scroll, den e2e/grenzwerte.spec.ts
   auf JEDER Seite melden würde: die Glocke hängt im Layout. */
.bell-menu {
    min-width: 340px;
    max-width: calc(100vw - 1.5rem);
}
/* Textlose Icon-Schaltfläche: e2e/taptargets.spec.ts verlangt 32x32 px. Ein
   .btn-close in Standardgröße rendert darunter. */
.bell-dismiss {
    min-width: 2rem;
    min-height: 2rem;
}

@media (prefers-reduced-motion: reduce) {
    .bell-ring, .cta-pulse { animation: none; }
}


/* =============================================================================
   Der Dokumentgestalter: Bühne, Blatt und Werkzeug-Panel

   Bedienmodell „Canvas + Panel": Das Blatt steht groß in der Mitte und bleibt
   immer sichtbar. Antippen einer Zone öffnet ihre Werkzeuge — ab lg als rechte
   Seitenleiste, darunter als halbhohes, NICHT-modales Bottom-Sheet (Bootstrap
   offcanvas-lg mit backdrop=false: das Blatt darüber bleibt bedienbar).

   Bis 09/2026 stand hier eine feste 7/5-Spaltenteilung mit einem Panel, das auf
   `max-height: 34rem; overflow-y: auto` gedeckelt war. Auf dem Telefon stapelte
   es UNTER das Blatt — man scrollte zwischen Werkzeug und Wirkung hin und her,
   und genau Tablet und Telefon sind der erklärte Bedienfall des Gestalters.

   Übernommen aus dem Schwesterprojekt (dort .ld-* in theme.css). Die Maße stehen
   hier als feste rem-Werte statt als Design-Tokens: ein zweites Token-System
   neben Bootstrap wäre hier eine Bruchkante ohne Nutzen, solange der Rest der
   Anwendung mit --bs-* auskommt.
   ============================================================================= */
.ld-stage {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.ld-canvas {
    flex: 1 1 auto;
    min-width: 0;                    /* der Flex-Klassiker: sonst läuft der Inhalt über */
    background: var(--bs-body-bg, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    padding: 0.75rem;
}

/* Das Blatt: in der Vollansicht höhengetrieben (so groß, wie der Schirm hergibt),
   im Zonen-Zoom setzt das Skript breitengetriebene Inline-Maße samt dem
   Seitenverhältnis der Zone — so letterboxt nichts und die Millimeter-Skala
   bleibt exakt.

   Breite statt Höhe deckeln: mit expliziter Höhe UND geklemmter max-width
   verlöre das Element das 210/297-Verhältnis (WebKit meldet dann 340×518 statt
   340×481) — der Inhalt letterboxte senkrecht, und alles, was Bildschirm-
   Millimeter aus der Elementbreite ableitet, zielte daneben. So bleibt
   Element = viewBox.

   touch-action: pan-y statt none — das Blatt füllt auf dem Telefon fast den
   Schirm, die Seite muss darüber scrollbar bleiben. Nur die Griffe (.ld-drag)
   sperren das Scrollen für ihre eigene Geste; die Begründung dazu steht am
   Zieh-Block in partials/dokumentdesign_script.blade.php. */
.ld-sheet {
    display: block;
    margin-inline: auto;
    width: 100%;
    max-width: calc(min(78vh, 62.5rem) * 210 / 297);
    height: auto;
    aspect-ratio: 210 / 297;
    background: #fff;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.25rem;
    touch-action: pan-y pinch-zoom;
}
.ld-sheet .ld-drag { touch-action: none; }
.ld-sheet .ld-zone-hit,
.ld-sheet .ld-zone-fix { cursor: pointer; }

/* Zonenleiste: dasselbe tab-scroll-Muster wie die Einstellungs-Reiter, nur ohne
   sichtbare Scrollleiste. */
.ld-zonebar { min-width: 0; }
.ld-zonebar .tab-scroll__viewport { scrollbar-width: none; }
.ld-zonebar .tab-scroll__viewport::-webkit-scrollbar { display: none; }

/* Werkzeug-Panel. Unter lg: halbhohes Bottom-Sheet (Bootstrap positioniert), mit
   abgerundeter Oberkante und Schatten — das Blatt bleibt sichtbar und bedienbar.
   Die Bühne bekommt Platz nach unten, solange es offen ist. */
.ld-panel { --bs-offcanvas-height: min(48vh, 480px); }

@media (max-width: 991.98px) {
    .ld-panel {
        border-top-left-radius: 0.5rem;
        border-top-right-radius: 0.5rem;
        box-shadow: 0 8px 24px rgba(31, 53, 93, 0.12);
    }
    body.ld-sheet-offen .ld-stage { padding-bottom: min(48vh, 480px); }
}

/* Ab lg: angedockte Seitenleiste. Bootstrap macht .offcanvas-lg hier zu einem
   normalen Element (keine Positionierung mehr), blendet aber den offcanvas-Kopf
   aus und stellt den Body auf Flex-Zeile — beides stellen wir fürs Panel zurück. */
@media (min-width: 992px) {
    .ld-panel {
        flex: 0 0 auto;
        width: 0;
        overflow: hidden;
    }
    .ld-stage.is-open .ld-panel {
        width: 400px;
        background: var(--bs-body-bg, #fff);
        border: 1px solid var(--bs-border-color, #dee2e6);
        border-radius: 0.5rem;
        position: sticky;
        top: 0.75rem;
        max-height: calc(100vh - 1.5rem);
        display: flex;
        flex-direction: column;
    }
    .ld-panel .offcanvas-header { display: flex; }
    .ld-panel .offcanvas-body {
        display: block;
        flex-grow: 1;
        padding: 0.5rem 0.75rem 0.75rem;
        overflow-y: auto;
    }
}

/* Farbwähler: Wähler — Name — Hexwert in einer Zeile, der Hinweis darunter über
   die volle Breite. Ein Grid statt Flexbox, weil der Hinweis sonst entweder in
   der schmalen Namensspalte klebte oder das Textfeld nach unten drückte.

   Feste Außenspalten, dehnbare Mitte: Farbfeld und Hexfeld sollen in jeder Zeile
   gleich breit sein und nie schrumpfen (im Panel sind ab lg nur 400 px zu holen),
   der Name darf dafür umbrechen — deshalb minmax(0, 1fr) statt 1fr. */
.ld-color-row {
    display: grid;
    grid-template-columns: 2.5rem minmax(0, 1fr) auto;
    align-items: center;
    gap: .25rem .5rem;
}
.ld-color-row > .form-control-color {
    width: 2.5rem;
    height: 2.5rem;
    padding: .25rem;
}
.ld-color-row > label {
    min-width: 0;
    overflow-wrap: break-word;
}
/* Breit genug für „#262d2f" samt Polsterung, und keinen Millimeter mehr — der
   Platz fehlt sonst dem Namen daneben. Ziffernbreite fest, damit die Felder
   untereinander nicht zappeln, während getippt wird. */
.ld-color-hex {
    width: 6.25rem;
    font-family: var(--bs-font-monospace, ui-monospace, monospace);
    font-variant-numeric: tabular-nums;
}
/* Der Hinweis gehört zu beiden Feldern und läuft deshalb unter der ganzen Zeile
   durch — ab der Namensspalte, damit er unter dem Namen beginnt. */
.ld-color-row > .ld-color-hint {
    grid-column: 2 / -1;
}
.ld-color-hint {
    display: block;
    font-size: .75rem;
    line-height: 1.25;
    color: var(--bs-secondary-color, #6c757d);
}

/* Gerenderter Zonen-Ausschnitt: das PNG ist die ganze Seite, der Ausschnitt ist
   reiner CSS-Beschnitt (die Maße setzt das Skript aus dem Zonen-Rechteck). */
.ld-preview-crop {
    position: relative;
    overflow: hidden;
    width: 100%;
    background: #fff;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.25rem;
}
.ld-preview-crop img {
    position: absolute;
    display: block;
    height: auto;
}

/* Touch: Zonenleiste und alles Bediente im Panel sicher treffbar. Beide Signale
   (pointer/hover), weil Emulatoren und manche Geräte nur eines von beiden setzen.
   Dieselbe Grenze, die e2e/taptargets.spec.ts prüft. */
@media (pointer: coarse), (hover: none) {
    #ddZoneTabs .nav-link {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }
    .ld-panel .btn,
    .ld-panel .form-select,
    .ld-panel .form-control { min-height: 44px; }
    .ld-panel .list-group-item { min-height: 44px; }
    .ld-panel .ld-weg { min-width: 40px; }
}


/* =============================================================================
   Aktionsleiste am Fuß einer Arbeitsfläche

   position: sticky statt fixed: die Leiste bleibt Teil des Seitenflusses,
   verdeckt am Seitenende nichts und braucht keinen Platzhalter im Layout.
   ============================================================================= */
.doc-actionbar {
    position: sticky;
    bottom: 0;
    z-index: 3;
    margin-top: 1.5rem;
    padding: 0.75rem 1rem;
    background: var(--bs-body-bg, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    box-shadow: 0 -0.5rem 1rem -0.5rem rgba(31, 53, 93, 0.15);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.doc-actionbar__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}
.doc-actionbar__actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    align-items: center;
}

/* Auf dem Telefon frisst die volle Leiste zu viel Höhe: Status in eine Zeile,
   Aktionen darunter über die volle Breite (bessere Trefferfläche). */
@media (max-width: 575.98px) {
    .doc-actionbar { padding: 0.5rem 0.75rem; }
    .doc-actionbar__inner { flex-direction: column; align-items: stretch; gap: 0.5rem; }
    .doc-actionbar__actions > .btn { flex: 1 1 0; min-width: 0; }
}


/* =============================================================================
   BETREIBER-BACKOFFICE — angeglichen an die Betreiberfläche des ERP
   =============================================================================

   Warum das hier steht und nicht in einer eigenen Datei: Das Backoffice-Layout
   lädt dieselbe app.css wie die Mandanten-Anwendung. Eine zweite Datei wäre ein
   zweiter Ladevorgang für eine Fläche, die ohnehin nur eine Handvoll Regeln
   braucht — und eine zweite Stelle, an der man beim nächsten Umbau nachsehen muss.

   KEINE MARKENFARBEN, KEINE TOKEN-DATEI. Das ERP führt seine Marke in einer
   eigenen brand-tokens.css (Levius-Navy, Türkis-Familie, neutrale Rampe). Dieses
   Projekt tut das bewusst NICHT: Gearbeitet wird mit den --bs-*-Variablen, die
   Bootstrap 5.3.8 ohnehin mitbringt und die in beiden Projekten identisch sind.
   Wo das ERP var(--brand-blue) schreibt, steht hier var(--bs-primary).
   Abstände sind rohe rem-Werte auf Bootstraps Stufung (0.25/0.5/0.75/1/1.5/2).

   WAS HIER GLOBAL GILT UND WAS NICHT: Alles in diesem Block wird über eine
   KLASSE zugeschaltet (.bo-shell, .app-shell, .navbar-adaptive, .table-stack,
   .app-footer). Keine Regel greift von selbst in die Mandanten-Anwendung hinein.
   Das ist Absicht und nicht Vorsicht: Die Mandantenfläche hat visuelle Baselines
   über acht Geräteprojekte; eine Angleichung des Backoffice darf sie nicht
   nebenbei verschieben.
   ========================================================================== */


/* --- Überschriftenschrift der Betreiberfläche -------------------------------
   Selbst gehostet (DSGVO — kein Google-CDN); beide Schnitte liegen bereits unter
   public/fonts/, weil Werbeseite und Fehlerseiten sie schon führen. Die
   OFL-Lizenzdatei liegt daneben (MONTSERRAT-LICENSE.txt) und wird von
   app:generate-third-party-notices erfasst — es kommt also KEINE neue Datei und
   keine neue Lizenzpflicht dazu.

   Auf .bo-shell geschlüsselt und nicht global: Die Mandanten-Anwendung setzt ihre
   Überschriften seit jeher in der Systemschrift, und ihre Layout-Baselines messen
   genau diese Zeilenhöhen. Die Betreiberfläche hat keine Baselines und ist die
   Fläche, die dem ERP gleichen soll. */
@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/montserrat-latin-600-normal.woff2') format('woff2');
}
@font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/montserrat-latin-700-normal.woff2') format('woff2');
}

.bo-shell h1, .bo-shell h2, .bo-shell h3,
.bo-shell h4, .bo-shell h5, .bo-shell h6,
.bo-shell .h1, .bo-shell .h2, .bo-shell .h3,
.bo-shell .h4, .bo-shell .h5, .bo-shell .h6,
.bo-shell .modal-title,
.bo-shell .brand-company {
    font-family: 'Montserrat', var(--bs-font-sans-serif);
}


/* --- Inhaltsspalte: Deckel wie im ERP ---------------------------------------
   Ab 992 px bekommt die Inhaltsspalte denselben Deckel wie Leiste und Fußzeile.
   Ohne ihn greift Bootstraps 960er-Stufe, während die Chrome-Balken schon auf
   1320 stehen — der Inhalt säße dann schmaler als die Marke darüber.

   Der Randabstand gilt NUR, solange der Container fließt (992–1319). Ab 1320
   schafft die max-width den Rand von selbst; dort bleibt die Polsterung
   unangetastet, damit sich oberhalb des Deckels nichts ändert.

   EIN Selektor reicht: Leiste und Fußzeile tragen ihren Container INNERHALB von
   body.app-shell, .app-shell .container greift also auch dort. Das ERP schlüsselt zusätzlich
   auf .navbar > .container und .app-footer > .container, weil dort Anmelde-, Bezahl- und
   Einrichtungsseiten dasselbe Stylesheet ohne .app-shell laden und die Chrome-Balken den
   Deckel trotzdem brauchen. Diese Fläche hat den Fall nicht — jede ihrer Seiten, auch die
   Anmeldung, läuft im selben Layout. */
@media (min-width: 992px) {
    .app-shell .container { max-width: min(100%, 1320px); }
}
@media (min-width: 992px) and (max-width: 1319.98px) {
    .app-shell .container { padding-inline: 1.5rem; }
}

/* EINE Leistenhöhe, unabhängig davon, was in der Leiste steht. Ohne diesen Boden
   ist sie inhaltsgetrieben: auf der Anmeldeseite trägt sie nur die Marke, in der
   Anwendung die Menüzeile — das Logo spränge beim Anmelden senkrecht. */
@media (min-width: 992px) {
    .bo-shell .navbar > .container { min-height: 2.75rem; }
}


/* --- Navbar: Marke ----------------------------------------------------------
   Aus dem Inline-<style> von layouts/app.blade.php hierher gezogen (dort trug sie
   rohe Hex-Werte; #212529 ist exakt --bs-body-color, #6c757d exakt
   --bs-gray-600 — der Umzug ändert also keine einzige Farbe).

   Logo-Seitenverhältnis UND Textlänge sind mandantenkonfigurierbar und damit
   unbekannt. Deshalb die beiden Notnägel unten. */
.navbar-brand-container {
    display: flex;
    align-items: center;
    text-decoration: none;
}
.brand-logo {
    flex: 0 0 auto;

    /* height SETZT die Höhe, max-height DECKELT sie nur — und das ist hier der
       ganze Unterschied: Logos, deren SVG mit kleinen Maßen exportiert ist
       (width="28" height="24" ist durchaus üblich), würden mit
       `height:auto;max-height:40px` NICHT auf 40 px hochskaliert, sondern blieben
       bei 24 px stehen. Also feste Höhe; der Preis ist die Letterbox unten. */
    height: 40px;
    width: auto;

    /* Gegen Extremformate: ein 1200×100-Banner käme mit width:auto auf 480 px und
       sprengte die Leiste im Alleingang. Greift der Deckel, bleibt die BOX 40 px
       hoch und object-fit setzt das Bild unverzerrt linksbündig hinein. Für ein
       normales, annähernd quadratisches Zeichen greift er nie. */
    max-width: 15rem;
    object-fit: contain;
    object-position: left center;

    margin-right: 12px;
}
.brand-text-wrapper {
    display: flex;
    flex-direction: column;
    line-height: 1.1;
    min-width: 0;   /* der Flex-Klassiker: sonst greift text-overflow nie */
}
.brand-company { font-size: 1.15rem;  font-weight: 700; color: var(--bs-body-color); }
.brand-site    { font-size: 0.85rem;  font-weight: 500; color: var(--bs-gray-600); }

/* Umbricht der Markenname mobil, springt der Hamburger in die nächste Flex-Zeile
   — ohne row-gap klebte er ohne Abstand direkt unter dem Namen. */
.navbar > .container { row-gap: 0.5rem; }

/* Telefon: eine querformatige Wortmarke fräße hier die halbe Bildschirmbreite. */
@media (max-width: 575.98px) {
    .brand-logo { max-width: 7rem; }
}

/* Ein reines Symbol in der Leiste trägt oft fs-5 und machte seine Zeile höher als
   alle beschrifteten Punkte. Mit line-height 1 zählt nur noch das Symbol. */
.nav-link--icon .bi { line-height: 1; }


/* --- Navbar: adaptiver Zustand ----------------------------------------------
   Der Hamburger erscheint, wenn die Menüzeile NICHT MEHR PASST — nicht bei einer
   festen Breite. Grund: Der Platzbedarf steht zur Autorenzeit nicht fest. Er
   hängt an der Stufe des Angemeldeten (owner sieht einen Menüpunkt mehr), am
   Anzeigenamen des Betreibers und am konfigurierbaren Markennamen. Jeder feste
   Breakpoint ist für die eine Hälfte zu früh und für die andere zu spät.

   Deshalb trägt <nav> KEIN navbar-expand-*, sondern die Zustandsklasse
   .is-expanded, die public/js/nav-adaptive.js hinter </nav> setzt.

   EINGEKLAPPT ist damit der unveränderte Bootstrap-Grundzustand einer .navbar
   ohne Expand-Klasse — gestapelte Spalte, sichtbarer Toggler, .collapse:not(.show)
   versteckt. Es wird also NICHTS von Bootstraps Mobilverhalten nachgebaut.
   AUSGEKLAPPT sind es exakt die Regeln, die .navbar-expand-lg in
   bootstrap.min.css v5.3.8 ab 992 px setzt (die .navbar-nav-scroll- und die
   .offcanvas-Regeln nutzt dieses Layout nicht). Wer hier etwas ergänzt, hält sich
   an diese Liste. */
.navbar-adaptive.is-expanded                             { flex-wrap: nowrap; }
.navbar-adaptive.is-expanded .navbar-nav                 { flex-direction: row; align-items: center; }
.navbar-adaptive.is-expanded .navbar-nav .dropdown-menu  { position: absolute; margin-top: 0.5rem; }
.navbar-adaptive.is-expanded .navbar-nav .nav-link       { padding-inline: var(--bs-navbar-nav-link-padding-x); }
.navbar-adaptive.is-expanded .navbar-nav .nav-link--icon { padding-inline: 0.25rem; }
.navbar-adaptive.is-expanded .navbar-toggler             { display: none; }
/* justify-content bleibt bewusst auf Bootstraps space-between (statt des
   flex-start, das navbar-expand-lg setzt): Weil das Menü unten auf seine
   Inhaltsbreite fixiert wird, hätte ms-auto keinen freien Raum mehr zu verteilen
   — space-between erledigt die Rechtsbündigkeit. */

/* Nur im ausgeklappten Zustand sichtbar/unsichtbar (ersetzt d-lg-none und die
   ms-lg-*-Abstände, die nach dem Wegfall von navbar-expand-* die falsche Frage
   stellten — Bildschirmbreite statt Zustand). */
.navbar-adaptive.is-expanded .nav-only-collapsed { display: none !important; }
.navbar-adaptive.is-expanded .nav-gap-group      { margin-left: 1rem; }
.navbar-adaptive.is-expanded .nav-gap-util       { margin-left: 0.5rem; }

/* MESSBARKEITS-INVARIANTE — ohne sie funktioniert das Skript nicht.
   Im ausgeklappten Zustand darf weder die Marke noch das Menü wachsen oder
   schrumpfen, und nichts darf umbrechen. Nur dann ist die gemessene Breite die
   WAHRE Platznachfrage. Andernfalls würde die Marke still gekürzt, der Bedarf
   sänke genau dann, wenn er zu hoch ist — die Messung mäße ihre eigene
   Entscheidung (Zirkelschluss) und der Hamburger käme nie.

   Aus demselben Grund müssen die Menüpunkte .nav-link sein und keine .btn: Ein
   Knopf dürfte umbrechen und meldete damit einen zu kleinen Bedarf. */
.navbar-adaptive.is-expanded > .container > .navbar-collapse {
    display: flex !important;
    flex: 0 0 auto;
    min-width: 0;
}
.navbar-adaptive.is-expanded .navbar-brand-container { flex: 0 0 auto; min-width: 0; }
.navbar-adaptive.is-expanded .navbar-nav > *         { flex: 0 0 auto; }
.navbar-adaptive.is-expanded .navbar-nav .nav-link   { white-space: nowrap; }

/* Ein sehr langer Markenname soll die Leiste nicht in den Hamburger zwingen,
   sondern selbst zurückstecken: Die Marke bekommt höchstens 40 % der Leiste und
   kürzt danach mit Ellipse. Der Deckel hängt am VIEWPORT, nicht am Restplatz —
   die Messung bleibt dadurch zirkelfrei. */
.navbar-adaptive.is-expanded .navbar-brand-container { max-width: min(30rem, 40vw); }
.navbar-adaptive.is-expanded .brand-company,
.navbar-adaptive.is-expanded .brand-site {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Eingeklappt: gestapelte Liste (ersetzt pt-3/pt-lg-0). Hier darf der Name
   umbrechen — auf einem 390-px-Telefon wäre eine Ellipse nach 160 px schlechter
   als zwei Zeilen, und row-gap oben ist genau dafür da. */
.navbar-adaptive:not(.is-expanded) .navbar-nav { padding-top: 1rem; }

/* Kompaktband 992–1399: Die Leiste ist hier gerade erst ausklappbar, der Container
   aber noch nicht auf seinem Maximum. Etwas dichter gesetzt passt das Menü rund
   60 px früher — der Unterschied zwischen „volle Navigation auf dem iPad" und
   „Hamburger". Es rückt AUSSCHLIESSLICH das Menü zusammen, nie die Marke: Das
   Logo ist Marke, nicht Füllmaterial, und bleibt in allen Breiten gleich groß. */
@media (min-width: 992px) and (max-width: 1399.98px) {
    .navbar-adaptive.is-expanded                { --bs-navbar-nav-link-padding-x: 0.375rem; }
    .navbar-adaptive.is-expanded .nav-link      { font-size: 0.9375rem; }
    .navbar-adaptive.is-expanded .nav-gap-group { margin-left: 0.5rem; }
    .navbar-adaptive.is-expanded .nav-gap-util  { margin-left: 0.25rem; }
}


/* --- Fußzeile ---------------------------------------------------------------
   Klebt am unteren Rand, auch wenn die Seite kürzer ist als das Fenster — das
   besorgt d-flex/min-vh-100/mt-auto im Layout, nicht diese Regel. Hier steht nur
   die Fläche. bg-dark statt einer Markenfarbe: Dieses Projekt führt keine
   Token-Datei (siehe Kopf dieses Blocks). */
.app-footer {
    background-color: var(--bs-dark);
    color: rgba(255, 255, 255, 0.8);
}
.app-footer a {
    color: rgba(255, 255, 255, 0.8);
    text-decoration: none;
    transition: color 0.2s ease;
}
.app-footer a:hover,
.app-footer a:focus { color: #fff; }


/* --- Tabellen: unter lg als gestapelte Karten --------------------------------
   .table-stack auf ein <table>, dazu an jeder Daten-<td> ein
   data-label="Spaltenname". Ab lg eine normale Tabelle, darunter wird jede Zeile
   zu einer Karte (Label über Wert) — so bleibt auf dem Telefon alles lesbar statt
   seitlich abgeschnitten. Aktionszellen bekommen zusätzlich .stack-actions.

   WARUM NICHT DIE VORHANDENEN .rtable-*: Jene erwarten <div>-Zeilen. Die
   Backoffice-Tabellen sind echte <table>; sie umzuschreiben wäre ein Vielfaches
   des Diffs und träfe nebenbei den Selektor `table a[href^="/mandanten/"]` in
   e2e/backoffice.spec.ts. Es entsteht damit bewusst ein zweiter Mechanismus neben
   dem ersten — er bleibt auf die Betreiberfläche beschränkt. */
@media (max-width: 991.98px) {
    .table-stack thead { display: none; }
    .table-stack,
    .table-stack > tbody,
    .table-stack > tbody > tr,
    .table-stack > tbody > tr > td {
        display: block;
        width: 100%;
    }
    .table-stack > tbody > tr {
        border: 1px solid var(--bs-border-color);
        border-radius: 0.5rem;
        padding: 0.75rem 1rem;
        margin-bottom: 0.75rem;
        background: var(--bs-body-bg);
    }
    .table-stack > tbody > tr > td {
        border: 0 !important;
        padding: 0.3rem 0 !important;
        text-align: left !important;
        white-space: normal !important;
    }
    .table-stack > tbody > tr > td[data-label]::before {
        content: attr(data-label);
        display: block;
        font-size: 0.7rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.02em;
        color: var(--bs-secondary-color);
        margin-bottom: 0.1rem;
    }
    /* Lange Werte (Hashes, Schlüssel) sauber umbrechen statt abschneiden. */
    .table-stack > tbody > tr > td code.text-truncate {
        max-width: 100% !important;
        white-space: normal;
        word-break: break-all;
    }
    /* Aktionszellen: Knöpfe auf volle Breite, größere Tap-Fläche. */
    .table-stack > tbody > tr > td.stack-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
        padding-top: 0.6rem !important;
    }
    .table-stack > tbody > tr > td.stack-actions > .btn,
    .table-stack > tbody > tr > td.stack-actions > form { flex: 1 1 auto; }
    .table-stack > tbody > tr > td.stack-actions > form > .btn { width: 100%; }
    /* Eine leere Aktionszelle soll keine Lücke aufreißen. */
    .table-stack > tbody > tr > td.stack-actions:empty { display: none; }
}

/* ===== Status-Badges (Zahlungszustände) ======================================
   Die Bootstrap-Kombination `bg-X-subtle text-X` ist nicht barrierefrei; im
   Schwesterprojekt gemessen: „Offen" kam auf 1,47:1 und war praktisch
   unsichtbar. Die Paare hier liegen alle über 7:1.

   Verwendung: <x-status-badge :status="$satz->payment_state" />           */
.badge-status {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.35em 0.65em;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    border-radius: 0.25rem;
    border: 1px solid transparent;
}
.badge-status--paid     { color: #0F5132; background: #D1E7DD; border-color: #A3CFBB; } /* 7,21:1 */
.badge-status--open     { color: #664D03; background: #FFF3CD; border-color: #E8D48B; } /* 7,21:1 */
.badge-status--overdue  { color: #842029; background: #F8D7DA; border-color: #EBA9AE; } /* 7,08:1 */
.badge-status--canceled { color: #41464B; background: #E2E3E5; border-color: #C4C8CB; } /* 7,42:1 */
