/**
 * Eigene Gestaltung über Bootstrap.
 *
 * Bewusst klein gehalten: Bootstrap bringt fast alles mit, was gebraucht
 * wird. Hier stehen nur die Farben der Marke und das Wenige, wofür es keine
 * Bootstrap-Hilfsklasse gibt.
 *
 * Die Farbwerte stimmen mit dem Bildstil überein, damit erzeugte Grafiken
 * und Seitenelemente nicht nebeneinander auffallen:
 *   Tiefblau #1B3A8C, Amber #F2A81D, Hellgrau #F5F6F8.
 */

:root {
    --apizone-tiefblau: #1b3a8c;
    --apizone-tiefblau-dunkel: #13296a;
    --apizone-amber: #f2a81d;
    --apizone-amber-dunkel: #d8920e;
    --apizone-hellgrau: #f5f6f8;
}

body {
    /* Systemschriften statt einer geladenen Webschrift: eine Schrift von
       fonts.google.com würde die IP-Adresse jedes Besuchers an Google
       übertragen, dasselbe Problem wie bei einem fremden CDN. */
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    color: #1f2430;
}

.bg-tiefblau {
    background-color: var(--apizone-tiefblau) !important;
}

.bg-hellgrau {
    background-color: var(--apizone-hellgrau) !important;
}

.text-tiefblau {
    color: var(--apizone-tiefblau) !important;
}

.text-amber {
    color: var(--apizone-amber) !important;
}

/* Amber trägt auf höchstens einem Element je Ansicht die Aufmerksamkeit
   dieselbe Regel gilt für die erzeugten Grafiken. */
.btn-amber {
    background-color: var(--apizone-amber);
    border-color: var(--apizone-amber);
    color: #1f2430;
    font-weight: 600;
}

.btn-amber:hover,
.btn-amber:focus {
    background-color: var(--apizone-amber-dunkel);
    border-color: var(--apizone-amber-dunkel);
    color: #1f2430;
}

.btn-tiefblau {
    background-color: var(--apizone-tiefblau);
    border-color: var(--apizone-tiefblau);
    color: #fff;
}

.btn-tiefblau:hover,
.btn-tiefblau:focus {
    background-color: var(--apizone-tiefblau-dunkel);
    border-color: var(--apizone-tiefblau-dunkel);
    color: #fff;
}

.navbar-dark .navbar-nav .nav-link {
    color: rgba(255, 255, 255, 0.85);
}

.navbar-dark .navbar-nav .nav-link.active,
.navbar-dark .navbar-nav .nav-link:hover {
    color: #fff;
}

/**
 * Sichtbarer Fokusrahmen, zwei Ringe, und beide werden gebraucht.
 *
 * Bootstrap bringt einen mit, der auf dem Tiefblau des Kopfbereichs zu schwach
 * ist; Tastaturbedienung darf nicht raten. Ein Amber-Rahmen allein löst das
 * aber nur halb: auf dem Tiefblau kommt er auf 5,1:1, auf Weiß nur auf 2,0:1
 * WCAG verlangt 3:1 gegen den Untergrund (1.4.11).
 *
 * Deshalb innen ein dunkler Ring und außen der Amber-Ring. Auf hellem Grund
 * trägt der dunkle (13,5:1), auf dem Tiefblau der Kopfzeile trägt der Amber.
 * Einer von beiden ist immer der sichtbare, und welcher, muss niemand wissen.
 */
a:focus-visible,
button:focus-visible,
.btn:focus-visible {
    outline: 3px solid var(--apizone-amber);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--apizone-tiefblau-dunkel);
}

.abschnitt {
    padding: 4rem 0;
}

/*
 * Hier stand bis zum 2026-09-23 `.fusszeile-gedaempft` mit 70 % Weiß, als
 * barrierefreier Ersatz für Bootstraps `text-white-50` (das kommt auf dem
 * Tiefblau nur auf 3,8:1 und verfehlt WCAG AA).
 *
 * Die Regel ist entfallen. Der Benutzer hat festgelegt, dass der Text der
 * Fußzeile weiß ist, und dafür genügt Bootstraps `text-white`. Das ist hier
 * nicht nur kürzer, sondern belastbarer: im ausgelieferten Portal fehlte die
 * eigene Regel, weil der Zwischenspeicher eine ältere Fassung dieser Datei
 * hielt, und der Text stand dunkel auf dem Tiefblau. Eine Farbe, die eine
 * Seite unlesbar macht, wenn genau diese Datei fehlt, gehört nicht hierher.
 */

/**
 * Tabellen, deren Spaltenbreite nicht vom Inhalt abhängt.
 *
 * Alle Tabellen des Portals zeigen Zahlen, die sich laufend ändern. Bei der
 * üblichen automatischen Breite verschiebt schon ein Credit mehr die ganze
 * Zeile nach rechts, für den Betrachter unruhig, und für den
 * Screenshot-Vergleich fatal: die veränderlichen Stellen sind ausgeblendet,
 * aber der Versatz, den sie auslösen, ist es nicht. Genau daran ist der
 * Vergleich des Adminbereichs am 2026-09-21 gescheitert.
 *
 * Die Breiten stehen als `<colgroup>` in der jeweiligen Vorlage, weil sie zur
 * Tabelle gehören und nicht zur Gestaltung.
 */
.tabelle-fest {
    table-layout: fixed;
}

/**
 * Das linke Portalmenü (`rahmen/portal.tpl`).
 *
 * Bootstrap bringt `.nav-pills` mit, das sähe hier aber aus wie eine
 * Reiterleiste. Gebraucht wird eine ruhige Liste, in der die aktive Seite
 * durch eine Kante links markiert ist, dieselbe Kante bleibt bei den
 * inaktiven Einträgen durchsichtig, damit beim Wechsel nichts verspringt.
 */
.portalmenue .nav-link {
    color: #1f2430;
    border-left: 3px solid transparent;
    padding: 0.35rem 0.75rem;
}

.portalmenue .nav-link:hover {
    color: var(--apizone-tiefblau);
    background-color: var(--apizone-hellgrau);
}

.portalmenue .nav-link.active {
    color: var(--apizone-tiefblau);
    border-left-color: var(--apizone-amber);
    font-weight: 600;
}

.portalmenue .nav-link .bi {
    margin-right: 0.5rem;
    color: var(--apizone-tiefblau);
}

/*
 * Hier standen bis zum 2026-09-23 `.portalmenue-titel` und
 * `.portalmenue-kategorie`: die Überschrift „Ihre APIs" im linken Menü und
 * darunter je Kategorie eine Zwischenzeile. Der Benutzer hat diese dritte
 * Menüebene verworfen, an ihrer Stelle steht der feste Punkt „APIs" und
 * dahinter `templates/portal/apis.tpl`. Beide Regeln sind damit ohne Element.
 */

/**
 * Die erzeugten Kategorie-Icons (`public/bilder/kategorie/`).
 *
 * Ausgeliefert werden sie mit 256 px Kantenlänge, damit sie auf einem
 * Bildschirm mit doppelter Auflösung scharf bleiben. Dargestellt hier mit 96
 * bzw. 128 px; `width`/`height` stehen trotzdem im `<img>`, weil der Browser
 * sonst erst beim Laden weiß, wie hoch die Karte wird, und die ganze Reihe
 * nachträglich verspringt.
 *
 * `mix-blend-mode: multiply` löst den weißen Hintergrund auf. Die Bilder
 * kommen mit einer nahezu weißen Fläche (gemessen #FBFCFC); auf der weißen
 * Karte fällt die nicht auf, auf dem hellgrauen Kopfbereich der
 * Kategorieseite säße sonst ein hellerer Kasten hinter dem Motiv.
 * Multiplizieren mit #F5F6F8 verdunkelt die Farben um weniger als zwei
 * Prozent, nicht sichtbar, und der Kasten ist weg. Ein Freistellen beim
 * Erzeugen wäre die Alternative, verlangt aber einen Alphakanal, den das
 * Modell nicht liefert.
 */
.icon-kategorie {
    width: 96px;
    height: 96px;
    mix-blend-mode: multiply;
}

.icon-kategorie-gross {
    width: 128px;
    height: 128px;
}

/**
 * Die erzeugte Kopfgrafik je API (`public/bilder/api/`).
 *
 * Dieselbe Überlegung wie beim Icon, nur quer: `mix-blend-mode: multiply`
 * löst den nahezu weißen Grund auf dem hellgrauen Kopfbereich auf.
 *
 * `max-width: 100%` statt einer festen Breite, die Spalte ist auf großen
 * Bildschirmen rund 450 px breit und auf dem Telefon so breit wie die Seite.
 * `height: auto` muss dazu, weil im `<img>` eine feste Höhe steht; ohne diese
 * Zeile würde die Grafik beim Schrumpfen gestaucht.
 */
.grafik-api {
    max-width: 100%;
    height: auto;
    mix-blend-mode: multiply;
}

/**
 * Dieselbe Grafik als Vorschaubild in der Dienstliste des Portals
 * (Festlegung des Benutzers vom 2026-09-27).
 *
 * Eine feste Breite und keine Obergrenze in Prozent: hier steht das Bild in
 * einer Zeile neben Namen und Kurztext und soll in jeder Zeile gleich breit
 * sein. Ohne die feste Breite bestimmte das Seitenverhältnis der Datei, wie
 * weit der Text einrückt, und die Liste stünde schief.
 *
 * `flex-shrink: 0` gehört dazu, weil die Zeile ein Flexkasten ist: sonst
 * gäbe das Bild auf dem Telefon seine Breite an den Text ab und würde zum
 * Strich.
 */
.grafik-api-klein {
    width: 96px;
    height: auto;
    flex-shrink: 0;
    mix-blend-mode: multiply;
}

/**
 * Zu den Szenen der Werbeseiten (`public/bilder/szene/`) steht hier mit
 * Absicht keine Regel mehr.
 *
 * Bis zum 2026-09-25 gab es `.szene` mit `max-width: min(100%, 460px)` und
 * `mix-blend-mode: multiply`. Beides ist mit den Fotos hinfällig. `multiply`
 * war für eine flache Illustration mit nahezu weißem Grund gedacht; ein Foto
 * hat keinen solchen Grund, und `multiply` würde es auf jeder farbigen Fläche
 * verdunkeln. Die Obergrenze hielt das Bild unterhalb von `lg` davon ab, die
 * ganze Breite zu nehmen; das erledigen jetzt die Spaltenklassen
 * `col-10 col-sm-8 col-md-6 col-lg-5` zusammen mit `img-fluid`.
 *
 * Der Grund für den Wechsel ist der gemeldete Fehler vom 2026-09-25: mit
 * einem veralteten `apizone.css` im Zwischenspeicher stand das Bild in voller
 * Breite über dem Text. Eine Größe, die nur aus diesem Stylesheet kommt, ist
 * eine Größe, die fehlen kann. Aus Bootstrap kann sie das nicht, ohne dass
 * die ganze Seite ohnehin verloren wäre.
 */

.karte-api {
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.karte-api:hover {
    transform: translateY(-2px);
    box-shadow: 0 0.5rem 1rem rgba(27, 58, 140, 0.15);
}

/* Wer Bewegung im Betriebssystem abgeschaltet hat, bekommt hier keine. */
@media (prefers-reduced-motion: reduce) {
    .karte-api,
    .karte-api:hover {
        transition: none;
        transform: none;
    }
}

/**
 * Das Signal am Feld, das beim Verlassen gespeichert hat.
 *
 * Festlegung des Benutzers vom 2026-09-25: es gibt keinen Speichern-Knopf
 * mehr, dafür ein optisches Signal. Den Rahmen macht Bootstrap mit
 * `.is-valid` und `.is-invalid`, den Text daneben setzt
 * `public/skript/feldspeichern.js`. Hier steht nur, wie er sich verhält.
 *
 * `display: block`, damit die Bestätigung unter dem Feld steht und nicht
 * daneben: in einer Tabellenzelle mit fester Breite schöbe ein Wort neben dem
 * Feld die Spalte auseinander.
 *
 * `min-height` hält den Platz frei, auch solange nichts dasteht. Ohne diese
 * Zeile rückte beim Speichern alles darunter um eine Zeilenhöhe nach unten
 * und vier Sekunden später wieder zurück.
 */
.feld-signal {
    display: block;
    min-height: 1.25rem;
    margin-top: 0.25rem;
}

/* Bootstrap hängt bei `.is-valid` ein Häkchen als Hintergrundbild ins Feld.
   In den schmalen Zahlenfeldern des Adminbereichs liegt es über der Zahl. */
.form-control-sm.is-valid,
.form-control-sm.is-invalid {
    background-position: right 0.4rem center;
    background-size: 0.75rem 0.75rem;
}

/**
 * Die hinterlegten Beispiele im öffentlichen Testbereich (4.10).
 *
 * Zwei Dienste nehmen eine Datei entgegen, und der Besucher wählt sie aus
 * statt sie hochzuladen. Warum das so ist, steht in
 * `src/Fachlich/Testbeispiel.php`.
 *
 * Bootstrap brächte dafür `.btn-check` mit. Das ist hier die falsche Form:
 * ein angewähltes `.btn-check` färbt seine Fläche voll ein, und eine
 * Bildvorschau auf einer vollen Farbfläche sieht aus wie ein Fehler. Gewählt
 * wird deshalb über den Rahmen, das Bild bleibt, wie es ist.
 *
 * Das Eingabefeld ist durchsichtig und nicht `display: none`: so bleibt es in
 * der Tabulatorreihenfolge, und die Auswahl lässt sich ohne Maus treffen. Was
 * dabei zu sehen ist, macht die Regel mit `:focus-visible` darunter.
 */
.beispiel input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}

.beispiel label {
    display: block;
    max-width: 11rem;
    padding: 0.5rem;
    border: 2px solid var(--bs-border-color);
    border-radius: 0.5rem;
    background-color: #fff;
    text-align: center;
    cursor: pointer;
}

.beispiel input:checked + label {
    border-color: var(--apizone-tiefblau);
    box-shadow: 0 0 0 2px var(--apizone-tiefblau);
}

.beispiel input:focus-visible + label {
    outline: 3px solid var(--apizone-amber);
    outline-offset: 2px;
}

/*
 * Feste Proportion statt fester Höhe: die Beispielbilder sind quer, aber sie
 * müssen nicht auf denselben Pixel gleich sein. `object-fit: cover` hält die
 * Reihe trotzdem bündig, und der Zuschnitt fällt bei einem Motiv in der Mitte
 * nicht auf.
 */
.beispiel-bild {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
}
