/* ── Self-hosted fonts ─────────────────────────────────────────────────────── */
@font-face {
    font-family: 'Inter';
    src: url('/fonts/inter-latin.woff2') format('woff2');
    font-weight: 400 600;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Manrope';
    src: url('/fonts/manrope-latin.woff2') format('woff2');
    font-weight: 500 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Design tokens ─────────────────────────────────────────────────────────── */
:root {
    /* Colours */
    --color-slate:          #3A4A5C;
    --color-terracotta:     #C4633F;
    --color-anthracite:     #1F2832;
    --color-background:     #F5F7FA;
    --color-warm-light:     #EFE3DC;
    --color-text-secondary: #5B6573;
    --color-text-light:     #8B95A3;
    --color-divider:        #EEF1F4;

    /* Left-rail exception marker (#699): the one red used by every left-edge accent bar,
       status or risk context alike — never a full traffic-light. Amber/grey are secondary
       Handlungsbedarf steps used only in the status context (see docs/design/components.md). */
    --color-rail-red:   #A32D2D;
    --color-rail-amber: #854F0B;
    --color-rail-grey:  #9CA3AF;

    /* Status palette (#574): the muted traffic light introduced with the GBU list in #668.
       Colour marks Handlungsbedarf, never achievement — "erledigt" is grey, never green.
       These are surface colours (dots, text); the louder --color-rail-* values stay reserved
       for the left-edge exception marker and the danger filter state. */
    --color-status-red-fg:      #7E4636;
    --color-status-red-dot:     #B0705E;
    --color-status-amber-dot:   #C2A566;
    --color-status-neutral-dot: #B9C1C9;
    --color-status-done-dot:    #D3D9DF;

    /* Typography */
    --font-headline: 'Manrope', sans-serif;
    --font-body:     'Inter', sans-serif;

    --font-weight-regular:  400;
    --font-weight-medium:   500;
    --font-weight-semibold: 600;
    --font-weight-bold:     700;

    --line-height-tight: 1.2;
    --line-height-body:  1.6;
}

/* ── Base ──────────────────────────────────────────────────────────────────── */
html, body {
    font-family: var(--font-body);
    font-size: 16px;
    line-height: var(--line-height-body);
    color: var(--color-text-secondary);
    background-color: var(--color-background);
    margin: 0;
    padding: 0;
    /* Clip horizontal overflow without creating a scroll container.
       overflow-x: hidden would make body the sticky ancestor, breaking
       position:sticky on .top-bar (top:0) and .sa-form-action-bar (bottom:0). */
    overflow-x: clip;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-headline);
    color: var(--color-anthracite);
    line-height: var(--line-height-tight);
}

h1 { font-size: 40px; font-weight: var(--font-weight-bold); letter-spacing: -0.8px; }
h2 { font-size: 26px; font-weight: var(--font-weight-bold); letter-spacing: -0.4px; }
h3 { font-size: 16px; font-weight: var(--font-weight-semibold); }

a, .btn-link {
    color: var(--color-terracotta);
}

/* ── Seitenkopf und Kartenköpfe (#1167) ──────────────────────────────────────
   Diese Bausteine standen bisher in jeder Seite neu: derselbe 24px-Slate-Titel unter fünf
   verschiedenen Namen (.ba-, .gbu-, .er-, .ed-, .kr-page-title) in rund einem Dutzend Dateien.
   Ursache ist die Blazor-CSS-Isolation: eine Klasse aus einer .razor.css kompiliert zu
   ".klasse[b-xyz]" und greift ausschließlich in ihrer eigenen Komponente. Wer das Muster
   "wiederverwendet", indem er nur den Klassennamen ins Markup schreibt, bekommt wirkungslosen
   Code — genau so war der erste Anlauf zu #1151 grün, ohne die Seite zu verändern.

   Deshalb stehen sie hier global. Global heißt: in dieser Datei, NICHT in einer .razor.css,
   sonst greift die Isolation erneut. Siehe docs/design/components.md. */
.sa-page-title {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--color-slate);
    margin: 0 0 2px;
}

.sa-page-subtitle {
    font-size: 14px;
    color: var(--color-text-secondary);
    margin: 0;
}

/* Seitenkopf-Container (#1175): Titelblock links, Aktionen rechts. Werte des Gefahrstoffkatasters
   (.kr-page-header), das laut AGENTS.md das Vorbild ist. Bis #1175 stand dieser Container in 19
   Varianten unter 12 Präfixen in den Seiten — mit Abständen von 0 über 1rem bis 1.75rem, und
   AdminCustomers verwies auf ein nirgends definiertes --spacing-6 und hatte damit gar keinen.

   Erwartete Struktur: EIN Element für Titel und Untertitel, daneben optional die Aktionen.
   Stehen <h1> und <p> direkt im Container, setzt die Flex-Zeile sie nebeneinander. */
.sa-page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
}

@media (max-width: 640px) {
    /* Titel und Aktionen untereinander, wie im Kataster. */
    .sa-page-header {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* Dunkler Kartenkopf — die eine Variante (#1176): 11px, Versalien, Headline-Schrift, wie im
   Gefahrstoffkataster. Bis #1176 gab es daneben eine schlichte 12px-Variante ohne Versalien;
   entschieden wurde für die Kataster-Variante, weil der Kataster laut AGENTS.md das kanonische
   Vorbild ist und das freigegebene Mockup (#1124) ebenfalls Versalien vorsieht.

   Immer als Flex-Zeile: Enthält der Kopf nur Text, ändert das nichts; enthält er rechts einen
   Zähler oder Buttons, stehen die rechtsbündig. Text, der zusammenbleiben soll (Titel + Badge),
   gehört deshalb in EIN Element — sonst schiebt space-between das Badge nach außen. */
.sa-card-header {
    background-color: var(--color-slate) !important;
    color: #ffffff !important;
    font-family: var(--font-headline);
    font-size: 11px !important;
    font-weight: 600 !important;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    padding: 10px 16px !important;
    border-bottom: none !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    /* Eigener Radius, damit der Balken innerhalb der Kartenrundung bleibt.
       !important ist hier nötig, nicht kosmetisch: Bootstraps ".card-header:first-child" hat die
       Spezifität (0,2,0). Die frühere gescopte Regel ".sd-card-header[b-xyz]" erreichte dieselbe
       und gewann über die Ladereihenfolge — eine globale Klasse allein (0,1,0) verliert und der
       Radius fiele still von 8px auf Bootstraps 5px zurück (beim Messen der Computed Styles
       aufgefallen, #1167). */
    border-radius: 8px 8px 0 0 !important;
}

/* Versalien und Laufweite vererben sich. Zähler und Aktionen im Kopf sind kein Titel und sollen
   normal geschrieben bleiben — ohne diesen Reset stünde auf den Buttons der Betriebsmittel-
   Detailseite z. B. „PRÜFUNG ERFASSEN" (#1176). Die Buttons setzen ihre Schriftart selbst. */
.sa-card-header button,
.sa-card-header a,
.sa-card-header .btn-sa-primary,
.sa-card-header .btn-sa-outline,
.sa-card-header .btn-sa-danger,
.sa-card-header-count {
    text-transform: none;
    letter-spacing: normal;
}

.sa-card-header-count {
    font-family: var(--font-body);
    font-size: 11px;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.75);
}

/* ── SA table ──────────────────────────────────────────────────────────────── */
.sa-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-family: Inter, sans-serif;
    font-size: 0.9rem;
}
.sa-table td {
    padding: 10px 12px;
    border-bottom: 1px solid #F3F4F6;
    color: #1F2937;
}
.sa-table tbody tr:hover {
    background-color: #F9FAFB;
    cursor: pointer;
}

/* ── Row chevron affordance (clickable rows) ────────────────────────────────── */
.sa-row-chevron-cell {
    text-align: right;
    padding: 10px 12px !important;
    vertical-align: middle;
    color: #E5E7EB;
    pointer-events: none;
    white-space: nowrap;
}

.sa-row-chevron-cell .ti {
    font-size: 1rem;
    transition: color 0.12s;
}

.sa-table tbody tr:hover .sa-row-chevron-cell .ti {
    color: #9CA3AF;
}

/* ── SA table header ───────────────────────────────────────────────────────── */
.sa-table-header th {
    background-color: #3A4A5C !important;
    color: #ffffff !important;
    font-family: Inter, sans-serif;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 10px 12px;
    border: none !important;
    user-select: none;
}
.sa-table-header th:hover {
    background-color: #3A4A5C !important;
}
.sa-table-header th.sorted,
.sa-table-header th.sort-asc,
.sa-table-header th.sort-desc,
.sa-table-header th.ba-th-sort--active,
.sa-table-header th.kr-th-sort--active {
    background-color: #3A4A5C !important;
}

/* ── SA design-system buttons ──────────────────────────────────────────────── */
.btn-sa-primary {
    background-color: #C4633F;
    color: #ffffff;
    border: none;
    border-radius: 6px;
    padding: 6px 14px;
    font-family: Inter, sans-serif;
    font-size: 0.875rem;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    transition: opacity 0.15s;
    text-decoration: none;
}
.btn-sa-primary:hover { opacity: 0.9; color: #ffffff; background-color: #C4633F; }
.btn-sa-primary:disabled, .btn-sa-primary[disabled] { opacity: 0.6; cursor: not-allowed; }

.btn-sa-outline {
    background-color: #ffffff;
    color: #3A4A5C;
    border: 1px solid #3A4A5C;
    border-radius: 6px;
    padding: 6px 14px;
    font-family: Inter, sans-serif;
    font-size: 0.875rem;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    transition: background-color 0.15s;
    text-decoration: none;
}
.btn-sa-outline:hover { background-color: #F3F4F6; color: #3A4A5C; }
.btn-sa-outline:disabled, .btn-sa-outline[disabled] { opacity: 0.6; cursor: not-allowed; }

.btn-sa-danger {
    background-color: #ffffff;
    color: #A32D2D;
    border: 1px solid #A32D2D;
    border-radius: 6px;
    padding: 6px 14px;
    font-family: Inter, sans-serif;
    font-size: 0.875rem;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    text-decoration: none;
}
.btn-sa-danger:hover { background-color: #FCEBEB; color: #A32D2D; }
.btn-sa-danger:disabled, .btn-sa-danger[disabled] { opacity: 0.6; cursor: not-allowed; }

/* ── "Ergänzen" inline link (#696) ───────────────────────────────────────────
   Hoisted from SubstanceDetailPage.razor.css's .sd-ergaenzen (was local-only) so the GBU read
   view can reuse it without copying — small dashed-underline link next to a read-view gap,
   jumps straight into editing that spot instead of the page-top "Bearbeiten" button. */
.sa-ergaenzen {
    color: #9CA3AF;
    font-size: 0.8rem;
    text-decoration: none;
    border-bottom: 1px dashed #9CA3AF;
    white-space: nowrap;
}
.sa-ergaenzen:hover {
    color: #8B3A3A;
    border-bottom-color: #8B3A3A;
}
/* #1443: 17 px high link. Transparent ::after grows the hit area to 44 px so the dashed underline
   stays under the text; real min-height would push the border away from it. */
@media (max-width: 1023px) {
    .sa-ergaenzen {
        position: relative;
    }

    .sa-ergaenzen::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        top: 50%;
        height: 44px;
        transform: translateY(-50%);
    }
}
/* Gap modifier (#696): used where the link sits inline right after a value/sentence — Blazor
   collapses the markup whitespace between an @expression and an adjacent @if block, so the
   spacing has to come from CSS. Not needed on the Substance page, where the link only ever
   replaces an empty value and never sits beside text. */
.sa-ergaenzen--gap {
    margin-left: 0.4rem;
    /* Inline next to a value/sentence, so match the surrounding text size instead of the base
       0.8rem — in the GBU read view that context (.who-readonly) is 11.5px, and a fixed 0.8rem
       would render the edit link larger than the value it annotates (#696 Julia catch). */
    font-size: inherit;
}

.btn-sa-icon {
    background: none;
    border: 1px solid #3A4A5C;
    border-radius: 6px;
    padding: 6px 10px;
    color: #3A4A5C;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.875rem;
    text-decoration: none;
}
.btn-sa-icon:hover { background-color: #F3F4F6; color: #3A4A5C; }
.btn-sa-icon:disabled, .btn-sa-icon[disabled] { opacity: 0.6; cursor: not-allowed; }

/* ── "Was ist zu tun?" cell (#574) ───────────────────────────────────────────
   Hoisted from RiskAssessmentsListPage.razor.css's .gbu-todo (#668) so the Kataster list
   renders the identical cell instead of a second, drifting variant: one dot, the most urgent
   point in plain text, everything else as a quiet subline. Modifiers follow RiskMatrix's
   pill letters (r/a/g) so the GBU list can pass them straight through; --n is the Kataster's
   fourth step ("nicht prüfbar": an open point that carries no colour), --g the terminal
   "alles erledigt" step, which stays deliberately grey — green would reward exactly the rows
   that need no attention. */
.sa-todo { display: flex; gap: 10px; align-items: flex-start; }
.sa-todo-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; margin-top: 4px; }
.sa-todo--r .sa-todo-dot { background: var(--color-status-red-dot); }
.sa-todo--a .sa-todo-dot { background: var(--color-status-amber-dot); }
.sa-todo--n .sa-todo-dot { background: var(--color-status-neutral-dot); }
.sa-todo--g .sa-todo-dot { background: var(--color-status-done-dot); }
/* display:block: an inline span keeps the wrapper's taller strut line, so the text sat ~5px below the dot (margin-top 4px assumes a 1.3 line). */
.sa-todo-txt { display: block; font-size: 13.5px; font-weight: 700; color: var(--color-anthracite); line-height: 1.3; }
.sa-todo--r .sa-todo-txt { color: var(--color-status-red-fg); }
.sa-todo--g .sa-todo-txt { font-weight: 600; color: var(--color-text-secondary); }
.sa-todo-sub { display: block; font-size: 11.5px; font-weight: 500; color: var(--color-text-light); margin-top: 2px; }
.sa-todo--g .sa-todo-sub { color: #A8B0B9; }

/* ── Status- und Prüfstands-Badges (#809) ────────────────────────────────────
   Hoisted from the list pages' scoped stylesheets (.ba-badge--*, .gbu-status-badge)
   for the same reason .sa-todo was hoisted in #574: the detail pages rendered a second,
   drifting variant — Bootstrap's .text-bg-success/-warning/-info — so one and the same
   Betriebsanweisung showed a soft green chip in the list and a loud solid one in its own
   header. Scoped CSS cannot cross component boundaries, so a shared definition has to be
   global; EntityMetaHeader's callers now pass these classes instead of Bootstrap's.

   Status is reference, not a signal (#745): it says what state the record is in, never that
   the user must act. Colour for Handlungsbedarf lives in .sa-review-badge below and in the
   left-rail marker, never here. */
.sa-badge {
    display: inline-block;
    font-size: 11px;
    font-weight: 600;
    border-radius: 10px;
    padding: 2px 9px;
    white-space: nowrap;
}
.sa-badge--neutral   { background-color: #F1F3F5; color: var(--color-text-secondary); }
.sa-badge--published { background-color: #E1F5EE; color: #0F6E56; }
.sa-badge--draft     { background-color: #FAEEDA; color: #854F0B; }
.sa-badge--archived  { background-color: var(--color-divider); color: var(--color-text-secondary); }

/* #1094: same hex pairs as --draft/--published, aliased for the Querschnitts-Checkliste so its
   markup does not say "--draft" on an item called "Zutreffend" — naming clarity only, not pixels. */
.sa-badge--zutreffend { background-color: #FAEEDA; color: #854F0B; }
.sa-badge--geprueft   { background-color: #E1F5EE; color: #0F6E56; }

/* Prüfstand: the one place in this family where colour carries Handlungsbedarf.
   --changed is neutral on purpose — it names the cause, while --overdue/--soon carry the
   deadline itself and must stay the louder pair when both sit in the same cell. */
.sa-review-badge {
    display: inline-block;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.7rem;
    font-weight: 600;
    white-space: nowrap;
    width: fit-content;
}
.sa-review-badge--overdue { background-color: #FCEBEB; color: #A32D2D; }
.sa-review-badge--soon    { background-color: #FAEEDA; color: #854F0B; }
.sa-review-badge--changed { background-color: var(--color-divider); color: var(--color-slate); }

/* ── Buttons ───────────────────────────────────────────────────────────────── */
.btn-primary {
    background-color: var(--color-terracotta);
    border-color: var(--color-terracotta);
    color: #fff;
    font-family: var(--font-body);
    font-weight: var(--font-weight-medium);
    font-size: 15px;
}

.btn-primary:hover {
    background-color: #b05636;
    border-color: #b05636;
}

.btn-secondary {
    background-color: var(--color-slate);
    border-color: var(--color-slate);
    color: #fff;
    font-family: var(--font-body);
    font-weight: var(--font-weight-medium);
    font-size: 15px;
}

.btn-secondary:hover {
    background-color: #31404f;
    border-color: #31404f;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus,
.form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--color-terracotta);
}

/* ── Content area ──────────────────────────────────────────────────────────── */
.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

/* ── Forms ─────────────────────────────────────────────────────────────────── */

/* Placeholder text: italic + lighter grey so it is visually distinct from actual input.
   "z. B." prefix + italic provide two additional cues beyond colour alone (WCAG). */
::placeholder {
    color: #B8C0C7 !important;
    font-style: italic;
    opacity: 1; /* Firefox lowers opacity by default */
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

/* ── Blazor error boundary ─────────────────────────────────────────────────── */
.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."
}

/* ── Misc ───────────────────────────────────────────────────────────────────── */
.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder,
.form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder,
.form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Global form input font size. Was three identical copies of this rule stacked on top of each
   other; folded into one while #1025 was touching it. */
.form-control {
    font-size: 14px;
}

/* #1025: iOS Safari zooms the page in whenever a text field is focused whose font-size is below
   16px, and it does not zoom back out when the field is left. Every field in the app was 14px, so
   tapping the Kataster search box on an iPhone left the whole page zoomed - confirmed on a real
   device. 16px is the threshold, not a preference: at 16px the browser has no reason to zoom.

   Element selectors with !important, deliberately. A rule keyed on .form-control loses to the
   page-scoped stylesheets: Blazor compiles .kr-filter-bar__search into .kr-filter-bar__search[b-xxx],
   which outranks any plain class rule from here, and there are several such copies across the list
   pages. Enumerating them would leave the next new field unprotected. This is a functional floor
   that stops the browser zooming, not a style preference, so overriding whatever a page set is the
   intent rather than a side effect.

   Raising the floor only where a finger is in play, so the deliberately compact 14px desktop form
   design is untouched. Two conditions rather than the plain width query #1035 uses for tap targets:
   there, missing a device meant a slightly small button, here it means a page that zooms and stays
   zoomed, and an iPad in landscape sits above every width breakpoint we have. Fixing the viewport
   meta with maximum-scale would also stop the zoom, and is deliberately not done - it takes pinch
   zoom away from everyone who needs it.

   #1077: the width half is paired with `any-pointer: coarse`, because on its own it also caught a
   narrow window on a plain desktop - the app docked beside an editor - where nothing can zoom and
   the floor only made the fields look oversized next to the rest of the compact form. `any-pointer`
   rather than `pointer`: a touch laptop driven by its mouse reports a fine primary pointer but still
   has a finger available, and that is the case the floor exists for. A touch device keeps the floor
   at any width through the second condition, which is unchanged. */
@media (max-width: 1023px) and (any-pointer: coarse), (pointer: coarse) {
    input:not([type="checkbox"]):not([type="radio"]),
    select,
    textarea {
        font-size: 16px !important;
    }
}

/* Global alert font size */
.alert {
    font-size: 0.875rem;
}

/* ── Touch targets on small screens (#1028) ──────────────────────────────────
   Measured on the Kataster page at 390px before this rule: the SA buttons rendered 34-36px tall
   and the filter row 31px, against the 44px minimum both Apple and Google recommend for a finger.
   Only the height was short - the buttons are already comfortably wide - so a min-height is enough
   and nothing is repositioned.

   Width query rather than `pointer: coarse`: the whole stylesheet switches layouts on width, the
   card layouts and the drawer included, so a second, differently-triggered mechanism would make
   the breakpoints harder to reason about and harder to check in a desktop browser. A touch laptop
   at desktop width keeps the compact buttons; that is the accepted trade.

   The cut-off is 1023px, not the 640px this block originally shipped with. 640px is where the
   tables fold into cards, which says nothing about whether a finger is doing the tapping - the
   sidebar stays a hamburger drawer all the way up to 1023px, so anything in that band is a tablet
   or a narrow window on a touch screen. #1028 already used 1023px for the hamburger and the drawer
   toggles for exactly that reason and then failed to apply it here, which left buttons and filters
   at 31-36px across the whole 641-1023px band. 1024px up is where the fixed sidebar appears and a
   mouse can be assumed.

   The .kr-filter-* / .ba-filter-select / .cp-filter-select names belong to page-scoped stylesheets
   that each carry their own copy of the same declarations (four files for .kr-filter-btn alone).
   Blazor's scoped CSS cannot be shared, so the touch-target rule is hoisted here for the same
   reason .sa-todo and .sa-badge were - one definition instead of six. It only adds min-height and
   never competes with the scoped rules, which set padding and font-size. */
@media (max-width: 1023px) {
    .btn-sa-primary,
    .btn-sa-outline,
    .btn-sa-danger,
    .kr-filter-btn,
    .kr-filter-select,
    .ba-filter-select,
    .cp-filter-select {
        min-height: 44px;
    }
}

/* ── Touch targets for form controls (#1442) ─────────────────────────────────
   The #1028 block above only named buttons and three filter-select classes. Measured at 375px
   (#1332 audit) everything else a finger has to hit was short: search fields 38px, the remaining
   filter selects 34px, form fields 32-38px, icon buttons 22-28px, the chip-remove cross 16px.
   Same breakpoint and same min-height-only approach as #1028; desktop (1024px up) is untouched.

   .form-control/.form-select exclude their -sm variants, which are deliberately compact inline
   controls in dense rows (Prüfpunkt remarks and similar) and were not part of the finding.
   .er-/.fa-filter-select, .btn-sa-icon, .um-menu-btn and .field-input are page-scoped or one-off
   classes for the same reason as in the block above: scoped CSS cannot be shared, and this rule
   only adds a minimum, it never competes with the scoped padding and font-size. */
@media (max-width: 1023px) {
    .form-control:not(.form-control-sm),
    .form-select:not(.form-select-sm),
    .field-input,
    .er-filter-select,
    .er-filter-btn,
    .fa-filter-select {
        min-height: 44px;
    }

    .btn-sa-icon,
    .um-menu-btn {
        min-height: 44px;
        min-width: 44px;
        justify-content: center;
    }

    /* Hit area only: the cross stays 16px so the chip looks the same, a transparent ::after grows
       the tappable area to 44px. position: relative is not set by the scoped chip rules. */
    .kr-active-chip__remove {
        position: relative;
    }

    .kr-active-chip__remove::after {
        content: "";
        position: absolute;
        inset: -14px;
    }

    /* Opt-in for forms that use the compact -sm controls: put .sa-touch-form on the form's
       container. Opt-in rather than global because ~140 -sm controls exist and only forms that
       were checked at phone width are tagged. */
    .sa-touch-form .form-control-sm,
    .sa-touch-form .form-select-sm {
        min-height: 44px;
    }
}

/* #1280: Ladeanzeige im Akzent-Look (.sa-loading-*). Der Balken pulsiert kontinuierlich statt von
   links nach rechts zu laufen, damit er keinen Prozentwert vortäuscht (#1233). Bewusst eigene
   Klassen statt Bootstrap-Überschreibung, damit andere Bootstrap-Spinner unverändert bleiben. */
.sa-loading-spinner {
    color: var(--color-terracotta);
}

.sa-loading-bar {
    width: 100%;
    height: 4px;
    background-color: #F1E3DC;
    border-radius: 2px;
    overflow: hidden;
}

.sa-loading-bar-fill {
    width: 100%;
    height: 100%;
    background-color: var(--color-terracotta);
    animation: sa-loading-pulse 1.5s ease-in-out infinite;
}

@keyframes sa-loading-pulse {
    0%, 100% { opacity: 0.6; }
    50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .sa-loading-bar-fill { animation: none; }
}

/* ── KI field marks (#1438) ───────────────────────────────────────────────────
   Amber frame for an input whose value the KI could not detect. Pairs with <AiFieldMark> (✨/⚠),
   see docs/design/components.md. Works on a wrapper (input group) and on a bare control. */
.sa-ai-undetected {
    border: 2px solid #C8960C;
    border-radius: 6px;
    overflow: hidden;
}

.sa-ai-undetected .form-control,
.sa-ai-undetected .form-select,
.form-control.sa-ai-undetected,
.form-select.sa-ai-undetected {
    border-color: #C8960C;
    background-color: #FFFBEB;
}

/* Inside a framed wrapper the wrapper's 2px border is the frame; a second gold border on the
   input would stack to ~3px (#1438 test feedback). */
.sa-ai-undetected .form-control,
.sa-ai-undetected .form-select {
    border-color: transparent;
}

/* The default light-grey placeholder is hard to read on the amber fill. */
.sa-ai-undetected .form-control::placeholder,
.form-control.sa-ai-undetected::placeholder {
    color: #8A6A2A;
}

.sa-ai-undetected .form-control:focus,
.sa-ai-undetected .form-select:focus,
.form-control.sa-ai-undetected:focus,
.form-select.sa-ai-undetected:focus {
    border-color: #D69E2E;
    box-shadow: 0 0 0 0.1rem rgba(240, 180, 41, 0.25);
    background-color: #FFFBEB;
}

.sa-ai-undetected .ai-mark--attached {
    border: none;
}

/* Same on focus: the wrapper frame stays the only border, the focus ring comes from box-shadow. */
.sa-ai-undetected .form-control:focus,
.sa-ai-undetected .form-select:focus {
    border-color: transparent;
}
