﻿@charset "UTF-8";

/*Die Palette des Schirms. Es gibt genau eine - die Anwendung ist dunkel, die zweite Palette der
  Datei ist die des Papiers (html.uhl-print weiter unten).

  Warum trotzdem beide data-bs-theme-Werte im Selektor stehen: die index.html der Hosts stempelt
  data-bs-theme="dark" ans <html> (Bootstrap liest es), der Druckdienst reicht den Wert an sein
  Druckdokument weiter. Steht dort einmal etwas anderes, sollen die Variablen trotzdem gelten -
  eine Anwendung ohne Farben waere schlimmer als eine, die dunkel bleibt, obwohl "light" dransteht.
  Und :root ist der Grundfall, damit auch ohne das Attribut alles seine Werte hat.

  Bis zum 26.08.2026 standen hier zwei Bloecke: ":root [data-bs-theme=light]" (ohne Komma, also ein
  Nachfahren-Selektor, der nie zutraf - damit war auch der :root-Grundfall weg) und ein Zeile fuer
  Zeile identischer [data-bs-theme=dark]. Getragen hat allein der zweite; eine neue Variable musste
  man an zwei Stellen pflegen.*/
:root,
[data-bs-theme=light],
[data-bs-theme=dark] {
    --std-headerfooter-color: #1D1D1D;
    --std-headerfooter-heigth: 55px;
    --std-background-gradient: linear-gradient(0deg, #292929, #484848, #292929);
    --std-background-color: #212529;
    --std-border-color: #495057;
    --std-border-color-t50: rgba(73, 80, 87, 0.5);
    /*ReadOnly-Grund der Eingabefelder, wie StdTextBoxReadOnlyBackground im WPF-Standard*/
    --std-input-readonly-background: #333333;
    /*stdcolors*/
    --std-white-color: white;
    --std-black-color: black;
    --std-darkgray-color: #343A40;
    /*--std-darkgray-color: #646464;*/
    --std-gray-color: #C8C8C8;
    --std-red-color: #E40421;
    --std-red-color-t50: rgba(228, 4, 33, 0.5);
    --std-orange-color: #FE8001;
    --std-orange-color-t50: rgba(254, 128, 1, 0.5);
    --std-yellow-color: #C8C828;
    --std-yellow-color-t50: rgba(200, 200, 40, 0.5);
    --std-blue-color: #0a58ca;
    --std-blue-color-t50: rgba(10, 88, 202, 0.5);
    /*Blau als Signalfarbe auf dunklem Grund. Es gibt sie, weil --std-blue-color dafuer nicht
      taugt: gegen --std-background-color (#212529) steht es bei 2,4:1, das WPF-Blau #2828C8 sogar
      bei 1,64:1 - dunkler als das Grau, mit dem der Ruhezustand gezeichnet wird. Eine Lampe war
      damit am hellsten, wenn nichts passiert. Dieses Blau liegt bei 5,9:1.
      --std-blue-color bleibt, was es ist: die Flaeche eines Knopfes, auf der Weiss steht.*/
    --std-lightblue-color: #4DA3FF;
    --std-green-color: #28C828;
    --std-green-color-t50: rgba(40, 200, 40, 0.5);
    --std-accent-color1: #0a58ca;
}

/*Papier. Dieselbe Palette wie oben, nur fuer Weiss statt Glas: der Druckdienst setzt die Klasse
  auf das <html> des Druckdokuments (printService.js), alles was den Variablen folgt, faerbt sich
  damit um. Wer oben eine Variable ergaenzt, ergaenzt sie hier gleich mit.

  Es ist eine Vorgabe, keine Vorschrift: ein Component, das auf Papier anders aussehen soll, sagt
  das in seiner eigenen Css in @media print - die Regeln wandern mit den Stylesheets in das
  Druckdokument und stechen die Palette. Nur die Groesse gehoert nicht dorthin, die misst der
  Druckdienst am lebenden Element, bevor er klont.*/
html.uhl-print {
    --std-headerfooter-color: #FFFFFF;
    --std-background-color: #FFFFFF;
    --std-background-gradient: none;
    --std-border-color: #B4B4B4;
    --std-border-color-t50: rgba(180, 180, 180, 0.5);
    --std-white-color: #000000;
    --std-black-color: #000000;
    --std-darkgray-color: #F2F2F2;
    --std-gray-color: #505050;
    /*Signalfarben bleiben, wie sie sind - Rot bedeutet auf Papier dasselbe wie am Schirm.
      Eine Ausnahme: das helle Blau ist fuer dunklen Grund gemacht und stuende auf Weiss bei
      2,6:1. Auf Papier tut es das gewoehnliche Blau (6,4:1) - dieselbe Aussage, lesbar.*/
    --std-lightblue-color: #0a58ca;
}

    html.uhl-print, html.uhl-print body {
        height: auto;
        overflow: visible;
        background: #FFFFFF;
        color: #000000;
    }

        /*Glas gibt es auf Papier nicht*/
        html.uhl-print * {
            backdrop-filter: none !important;
        }

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    height: 100%;
    margin: 0;
    overflow: hidden;
}

/*Grundgroesse 14px statt der 16px des Browsers. An einer Anlagenvisu steht man nicht mit der Nase
  vorm Bildschirm, dafuer passt mehr aufs Bild. Bootstrap und das Kendo-Thema rechnen beide in rem,
  Abstaende und Schrift folgen deshalb gemeinsam. Feste px-Groessen (Schaltflaechen, Kopfzeile,
  Zeilenhoehe der Grids) bleiben, wo sie sind - die haengen an Bedienbarkeit, nicht am Text.*/
html {
    font-size: 14px;
}

body {
    color: white;
    height: 100%;
    /*background: var(--std-background-gradient);*/
    background: var(--std-background-color);
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-size: 100% 100%;
}

/*Hell genug fuer den dunklen Grund - das alte #c02d76 war dort kaum zu lesen*/
code {
    color: #E685B5;
}

    /*Auf Papier umgekehrt: dort ginge die helle Rose auf Weiss unter*/
    html.uhl-print code {
        color: #c02d76;
    }

h1:focus {
    outline: none;
}

.content {
    padding-top: 1.1rem;
}

/*#################################################*/
/*Std components*/
/*#################################################*/

/*std-layout*/
.std-page-scroll {
    overflow-x: hidden;
    overflow-y: auto;
}

.std-page-full {
    overflow: hidden;
    height: 100%;
}

.std-border {
    border: 1px solid var(--std-border-color);
}

/*std-button

  Dieselbe Sprache wie Popup, Tooltip und die Meldungsschilder: durchscheinende Flaeche mit
  unscharfem Grund dahinter und hellem Rand, statt eines flaechigen Volltons. Der Rand liegt als
  inset-Schatten darin und nicht als border - so bleibt der Knopf exakt 34x34, egal ob er gerade
  einen Rand zeigt oder nicht. 34 wie die Hoehe von .std-input-field: Knopf und Eingabefeld stehen
  oft in derselben Zeile. Die Seitennavigation bleibt groesser (.std-button-navigation-size).*/
.std-button {
    display: flex;
    height: 34px;
    width: 34px;
    background: transparent;
    border-radius: 8px;
    font-size: 0.9rem;
    cursor: pointer;
    transition: background .15s ease-out, box-shadow .15s ease-out, filter .15s ease-out;
    overflow: hidden;
}

    /*Aufhellen statt Wachsen (Ansage des Users, 02.09.2026): der Knopf wuchs beim Ueberfahren auf
      105 % und schrumpfte beim Druecken auf 95 %. Das schob in einer Leiste die Nachbarn optisch
      beiseite und liess ein Bild flimmern. Jetzt hebt sich die Flaeche selbst an - das trifft auch
      einen farbig gefuellten Knopf, dem die Glasflaeche nichts anhaben kann -, und der Rand ist
      nur noch eine Andeutung (1px, 25 % Weiss). Im WPF ist es derselbe Umbau: eine duenne weisse
      Lage ueber dem Inhalt, siehe StdButton.xaml.*/
    .std-button:hover {
        background: color-mix(in srgb, var(--std-accent-color1) 55%, transparent);
        backdrop-filter: blur(8px) saturate(1.2);
        box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--std-white-color) 25%, transparent),
                    0 4px 14px rgba(0, 0, 0, .4);
        filter: brightness(1.12);
    }

    /*Der Druckpunkt geht in die andere Richtung: eine Spur dunkler statt kleiner*/
    .std-button:active {
        filter: brightness(0.85);
    }

    .std-button[aria-disabled="true"] {
        opacity: 0.5;
        pointer-events: none;
        cursor: not-allowed; /*won't work because of pointer-events: none, solution with js is possible*/
        filter: grayscale(100%);
    }

/*Nur der Halteknopf (OnPressedChanged): ohne touch-action wuerde ein Wisch, der auf dem Knopf
  beginnt, zum Scrollen und braeche das Halten ueber pointercancel sofort ab. Bewusst nicht an
  jedem Knopf - sonst liesse sich eine Seite nicht mehr von jedem Knopf aus scrollen.*/
.std-button-holdable {
    touch-action: none;
}

.std-button-content {
    display: flex;
    flex-grow: 1;
    justify-content: center;
    align-items: center;
    gap: 6px;
    overflow: hidden;
    user-select: none;
}

/*Ein Bild als Knopfinhalt behaelt sein Seitenverhaeltnis: der quadratische Knopf sieht davon
  nichts, ein Knopf mit eigener Breite/Hoehe zerrte das Bild sonst auf seine Form.*/
img.std-button-content {
    object-fit: contain;
}

/*Eine Bilddatei als Form statt als Bild (Button.Mask): das Bild schneidet nur aus, gezeichnet
  wird die Flaeche darunter in currentColor - die Farbe entscheidet also der Knopf und nicht die
  Datei. Seit dem 01.09.2026 die Ausweichloesung und nicht mehr der Weg: die Bilder des Hauses
  sind Zeichen aus Components/Icons, die brauchen keine Maske. Gedacht ist das hier noch fuer ein
  einfarbiges Bild aus einem Projekt, das kein Zeichen werden soll.
  Der Pfad selbst steht inline am Element, er kommt von der Aufrufstelle.
  -webkit- bleibt stehen: Safari kennt mask-image ohne Praefix erst ab 15.4.*/
.std-button-mask {
    flex: 0 0 auto;
    background-color: currentColor;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

/*Ein Knopf mit Beschriftung waechst auf deren Breite, bleibt aber mindestens quadratisch - wie
  .std-toggle-button, das dasselbe fuer seinen Fall tut. Siehe Components/Buttons/Button.razor.*/
.std-button-wide {
    width: fit-content;
    min-width: 34px;
}

    .std-button-wide > .std-button-content {
        padding: 0 10px;
    }

/*std-toggle-button: a std-button that carries a state. Grows with its caption, an icon-only one
  stays square*/
.std-toggle-button {
    width: fit-content;
    min-width: 34px;
}

    .std-toggle-button > .std-button-content {
        padding: 0 10px;
    }

/*Pressed look instead of just a colour: :hover of .std-button already paints the accent colour,
  the two states have to stay distinguishable*/
.std-toggle-button-selected {
    background: var(--std-accent-color1);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, .45);
}

    .std-toggle-button-selected:hover {
        background: color-mix(in srgb, var(--std-accent-color1) 82%, #fff 18%);
    }

.std-button-size {
    width: 34px;
    height: 34px;
}

.std-button-navigation-size {
    width: 48px;
    height: 48px;
}

/*Navigationsknopf (NavigationLink und AuthorizedNavigationLink). Global und nicht in einer scoped
  Css: die gilt je Datei, die beiden Components sind zwei - eine scoped Fassung musste doppelt
  gepflegt werden und lief prompt auseinander.

  Optik wie .std-button, siehe dort auch, warum der Rand ein inset-Schatten ist.*/
.std-navlink {
    border-radius: 8px;
    user-select: none;
    transition: background .15s ease-out, box-shadow .15s ease-out;
}

    .std-navlink:hover {
        background: color-mix(in srgb, var(--std-accent-color1) 55%, transparent);
        backdrop-filter: blur(8px) saturate(1.2);
        box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--std-white-color) 20%, transparent),
                    0 4px 14px rgba(0, 0, 0, .4);
        cursor: pointer;
    }

    .std-navlink[aria-disabled="true"] {
        opacity: .5;
        pointer-events: none;
        filter: grayscale(100%);
    }

/*Die aktuelle Seite steht kraeftiger da als ein blosses Ueberfahren - sonst waeren die beiden
  Zustaende nicht zu unterscheiden*/
.std-navlink-active {
    background: color-mix(in srgb, var(--std-accent-color1) 72%, transparent);
    backdrop-filter: blur(8px) saturate(1.2);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--std-white-color) 26%, transparent);
}

/*std-input - shared by TextBox and NumericTextBox, therefore here and not in a scoped css.
  Height and border colour like the Kendo inputs still standing next to them, otherwise they sit
  two pixels offset in the same row.*/
/*relative als Bezug fuer alles, was im Feld absolut sitzt. Das Schild der Eingabepruefung gehoert
  seit 02.09.2026 nicht mehr dazu - es ist fixed, siehe .std-input-hint*/
.std-input {
    position: relative;
    display: inline-block;
    min-width: 0;
}

/*Weiss mit schwarzer Schrift wie im WPF-Standard, ReadOnly dunkel - siehe unten. Die Schriftfarbe
  steht hier und nicht am Eingabefeld: Eingabe, Platzhalter und Pfeile erben sie ueber currentColor.
  So genuegt es, sie am Feld umzusetzen.*/
.std-input-field {
    display: flex;
    align-items: stretch;
    height: 34px;
    border: 1px solid color-mix(in srgb, var(--std-border-color) 81%, #fff 19%);
    border-radius: 6px;
    background: var(--std-white-color);
    color: var(--std-black-color);
    overflow: hidden;
    transition: border-color .12s ease-out, box-shadow .12s ease-out;
}

    .std-input-field:focus-within {
        border-color: var(--std-accent-color1);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-accent-color1) 25%, transparent);
    }

.std-input-field-disabled {
    opacity: .5;
}

/*Farbe des Feldes und Farbe des Schildes sind getrennt, und das ist der Punkt: rot wird das Feld
  nur, solange die Eingabe darin wirklich daneben liegt. Steht wieder ein gueltiger Wert darin und
  das Schild erklaert nur noch, warum es nicht der eingegebene ist, bleibt das Feld unauffaellig -
  das Schild aber rot, denn es ist eine Meldung und soll auffallen.

  Der rote Rahmen gewinnt auch im Fokus, sonst waere die Markierung genau dann weg, wenn der
  Anwender im Feld steht und sie am ehesten braucht.*/
.std-input-field-invalid {
    border-color: var(--std-red-color);
    background: color-mix(in srgb, var(--std-red-color) 7%, var(--std-white-color));
}

    .std-input-field-invalid:focus-within {
        border-color: var(--std-red-color);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-red-color) 30%, transparent);
    }

/*ReadOnly wie im WPF-Standard: dunkel mit weisser Schrift - ein Wert zum Ansehen, nicht zum
  Bearbeiten. Nach -invalid, damit ein nur lesbares Feld nie rot einfaerbt.*/
.std-input-field-readonly {
    background: var(--std-input-readonly-background);
    color: var(--std-white-color);
}

/*Deckende rote Flaeche mit weisser Schrift: eine duenne rote Zeile geht neben einem Formular
  unter, ein Schild wird gelesen. Die Spitze zeigt auf das Feld, damit klar ist, wozu es gehoert.

  Ausserhalb des Flusses, damit es keine Hoehe kostet - sonst spraenge ein ganzes Formular, sobald
  eine einzige Eingabe daneben liegt. pointer-events: none laesst Klicks darunter durch.

  Seit 02.09.2026 fixed und aus JavaScript platziert (uhltronixBlazor.inputHint, das Component
  Components/Input/InputHint.razor) statt absolut unter dem Feld: absolut schnitt es jeder Vorfahr
  mit overflow:hidden oder auto ab - in einer Liste oder einem Gitter also immer. Derselbe Weg wie
  bei Popup, Tooltip und dem Aufklappteil des DateTimePicker. Bis die Lage gerechnet ist, steht es
  ausserhalb des Bildes statt in der linken Ecke.*/
.std-input-hint {
    position: fixed;
    top: -9999px;
    left: -9999px;
    z-index: 100200;
    padding: 5px 10px;
    border: 1px solid color-mix(in srgb, var(--std-white-color) 24%, transparent);
    border-radius: 6px;
    background: color-mix(in srgb, var(--std-red-color) 82%, transparent);
    backdrop-filter: blur(10px) saturate(1.2);
    box-shadow: 0 8px 20px rgba(0, 0, 0, .55);
    color: var(--std-white-color);
    font-size: .85rem;
    line-height: 1.3;
    white-space: nowrap;
    pointer-events: none;
    animation: uhl-input-hint-in .12s ease-out;
}

    /*Zwei Lagen: die aeussere sitzt auf dem Glasrand, die innere traegt die Farbe - eine einzelne
      Spitze haette dort einen kahlen Rand, wo der Kasten ringsum seinen hat*/
    .std-input-hint::before,
    .std-input-hint::after {
        content: "";
        position: absolute;
        bottom: 100%;
        right: 11px;
        border: 6px solid transparent;
        border-bottom-color: color-mix(in srgb, var(--std-white-color) 24%, transparent);
    }

    .std-input-hint::after {
        right: 12px;
        border-width: 5px;
        border-bottom-color: color-mix(in srgb, var(--std-red-color) 82%, transparent);
    }

/*Nur die Deckkraft, kein Hineingleiten mehr (02.09.2026): die Lage rechnet jetzt JavaScript, und
  es misst das Schild unmittelbar nach dem Zeichnen - also mitten in der Bewegung. Die drei Pixel
  des translateY landeten damit in der berechneten Lage und blieben nach dem Ende der Bewegung
  stehen.*/
@keyframes uhl-input-hint-in {
    from {
        opacity: 0;
    }
}

/*Text steht links, Zahlen stehen rechts (siehe -numeric). Beides ausdruecklich und nicht dem
  Erben ueberlassen: in einer mittig gesetzten Zelle - einer Grid-Spalte etwa - wanderte der
  Feldinhalt sonst mit, und zwei gleiche Felder saehen je nach Umgebung verschieden aus.*/
.std-input-element {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0 9px;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    outline: none;
}

    .std-input-element::placeholder {
        color: currentColor;
        opacity: .45;
    }

    .std-input-element:disabled {
        cursor: not-allowed;
    }

.std-input-element-numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/*uhl-icon: without a size it follows the font size, and it always follows the text colour because
  it is drawn in currentColor*/
.uhl-icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    flex: 0 0 auto;
}

/*std-checkbox: the native input drawn ourselves - appearance:none keeps the semantics and lets
  everything be styled at one element. The root is a label, so content beside the box toggles on
  click; margin 0 because the browser default would push a bare box out of line.*/
.std-checkbox {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    cursor: pointer;
    user-select: none;
}

    /*The whole label follows the lock of the input inside, not only the box*/
    .std-checkbox:has(.std-checkbox-input:disabled) {
        cursor: not-allowed;
    }

    .std-checkbox:has(.std-checkbox-readonly) {
        cursor: default;
    }

.std-checkbox-input {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin: 0;
    border: 1px solid color-mix(in srgb, var(--std-border-color) 81%, #fff 19%);
    border-radius: 4px;
    /*White with a black tick like the WPF standard; the tick follows the colour via currentColor,
      so the ReadOnly state only has to swap the two at the input*/
    background: var(--std-white-color);
    color: var(--std-black-color);
    cursor: pointer;
    transition: background .12s ease-out, border-color .12s ease-out;
}

    .std-checkbox-input:focus-visible {
        outline: none;
        border-color: var(--std-accent-color1);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-accent-color1) 25%, transparent);
    }

        /*The tick is an L rotated by 45 degrees. Its ink sits in the lower right of its own box,
          after the rotation about a tenth of the height below the centre - the -60% takes that
          back, otherwise the tick hangs visibly low in the box. The percentages keep it centred
          whatever size the box has.*/
        .std-checkbox-input:checked::after {
            content: "";
            position: absolute;
            left: 50%;
            top: 50%;
            width: 4px;
            height: 8px;
            border: solid currentColor;
            border-width: 0 2px 2px 0;
            transform: translate(-50%, -60%) rotate(45deg);
        }

    /*After the tick, so it wins where both are set*/
    .std-checkbox-input.std-checkbox-indeterminate::after {
        content: "";
        position: absolute;
        left: 50%;
        top: 50%;
        width: 10px;
        height: 2px;
        border: none;
        background: currentColor;
        transform: translate(-50%, -50%);
    }

    .std-checkbox-input:disabled {
        opacity: .5;
        cursor: not-allowed;
    }

    /*ReadOnly wie die Eingabefelder: dunkel mit weissem Haken, nur ansehen*/
    .std-checkbox-input.std-checkbox-readonly {
        background: var(--std-input-readonly-background);
        color: var(--std-white-color);
        cursor: default;
    }

/*std-radio: the checkbox drawn round. Lives only inside the RadioGroup - the group owns the value,
  which is why there is no standalone RadioButton component.*/
.std-radiogroup-items {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 18px;
    /*Same height as the fields, so a group beside a TextBox does not sit offset in the row*/
    min-height: 34px;
}

/*Das Schild haengt an der RadioGroup links und nicht rechts wie an den Feldern. Der Grund ist die
  Breite: ein Feld fuellt seine Wurzel aus, das Schild klebt an seiner rechten Kante und damit am
  Feld. Eine Gruppe fuellt sie **nicht** - sie steht links, der Rest der Zelle bleibt leer -, ein
  rechts gehaengtes Schild landete deshalb am Ende der Zeile, weit weg von den Radios, auf die es
  zeigt. Links ist der Anfang der Gruppe und damit der einzige verlaessliche Bezug.

  Die Seite selbst rechnet seit 02.09.2026 das JavaScript (InputHint.AlignLeft) - hier steht nur
  noch, wo die Spitze sitzt. Deshalb an einer eigenen Klasse und nicht mehr am Elternteil: das
  Schild ist fixed und muss nicht mehr im Baum der Gruppe stehen, um zu ihr zu gehoeren.*/
    /*Die Spitze wandert mit, sonst zeigte sie ins Leere*/
    .std-input-hint-left::before {
        right: auto;
        left: 11px;
    }

    .std-input-hint-left::after {
        right: auto;
        left: 12px;
    }

.std-radiogroup-vertical {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    min-height: 0;
}

.std-radio {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    cursor: pointer;
    user-select: none;
}

/*On the label and not on the input: the caption has to gray out with it*/
.std-radio-disabled {
    opacity: .5;
    cursor: not-allowed;
}

/*ReadOnly wie die Eingabefelder: dunkel mit weissem Punkt, nur ansehen*/
.std-radio-readonly {
    cursor: default;
}

    .std-radio-readonly .std-radio-input {
        background: var(--std-input-readonly-background);
        color: var(--std-white-color);
    }

.std-radio-input {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin: 0;
    border: 1px solid color-mix(in srgb, var(--std-border-color) 81%, #fff 19%);
    border-radius: 50%;
    /*White with a black dot, like the checkbox beside it*/
    background: var(--std-white-color);
    color: var(--std-black-color);
    cursor: inherit;
    transition: background .12s ease-out, border-color .12s ease-out;
}

    .std-radio-input:focus-visible {
        outline: none;
        border-color: var(--std-accent-color1);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-accent-color1) 25%, transparent);
    }

        .std-radio-input:checked::after {
            content: "";
            position: absolute;
            left: 50%;
            top: 50%;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background: currentColor;
            transform: translate(-50%, -50%);
        }

/*std-slider: the native range input drawn ourselves, like the checkbox. The filled part of the
  track comes from --uhl-slider-fill, which the component recomputes with the value - Chrome has
  no track progress of its own.*/
.std-slider {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 140px;
    /*Same height as the fields, so a slider beside a TextBox does not sit offset in the row*/
    min-height: 34px;
    color: var(--std-white-color);
}

.std-slider-input {
    appearance: none;
    -webkit-appearance: none;
    flex: 1 1 auto;
    min-width: 0;
    /*Taller than the track: this is the hit area for finger and mouse*/
    height: 18px;
    margin: 0;
    background: transparent;
    cursor: pointer;
}

    .std-slider-input:disabled {
        opacity: .5;
        cursor: not-allowed;
    }

    /*ReadOnly wie die Eingabefelder: dunkler Griff, nicht anfassbar. pointer-events sperrt die
      Maus, das tabindex -1 im Markup die Tastatur - ein readonly kennt type=range nicht.*/
    .std-slider-input.std-slider-readonly {
        pointer-events: none;
    }

        .std-slider-input.std-slider-readonly::-webkit-slider-thumb {
            border-color: var(--std-white-color);
            background: var(--std-input-readonly-background);
        }

        .std-slider-input.std-slider-readonly::-moz-range-thumb {
            border-color: var(--std-white-color);
            background: var(--std-input-readonly-background);
        }

    .std-slider-input:focus-visible {
        outline: none;
    }

    .std-slider-input::-webkit-slider-runnable-track {
        height: 6px;
        border-radius: 3px;
        background: linear-gradient(to right,
            var(--std-accent-color1) var(--uhl-slider-fill, 0%),
            color-mix(in srgb, var(--std-border-color) 81%, #fff 19%) var(--uhl-slider-fill, 0%));
    }

    .std-slider-input::-moz-range-track {
        height: 6px;
        border-radius: 3px;
        background: color-mix(in srgb, var(--std-border-color) 81%, #fff 19%);
    }

    .std-slider-input::-moz-range-progress {
        height: 6px;
        border-radius: 3px;
        background: var(--std-accent-color1);
    }

    /*The thumb is the radio circle on the track*/
    .std-slider-input::-webkit-slider-thumb {
        appearance: none;
        -webkit-appearance: none;
        width: 18px;
        height: 18px;
        /*(thumb - track) / 2: webkit puts the thumb on the upper track edge*/
        margin-top: -6px;
        border: 1px solid color-mix(in srgb, var(--std-accent-color1) 60%, #fff 40%);
        border-radius: 50%;
        background: var(--std-accent-color1);
        transition: box-shadow .12s ease-out;
    }

    .std-slider-input::-moz-range-thumb {
        width: 18px;
        height: 18px;
        border: 1px solid color-mix(in srgb, var(--std-accent-color1) 60%, #fff 40%);
        border-radius: 50%;
        background: var(--std-accent-color1);
        transition: box-shadow .12s ease-out;
    }

    .std-slider-input:focus-visible::-webkit-slider-thumb {
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-accent-color1) 25%, transparent);
    }

    .std-slider-input:focus-visible::-moz-range-thumb {
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-accent-color1) 25%, transparent);
    }

/*Tabular digits, so the text does not wobble while dragging*/
.std-slider-value {
    flex: 0 0 auto;
    min-width: 3.5ch;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/*Senkrecht (Vertical): writing-mode dreht das native Feld, direction:rtl legt das Kleine nach
  unten. Der alte Weg -webkit-appearance:slider-vertical vertraegt sich nicht mit appearance:none,
  mit dem wir die Bahn ja selbst zeichnen. Die Fuellung laeuft dann von unten nach oben, sonst
  faerbte sie die falsche Haelfte.*/
.std-slider-vertical {
    flex-direction: column;
    width: fit-content;
    min-width: 34px;
    min-height: 140px;
}

    .std-slider-vertical .std-slider-input {
        writing-mode: vertical-lr;
        direction: rtl;
        flex: 1 1 auto;
        width: 18px;
        height: auto;
        min-height: 0;
    }

    .std-slider-vertical .std-slider-input::-webkit-slider-runnable-track {
        width: 6px;
        height: 100%;
        background: linear-gradient(to top,
            var(--std-accent-color1) var(--uhl-slider-fill, 0%),
            color-mix(in srgb, var(--std-border-color) 81%, #fff 19%) var(--uhl-slider-fill, 0%));
    }

    .std-slider-vertical .std-slider-input::-moz-range-track {
        width: 6px;
    }

    /*Waagerecht schiebt der Rand den Griff auf die Bahnmitte - senkrecht ist es der linke*/
    .std-slider-vertical .std-slider-input::-webkit-slider-thumb {
        margin-top: 0;
        margin-left: -6px;
    }

    .std-slider-vertical .std-slider-value {
        text-align: center;
    }

/*std-status: the signal lamp, counterpart of StatusEllipse/StatusRectangle in UhltronixWpf. The
  state colour arrives as `color`, so surface, gloss and glow all take it through currentColor and
  one change travels everywhere by itself.*/
.std-status {
    position: relative;
    display: inline-block;
    flex: 0 0 auto;
    background: currentColor;
    /*Nothing here animates the colour: a lamp that fades between red and green is unreadable in the
      moment it matters*/
}

.std-status-ellipse {
    border-radius: 50%;
}

.std-status-rounded {
    border-radius: 4px;
}

/*The gloss over the upper three quarters, exactly as the Wpf template draws it - that is what makes
  the surface read as a lamp instead of a coloured box. border-radius: inherit lets it follow the
  shape: on the ellipse the smaller box becomes an ellipse again.*/
.std-status::after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    height: 75%;
    border-radius: inherit;
    background: rgba(255, 255, 255, .15);
    pointer-events: none;
}

/*Behind the shape and in its colour - the same language the connection symbol speaks*/
.std-status-glow::before {
    content: "";
    position: absolute;
    inset: -60%;
    border-radius: 50%;
    background: radial-gradient(circle, currentColor 0%, transparent 65%);
    opacity: .5;
    pointer-events: none;
}

.std-status-inactive {
    opacity: .4;
}

.std-status-blink {
    animation: uhl-status-blink 1s steps(1, end) infinite;
}

/*steps and not a fade: a lamp is on or off, and half brightness says nothing*/
@keyframes uhl-status-blink {
    0%, 50% {
        opacity: 1;
    }

    50.01%, 100% {
        opacity: .25;
    }
}

/*std-gauge: RadialGauge and LinearGauge share their looks - the round one is the straight one
  rolled up, and two instruments beside each other must read the same. Everything that carries a
  state colour gets it inline from the component; what stays neutral stands here.*/
.std-gauge {
    display: inline-block;
    color: var(--std-white-color);
    --std-gauge-background: color-mix(in srgb, var(--std-background-color) 62%, var(--std-black-color));
}

.std-gauge-svg {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}

/*The dark ground behind the scale - darker than the page, so the instrument reads as recessed*/
.std-gauge-background {
    fill: var(--std-gauge-background);
    stroke: var(--std-border-color);
    stroke-width: 1;
}

/*The unfilled scale - present but quiet, it is the backdrop and not the reading*/
.std-gauge-track {
    fill: none;
    stroke: var(--std-border-color);
}

/*In the LinearGauge the track is a bar, not a stroked arc*/
rect.std-gauge-track {
    fill: var(--std-border-color);
    stroke: none;
}

.std-gauge-tick {
    stroke: currentColor;
    stroke-width: 1.6;
    opacity: .75;
}

.std-gauge-tick-minor {
    stroke: currentColor;
    stroke-width: 1;
    opacity: .35;
}

.std-gauge-tick-label {
    fill: currentColor;
    font-size: 11px;
    opacity: .7;
}

/*Tabular digits, so the reading does not wobble while the value runs*/
.std-gauge-value {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.std-gauge-caption {
    fill: currentColor;
    opacity: .6;
}

.std-gauge-needle {
    stroke: none;
}

/*The linear marker rides on the coloured bands - the dark outline keeps it visible where
  band and marker share a colour*/
.std-gauge-marker {
    stroke: var(--std-gauge-background);
    stroke-width: 1;
    stroke-linejoin: round;
}

/*Dark like the ground behind, so the pivot reads as a hole and not as a dot on top of the needle*/
.std-gauge-hub {
    fill: var(--std-gauge-background);
    stroke: currentColor;
    stroke-width: 1.5;
    opacity: .9;
}

/*std-progressbar: the slider track with a filling instead of a thumb - pure display*/
.std-progressbar {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 140px;
    color: var(--std-white-color);
}

.std-progressbar-track {
    flex: 1 1 auto;
    min-width: 0;
    height: 10px;
    border-radius: 5px;
    background: color-mix(in srgb, var(--std-border-color) 81%, #fff 19%);
    overflow: hidden;
}

.std-progressbar-fill {
    height: 100%;
    /*The radius comes from the clipping track, so a filling near 0% is not a lens-shaped sliver*/
    background: var(--std-accent-color1);
    transition: width .2s ease-out, background .2s ease-out;
}

/*Like the slider caption - the two stand in the same rows*/
.std-progressbar-value {
    flex: 0 0 auto;
    min-width: 3.5ch;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/*Set by uhltronixBlazor.scroll.intoViewByText on the section it jumped to - without it a jump into
  the middle of a long page leaves the reader guessing which box was meant.*/
.uhl-scroll-flash {
    animation: uhl-scroll-flash 1.1s ease-out;
}

@keyframes uhl-scroll-flash {
    from {
        box-shadow: 0 0 0 2px var(--std-accent-color1), 0 0 20px color-mix(in srgb, var(--std-accent-color1) 55%, transparent);
    }

    to {
        box-shadow: 0 0 0 2px transparent, 0 0 20px transparent;
    }
}

/*std-stackpanel: the two rules are Bootstrap's hstack and vstack verbatim, so replacing those divs
  with the component changes no pixel. Gap and wrapping come inline from the component.*/
.std-stackpanel-horizontal {
    display: flex;
    flex-direction: row;
    align-items: center;
    align-self: stretch;
}

.std-stackpanel-vertical {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    align-self: stretch;
}

/*std-combobox: the field with free text - the list optics come from std-dropdown. The toggle is
  wider than the arrow it draws, a border triangle alone is no click target.*/
.std-combobox-toggle {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    align-self: stretch;
    padding: 0 2px;
    cursor: pointer;
}

/*std-menu: the action list of MenuButton and ContextMenu. Global because two components share it,
  the glass surface underneath comes from the Popup.*/
.std-menu {
    padding: 4px;
    min-width: 170px;
}

.std-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 8px;
    border-radius: 6px;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
}

    .std-menu-item:hover {
        background: color-mix(in srgb, currentColor 14%, transparent);
    }

.std-menu-item-disabled {
    opacity: .5;
    cursor: not-allowed;
}

    .std-menu-item-disabled:hover {
        background: transparent;
    }

/*Always there, even empty: the captions align when only some entries carry an icon*/
.std-menu-item-icon {
    flex: 0 0 auto;
    display: inline-flex;
    justify-content: center;
    width: 18px;
}

.std-menu-separator {
    height: 1px;
    margin: 4px 6px;
    background: color-mix(in srgb, var(--std-white-color) 13%, transparent);
}

.std-menubutton {
    display: inline-flex;
}

/*std-fileupload: selection only - the caller reads the streams. The native input covers the whole
  zone, which is what makes click and drop work without any script.*/
.std-fileupload {
    display: block;
    min-width: 220px;
}

.std-fileupload-zone {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0;
    padding: 18px 14px;
    border: 1px dashed color-mix(in srgb, var(--std-border-color) 60%, #fff 40%);
    border-radius: 8px;
    background: color-mix(in srgb, var(--std-white-color) 3%, transparent);
    color: var(--std-white-color);
    cursor: pointer;
    user-select: none;
    transition: border-color .12s ease-out, background .12s ease-out;
}

    .std-fileupload-zone:hover,
    .std-fileupload-dragover {
        border-color: var(--std-accent-color1);
        background: color-mix(in srgb, var(--std-accent-color1) 10%, transparent);
    }

    .std-fileupload-zone input[type=file] {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        opacity: 0;
        cursor: pointer;
    }

.std-fileupload-disabled .std-fileupload-zone {
    opacity: .5;
    cursor: not-allowed;
}

    .std-fileupload-disabled .std-fileupload-zone input[type=file] {
        cursor: not-allowed;
    }

.std-fileupload-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 8px;
}

.std-fileupload-file {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 10px;
    border: 1px solid color-mix(in srgb, var(--std-border-color) 81%, #fff 19%);
    border-radius: 6px;
    background: var(--std-background-color);
}

.std-fileupload-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.std-fileupload-size {
    flex: 0 0 auto;
    opacity: .7;
    font-variant-numeric: tabular-nums;
}

.std-fileupload-remove {
    flex: 0 0 auto;
    display: inline-flex;
    padding: 3px;
    border-radius: 4px;
    opacity: .7;
    cursor: pointer;
}

    .std-fileupload-remove:hover {
        opacity: 1;
        background: color-mix(in srgb, currentColor 14%, transparent);
    }

/*std-dropdown: the closed field looks like an input, the list lives in a Popup*/
.std-dropdown-field {
    align-items: center;
    cursor: pointer;
    user-select: none;
}

    .std-dropdown-field:focus {
        outline: none;
        border-color: var(--std-accent-color1);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--std-accent-color1) 25%, transparent);
    }

.std-dropdown-text {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0 9px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.std-dropdown-empty {
    opacity: .45;
}

/*Ein ItemTemplate zeichnet ein Bild oder mehr. Ein Auslassungszeichen ergibt dort keinen Sinn -
  und es erscheint schon, wenn der Inhalt einen Pixel zu breit ist.*/
.std-dropdown-text-template {
    display: flex;
    align-items: center;
    text-overflow: clip;
}

.std-dropdown-arrow {
    flex: 0 0 auto;
    width: 0;
    height: 0;
    margin: 0 9px 0 3px;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    opacity: .7;
}

/*Die aufgeklappte Liste traegt dieselben Farben wie das Feld darueber - weiss mit schwarzer
  Schrift. Vorher stand ueber dem hellen Feld eine dunkle Liste, und die beiden sahen aus wie zwei
  verschiedene Dinge. Betrifft DropDownList und ComboBox gemeinsam, sie teilen sich die Klasse.
  Ohne das Glas des uhl-popup: eine weisse Flaeche mit Unschaerfe dahinter wird milchig.*/
/*!important, weil die Grundfarben aus der isolierten Css des Popup kommen: dort steht .uhl-popup
  mit seiner Scope-Kennung und ist damit spezifischer als eine blosse Klasse von hier. Die Regel in
  Popup.razor.css zu ergaenzen waere der andere Weg - dann wuesste das Popup aber von seinen
  Benutzern, und das soll es nicht.*/
.std-dropdown-popup {
    border-color: color-mix(in srgb, var(--std-border-color) 81%, #fff 19%) !important;
    background: var(--std-white-color) !important;
    color: var(--std-black-color);
    backdrop-filter: none !important;
}

.std-dropdown-list {
    max-height: 320px;
    overflow-y: auto;
    padding: 4px;
}

.std-dropdown-item {
    padding: 5px 10px;
    border-radius: 6px;
    white-space: nowrap;
    cursor: pointer;
}

    /*currentColor ist jetzt schwarz - 14% davon waere ein kaum sichtbarer Grauschleier*/
    .std-dropdown-item:hover,
    .std-dropdown-item-highlight {
        background: color-mix(in srgb, var(--std-accent-color1) 14%, transparent);
    }

/*Der gewaehlte Eintrag bleibt blau, braucht auf hellem Grund aber seine eigene Schriftfarbe -
  sonst stuende schwarz auf blau*/
.std-dropdown-item-selected {
    background: var(--std-accent-color1);
    color: var(--std-white-color);
    font-weight: 600;
}

    .std-dropdown-item-selected:hover {
        background: color-mix(in srgb, var(--std-accent-color1) 82%, #fff 18%);
        color: var(--std-white-color);
    }

/*Multiline: the height comes from the rows of the textarea, the fixed 34px of the field would cut
  it off*/
.std-input-field-multiline {
    height: auto;
}

.std-input-element-multiline {
    padding: 6px 9px;
    line-height: 1.35;
    /*vertical only - horizontally the field follows its surroundings*/
    resize: vertical;
}

/*Spin buttons of the NumericTextBox, stacked in the field*/
.std-input-arrows {
    display: flex;
    flex-direction: column;
    flex: 0 0 auto;
    width: 20px;
    border-left: 1px solid color-mix(in srgb, currentColor 20%, transparent);
}

.std-input-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 50%;
    padding: 0;
    border: none;
    background: transparent;
    color: inherit;
    cursor: pointer;
    opacity: .7;
    transition: opacity .12s ease-out, background .12s ease-out;
}

    .std-input-arrow:hover:not(:disabled) {
        opacity: 1;
        background: color-mix(in srgb, currentColor 14%, transparent);
    }

    .std-input-arrow:disabled {
        opacity: .35;
        cursor: default;
    }

    .std-input-arrow + .std-input-arrow {
        border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent);
    }

.std-input-arrow-icon {
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
}

.std-input-arrow-up {
    border-bottom: 5px solid currentColor;
}

.std-input-arrow-down {
    border-top: 5px solid currentColor;
}

/*Std color classes*/
.std-color-headerfooter {
    color: var(--std-headerfooter-color);
}

.std-color-black {
    color: var(--std-black-color);
}

.std-color-white {
    color: var(--std-white-color);
}

.std-color-darkgray {
    color: var(--std-darkgray-color);
}

.std-color-gray {
    color: var(--std-gray-color);
}

.std-color-red {
    color: var(--std-red-color);
}

.std-color-red-t50 {
    color: var(--std-red-color-t50);
}

.std-color-orange {
    color: var(--std-orange-color);
}

.std-color-orange-t50 {
    color: var(--std-orange-color-t50);
}

.std-color-yellow {
    color: var(--std-yellow-color);
}

.std-color-yellow-t50 {
    color: var(--std-yellow-color-t50);
}

.std-color-blue {
    color: var(--std-blue-color);
}

.std-color-blue-t50 {
    color: var(--std-blue-color-t50);
}

.std-color-green {
    color: var(--std-green-color);
}

.std-color-green-t50 {
    color: var(--std-green-color-t50);
}

/*Std background classes*/
.std-bg-headerfooter {
    background: var(--std-headerfooter-color);
}

.std-bg-white {
    background: var(--std-white-color);
}

.std-bg-black {
    background: var(--std-black-color);
}

.std-bg-darkgray {
    background: var(--std-darkgray-color);
}

.std-bg-gray {
    background: var(--std-gray-color);
}

.std-bg-red {
    background: var(--std-red-color);
}

.std-bg-red-t50 {
    background: var(--std-red-color-t50);
}

.std-bg-orange {
    background: var(--std-orange-color);
}

.std-bg-orange-t50 {
    background: var(--std-orange-color-t50);
}

.std-bg-yellow {
    background: var(--std-yellow-color);
}

.std-bg-yellow-t50 {
    background: var(--std-yellow-color-t50);
}

.std-bg-blue {
    background: var(--std-blue-color);
}

.std-bg-blue-t50 {
    background: var(--std-blue-color-t50);
}

.std-bg-green {
    background: var(--std-green-color);
}

.std-bg-green-t50 {
    background: var(--std-green-color-t50);
}

/*Std animation classes*/
.std-pulse-element-1s {
    animation: pulse-fade-opacity 1s infinite alternate;
}

.std-pulse-element-2s {
    animation: pulse-fade-opacity 2s infinite alternate;
}

/*#################################################*/
/*DataGrid*/
/*#################################################*/
/*Gesetzt von dataGridService.js, solange eine Spaltenkante gezogen wird. Gehoert an den body und
  damit hierher - die scoped CSS der Komponente erreicht ihn nicht.*/
.uhl-datagrid-resizing {
    cursor: col-resize;
    user-select: none;
}

/*Inhalte aus einem Template tragen den Scope des Aufrufers, nicht den des Grids. Ein Element darin
  soll die Zelle nicht aufdruecken - die Zeilenhoehe haengt sonst am laengsten Inhalt.*/
.uhl-datagrid-cell > * {
    max-width: 100%;
    vertical-align: middle;
}


/*#################################################*/
/*Ladebild vor dem Start*/
/*#################################################*/
/*Markup in ProjectSelector/wwwroot/index.html im #app. Die Regeln stehen hier und nicht dort, weil
  sie zur Bibliothek gehoeren - ein weiterer Host bringt nur sein Markup mit. Scoped Css scheidet
  aus, das Bild steht vor dem ersten Render und traegt keinen Scope.

  --blazor-load-percentage und --blazor-load-percentage-text setzt blazor.webassembly.js waehrend
  des Ladens an das html-Element. Ohne sie greifen die Vorgaben und es bleibt beim Lichtschein.*/
.uhl-splash {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 26px;
    background: radial-gradient(60% 55% at 50% 45%, color-mix(in srgb, var(--std-accent-color1) 16%, transparent), transparent 70%), var(--std-background-color);
}

.uhl-splash-mark {
    position: relative;
    /*Das Bild ist 720x132, das Verhaeltnis haelt die drei Lagen deckungsgleich*/
    width: min(52vw, 460px);
    aspect-ratio: 720 / 132;
}

.uhl-splash-logo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

/*Grundlage: das Logo steht von der ersten Sekunde an ganz da, nur zurueckgenommen*/
.uhl-splash-logo-dim {
    opacity: .16;
}

/*Ein Lichtschein wandert ueber die Schrift: ein heller Streifen, den die Logoform als Maske
  beschneidet - ohne sie laege er quer ueber dem Hintergrund.

  Bewegt wird ein transform, und das ist keine Geschmacksfrage: Waehrend die Anwendung hochkommt,
  blockiert der Wasm-Thread den Browser fuer knapp eine Sekunde am Stueck (gemessen: 874 ms).
  transform und opacity laufen im Compositor und damit daran vorbei, alles andere - der erste
  Versuch bewegte die mask-position - braucht in jedem Bild den Hauptthread und steht still.*/
.uhl-splash-sheen {
    position: absolute;
    inset: 0;
    overflow: hidden;
    -webkit-mask-image: url(../pictures/uhltronix-logo-weiss.png);
    mask-image: url(../pictures/uhltronix-logo-weiss.png);
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}

.uhl-splash-sheen-band {
    position: absolute;
    top: 0;
    bottom: 0;
    left: -40%;
    width: 40%;
    background: linear-gradient(100deg, transparent, color-mix(in srgb, var(--std-white-color) 55%, transparent), transparent);
    /*Die Ebene steht damit schon vor der Blockade, sonst faengt die Bewegung nicht an*/
    will-change: transform;
    animation: uhl-splash-sheen 2.6s ease-in-out infinite;
}

/*Der Fortschritt macht das Logo von links nach rechts deckend*/
.uhl-splash-logo-fill {
    clip-path: inset(0 calc(100% - var(--blazor-load-percentage, 0%)) 0 0);
    transition: clip-path .15s linear;
    filter: drop-shadow(0 0 12px color-mix(in srgb, var(--std-accent-color1) 40%, transparent));
}

.uhl-splash-track {
    width: min(52vw, 460px);
    height: 2px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--std-white-color) 12%, transparent);
    overflow: hidden;
}

.uhl-splash-track-fill {
    width: var(--blazor-load-percentage, 0%);
    height: 100%;
    background: var(--std-accent-color1);
    box-shadow: 0 0 10px color-mix(in srgb, var(--std-accent-color1) 70%, transparent);
    transition: width .15s linear;
}

.uhl-splash-text {
    font-size: .8rem;
    letter-spacing: .18em;
    opacity: .5;
}

    .uhl-splash-text:after {
        content: var(--blazor-load-percentage-text, "…");
    }

/*Der Streifen ist 40 % breit und startet links daneben, bis rechts hinaus sind es 350 % davon.
  Nach dem Durchlauf eine Pause, sonst wirkt das Wandern wie ein Flackern.*/
@keyframes uhl-splash-sheen {
    0% {
        transform: translateX(0);
    }

    55%, 100% {
        transform: translateX(350%);
    }
}

/*Zweiter Auftritt desselben Bildes: SplashScreen.razor haelt es ueber die Zeit, in der Blazor
  zwar steht, die Anwendung aber noch hochkommt. Der Ladefortschritt ist dann bei 100 - das Logo
  steht ganz da und die Spur laeuft unbestimmt, weil hier niemand die Dauer kennt.*/
.uhl-splash-app .uhl-splash-logo-fill {
    clip-path: none;
}

.uhl-splash-app .uhl-splash-track-fill {
    width: 40%;
    will-change: transform;
    animation: uhl-splash-run 1.6s ease-in-out infinite;
}

/*Dazu ein Pulsieren - erst hier, wo kein Fortschritt mehr mitzaehlt, ist es das Zeichen, dass noch
  etwas laeuft. Bewusst dieselbe Dauer wie der Lichtschein: zwei verschiedene Takte uebereinander
  machen das Bild unruhig. Nur Helligkeit, kein Skalieren - und opacity laeuft wie transform im
  Compositor weiter, wenn der Wasm-Thread gerade nichts durchlaesst.

  Es haengt an der deckenden Lage, nicht an der Grundschicht: die liegt darunter und ist hier
  vollstaendig verdeckt - dort bewegt sich etwas, das niemand sehen kann. Nach unten hin bleiben
  die 16 % der Grundschicht stehen, das Logo verschwindet also nie ganz.*/
.uhl-splash-app .uhl-splash-logo-fill {
    will-change: opacity;
    animation: uhl-splash-pulse 2.6s ease-in-out infinite;
}

/*Haelt die Zeile frei, auch wenn kein Text dasteht - sonst ruecken Logo und Spur beim Uebergang
  vom Ladebild zum Component um eine halbe Zeile nach unten*/
.uhl-splash-app .uhl-splash-text {
    /*Gemessen: die Zeile mit Prozentwert ist 17px hoch, so bleibt die Marke auf derselben Hoehe*/
    min-height: 1.55em;
}

    .uhl-splash-app .uhl-splash-text:after {
        content: none;
    }

.uhl-splash-leaving {
    opacity: 0;
    pointer-events: none;
    transition: opacity .35s ease;
}

@keyframes uhl-splash-run {
    from {
        transform: translateX(-110%);
    }

    to {
        transform: translateX(260%);
    }
}

/*Ohne Start- und Endbild: Anfang und Ende sind die volle Deckung, es nimmt sich nur kurz zurueck*/
@keyframes uhl-splash-pulse {
    50% {
        opacity: .5;
    }
}

@media (prefers-reduced-motion: reduce) {
    .uhl-splash-sheen-band {
        animation: none;
        opacity: 0;
    }

    .uhl-splash-logo-fill {
        transition: none;
    }

    .uhl-splash-track-fill {
        transition: none;
    }

    /*Das Pulsieren bleibt: es ist die vertraeglichste Bewegung und hier das einzige Zeichen,
      dass noch etwas laeuft - genauso haelt es der BusyOverlay*/
    .uhl-splash-app .uhl-splash-track-fill {
        width: 100%;
        animation: none;
        opacity: .45;
    }
}

/*#################################################*/
/*Responsive Design*/
/*#################################################*/
.desktop-app {
    display: none;
}

.mobile-app {
    display: grid;
}

.mobile-app-menu {
    position: fixed;
    top: var(--std-headerfooter-heigth);
    width: 100%;
    height: calc(100% - 50px);
    background-color: rgba(0, 0, 0, 0.8);
    color: white;
    overflow-y: auto;
    z-index: 100000;
    display: flex;
    padding: 1rem;
    transition: transform 0.3s ease-out;
    transform: translateX(-100%);
}

    .mobile-app-menu.mobile-app-menu-show {
        transform: translateX(0);
    }

/*Ein Aufklappteil, dessen Knoepfe in der Seite stehen und nicht in der Kopfzeile.

  Der Grund: .mobile-app-menu beginnt unter der Kopfzeile (top: 55px) - und genau dort steht auch
  die Knopfzeile der Ansicht. Der Inhalt des Aufklappteils liefe damit unter den Knoepfen hindurch;
  sichtbar bleiben die zwar (z-index 100100 gegen 100000), aber es sieht aus, als ueberdeckten sie
  einander. Diese Klasse schiebt den Inhalt um eine Knopfzeile nach unten.

  50px ist deren Hoehe: std-button-navigation-size mit 48px plus der Rand des Knopfes. Die 1rem
  sind die eigene Polsterung des Aufklappteils, die darueber und darunter gleich bleiben soll.

  Nicht noetig fuer ein Aufklappteil, dessen Knopf in der Kopfzeile sitzt - der Hamburger der
  MainLayout steht ueber dem top-Rand und deckt nichts zu.*/
.mobile-app-menu-below-toggler {
    padding-top: calc(1rem + 50px);
}

/*Wo keine Kopfzeile ist, faengt das Aufklappteil oben an.

  .mobile-app-menu beginnt bei top: 55px, weil dort die Kopfzeile aufhoert. Im Querformat-Vollbild
  und im echten Vollbild des Browsers gibt es die aber nicht - die 55px blieben als heller Streifen
  ueber dem Overlay stehen (gemessen am 26.08.2026 an der Chart-Seite: der Immersiv-Rahmen deckte
  0..460 in --std-background-color, das Overlay begann erst bei 55). Der Streifen sah aus, als
  gehoerte er nicht dazu.

  Die Hoehe ist dieselbe Rechnung ohne die Leisten: der ganze Schirm.

  Der Querformat-Fall gehoert in dieselbe Media-Query wie .uhl-immersive-landscape selbst: ausserhalb
  davon ist der Rahmen ein gewoehnliches Div, die Kopfzeile steht, und die 55px sind richtig.*/
.uhl-fullscreen-root:fullscreen .mobile-app-menu {
    top: 0;
    height: 100%;
}

/*Safaris Praefixfassung desselben Zustands, als eigene Regel - siehe .uhl-fullscreen-root weiter
  unten. Das Ersatz-Vollbild bringt seine eigene Fassung davon mit.*/
.uhl-fullscreen-root:-webkit-full-screen .mobile-app-menu {
    top: 0;
    height: 100%;
}

@media (orientation: landscape) and (max-height: 500px) {
    .uhl-immersive-landscape .mobile-app-menu {
        top: 0;
        height: 100%;
    }
}

.mobile-app-menu-toggler {
    display: flex;
    background-color: transparent;
    color: white;
    z-index: 100100;
    border: none;
}

    .mobile-app-menu-toggler:hover {
        color: var(--std-accent-color1);
    }

/*Dieselbe Schwelle wie der ResponsiveService, und aus demselben Grund auch mit der Hoehe: ein quer
  gehaltenes Handy ist ueber 768px breit und keine 430px hoch. Ohne den zweiten Teil zeigte es die
  Desktop-Navigation, waehrend die Ansicht dahinter (IsDesktop in C#) ihre mobile Fassung baut -
  die beiden muessen dieselbe Grenze ziehen.*/
@media (min-width: 768px) and (min-height: 500px) {
    .desktop-app {
        display: grid;
    }

    .mobile-app {
        display: none;
    }

    .mobile-app-menu {
        display: none;
    }
}

/*#################################################*/
/*Vollbild im Querformat*/
/*#################################################*/
/*Ein flacher Schirm im Querformat - das Handy, das jemand quer haelt, um mehr zu sehen. Der
  gekennzeichnete Bereich legt sich dann ueber Kopf- und Fusszeile und nimmt den ganzen Schirm,
  wie es ein Videoportal mit seinem Bild macht.

  Ueberlegen statt die Leisten auszublenden: die Hoehe des Rumpfes rechnet LayoutViewBase in C#
  aus (Fensterhoehe minus 2x55px) und schreibt sie als inline style - ausgeblendete Leisten
  liessen unten genau diese 110px als Loch stehen.

  Es haengt allein an der Media-Query und an keinem Zustand: Zuruckdrehen loest es von selbst
  wieder auf. Das echte Vollbild des Browsers geht so nicht, das verlangt eine Bedienhandlung -
  dafuer gibt es den Knopf und ResponsiveService.ToggleFullscreenAsync.*/
@media (orientation: landscape) and (max-height: 500px) {
    .uhl-immersive-landscape {
        position: fixed;
        inset: 0;
        z-index: 100150;
        background: var(--std-background-color);
    }
}

/*Der Anker fuers echte Vollbild des Browsers (ResponsiveService.ToggleFullscreenAsync). Wer eine
  Ansicht ins Vollbild schicken will, haengt diese Klasse und die @@ref an ihre Wurzel.

  Zwei Dinge, die beide schon einmal schiefgegangen sind:

  1. Ein Element im Vollbild bekommt vom Browser einen schwarzen Grund untergelegt und nicht den
     der Seite - ohne die background-Zeile saesse der Inhalt auf Schwarz.

  2. Das Element muss einen Wechsel zwischen Mobil- und Desktop-Fassung ueberleben, gehoert also
     ausserhalb des @@if. Das Vollbild macht das Fenster bildschirmgross, damit meldet die
     Media-Query am Pc "Desktop"; wird dabei der Zweig getauscht, in dem das Vollbild-Element
     steht, verlaesst der Browser das Vollbild sofort wieder - sichtbar als kurzes Flackern. Am
     Handy faellt es nie auf, dort aendert das Vollbild die Breite nicht.

  Verwendet von Chart.razor und ShiftsProcessDataFrame.razor.*/
.uhl-fullscreen-root:fullscreen {
    background: var(--std-background-color);
}

/*Safari kennt den Zustand nur unter dem Praefix. Als eigene Regel und nicht in der Liste oben:
  einen Selektor, den er nicht kennt, verwirft der Browser samt der ganzen Regel - dann saesse
  auch das echte Vollbild anderswo auf Schwarz.*/
.uhl-fullscreen-root:-webkit-full-screen {
    background: var(--std-background-color);
}

/*Ersatz-Vollbild fuer Browser ohne Vollbild-Api. Safari auf dem iPhone hat gar keines: weder
  requestFullscreen noch die Praefixfassung gibt es dort fuer ein Element, nur ein <video> darf
  gross werden. Der Knopf tat auf dem Geraet deshalb schlicht nichts.

  responsiveService.toggleFullscreen haengt diese Klasse an, wenn der Browser nichts anzubieten
  hat. Der Unterschied zum echten Vollbild: die Leisten des Browsers bleiben stehen, an die kommt
  keine Seite heran. Kopf- und Fusszeile der Anwendung sind weg, und darum geht es.

  Dieselben Werte wie .uhl-immersive-landscape - es ist derselbe Griff, nur von Hand ausgeloest
  statt vom Drehen des Geraets.*/
.uhl-fullscreen-root.uhl-fullscreen-fallback {
    position: fixed;
    inset: 0;
    z-index: 100150;
    background: var(--std-background-color);
}

/*Wie beim echten Vollbild: ohne Kopfzeile faengt das Aufklappteil oben an, sonst bleiben die
  55px als heller Streifen darueber stehen.*/
.uhl-fullscreen-root.uhl-fullscreen-fallback .mobile-app-menu {
    top: 0;
    height: 100%;
}

/*#################################################*/
/*Animations*/
/*#################################################*/
@keyframes pulse-fade-opacity {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

/*#################################################*/
/*TreeView*/
/*#################################################*/
/*Die Zeile zeigt die Hand, der Browser setzt fuer <label> aber cursor:default und ueberschreibt
  damit das geerbte pointer. Muss global stehen: die Beschriftung kommt aus dem ItemTemplate des
  Aufrufers und traegt dessen Scope, die scoped CSS des TreeView erreicht sie nicht.*/
.uhl-treeview label {
    cursor: pointer;
}

/*#################################################*/
/*Exceptions*/
/*#################################################*/
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/*Das Zeichen vor einer Anzahl in der Schlusszeile eines DataGrid: es sagt, was die nackte Zahl
  bedeutet - die anderen Aggregate tragen ihre Einheit im Wert, eine Anzahl nicht.

  Global und nicht in der isolierten Css des Gitters: die Klasse haengt an einem <Icon>, und
  dessen Svg traegt die Scope-Kennung des Icon-Components, nicht die des Gitters. Eine Regel
  drueben griffe an keiner der beiden Stellen - weder an dem Zeichen, das das Gitter selbst
  zeichnet, noch an einem aus dem FooterTemplate des Aufrufers.*/
.uhl-datagrid-aggregate-icon {
    margin-right: 5px;
    vertical-align: -2px;
    opacity: 0.7;
}
