/* Public Sans, self-hosted (k360 manual Kap. 5.1/5.2: the product font is not fetched from a third
   party) — the same files as k360 Sign. Variable font, one file per subset covers every weight; licence in
   fonts/PublicSans-OFL.txt. The font stack itself is set in Styles/site.scss. Relative URLs, so they
   resolve under the PathBase — and inside the municipality CSS preview, which inlines this file into
   an iframe that inherits the page's base URL. */
@font-face {
    font-family: "Public Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url("fonts/public-sans-latin-wght-normal.woff2") format("woff2");
    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: "Public Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url("fonts/public-sans-latin-ext-wght-normal.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

h1:focus {
    outline: none;
}

/* ── System alert banner (Form.razor: "not found" / "deactivated" / other load errors) ──────
   MUST stay visible and legible no matter what a municipality's CustomCss contains. That
   stylesheet (Form.razor's CustomCssUrl) is raw, admin-authored, and loaded unscoped on this
   very page — it legitimately targets common classes like .alert/.d-flex/.btn-close to style the
   FORM's own content, and until this rule existed, the exact same selectors also silently
   reshaped (or could hide entirely) this system message.
   `all: revert !important` strips any author-stylesheet influence on the container back to the
   browser default before every needed property is re-declared by hand — so this banner's actual
   look no longer depends on the shared .alert/.alert-danger/.alert-warning classes surviving
   untouched; it only depends on this dedicated, highly-specific class pair that no legitimate
   form stylesheet would plausibly also target. The child elements are *not* fully reverted (that
   would also strip Bootstrap's own bootstrap-icons glyph / .btn-close mask-image, breaking them) —
   only the handful of properties that could otherwise hide or disable them are force-set. ── */

.itkfs-system-banner {
    all: revert !important;
    box-sizing: border-box !important;
    display: flex !important;
    align-items: center !important;
    gap: 0.5rem !important;
    width: auto !important;
    margin: 0 0 1rem !important;
    padding: 1rem !important;
    border: 1px solid transparent !important;
    border-radius: 7px !important;
    font-family: "Public Sans", "Source Sans 3", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
    font-size: 0.9375rem !important;
    font-weight: 400 !important;
    line-height: 1.5 !important;
    text-align: left !important;
    position: relative !important;
    opacity: 1 !important;
    visibility: visible !important;
}

.itkfs-system-banner.itkfs-banner-danger {
    color: #A31F1C !important;            /* the manual's error pair (Kap. 4.4), 6.37:1 */
    background-color: #FAE7E6 !important;
    border-color: #F0B9B7 !important;
}

.itkfs-system-banner.itkfs-banner-warning {
    color: #7C4A03 !important;            /* the manual's warning pair (Kap. 4.4), 6.61:1 */
    background-color: #FCF1DC !important;
    border-color: #EED29A !important;
}

.itkfs-system-banner-text {
    flex: 1 1 auto !important;
    color: inherit !important;
    display: inline !important;
    visibility: visible !important;
    opacity: 1 !important;
}

.itkfs-system-banner-icon {
    flex-shrink: 0 !important;
    display: inline-block !important;
    visibility: visible !important;
    opacity: 1 !important;
}

/* "Problem melden" in the banner: when no form could be loaded, its header and bug report are gone. */
.itkfs-system-banner-link {
    flex-shrink: 0 !important;
    display: inline-flex !important;
    align-items: center !important;
    gap: 0.25rem !important;
    color: inherit !important;
    font-weight: 600 !important;
    text-decoration: underline !important;
    white-space: nowrap !important;
    visibility: visible !important;
    opacity: 1 !important;
    pointer-events: auto !important;
}

/* In the row, not where .alert-dismissible puts it (absolute, top right): the banner's own padding
   leaves no room there, so it covered the end of the text or "Problem melden". */
.itkfs-system-banner-close {
    position: static !important;
    padding: 0.25em !important;
    margin-left: auto !important;
    flex-shrink: 0 !important;
    display: block !important;
    visibility: visible !important;
    opacity: 1 !important;
    pointer-events: auto !important;
}

/* ── Blazor error banner ─────────────────────────────────────────────────
   MainLayout, EmptyLayout and FullWidthLayout each render their own
   #blazor-error-ui div — styled here once for all three. */

#blazor-error-ui {
    color-scheme: light only;
    background: #FCF1DC; /* the manual's warning pair (Kap. 4.4), 6.61:1 */
    color: #7C4A03;
    bottom: 0;
    box-shadow: var(--k-sch-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.6rem;
    }

/* ── Keyboard focus ──────────────────────────────────────────────────────
   Bootstrap's focus ring is a 25 % tint of the primary colour — about 1.4:1 against white, too faint
   to find (WCAG 2.4.7, 1.4.11). Keyboard focus gets a solid dark outline on top of it, on every
   control. !important because Bootstrap (site.css, loaded after this file) sets outline: 0 on
   :focus-visible for its buttons and links. Not for elements focused only by script (tabindex="-1":
   headings, the main content after the skip link), which aren't controls. */

:focus-visible:not([tabindex="-1"]) {
    outline: 2px solid #1d1d1f !important;
    outline-offset: 2px !important;
}

/* ── Skip link, main landmark, footer ────────────────────────────────── */

.skip-link {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 2000;
    padding: 0.5rem 1rem;
    background: var(--bs-body-bg);
    color: var(--bs-link-color);
    border: 2px solid currentColor;
    border-radius: 0.25rem;
}

/* BlazorBootstrap's stylesheet (loaded last) gives every <main> height: 100vh and overflow-x: hidden —
   on the layouts' <main> that would make it a scroll box of exactly the window's height, scrolling
   inside itself with the footer below it. The layouts size it themselves (flex, see each layout). */
#main-content {
    height: auto;
    overflow-x: visible;
}

/* Focused by the skip link or after a page change — no ring around the whole content. */
#main-content:focus {
    outline: none;
}

.site-footer {
    padding: 0.75rem 0;
    border-top: 1px solid var(--bs-border-color);
    font-size: 0.875rem;
}

/* ── Cross-page user menu toggle ─────────────────────────────────────────
   Used identically by Home and NavMenu — a class scoped to either one's
   .razor.css can't serve the other, so it stays global rather than duplicated. */

.user-dropdown-toggle::after {
    display: none;
}

/* ── Help info button ──────────────────────────────────────────────────
   The manual's info colour (Kap. 4.4): white on #185A93, 7.19:1. */

.help-info-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* At least 24 px to hit (WCAG 2.5.8 Target Size). */
    width: 24px;
    height: 24px;
    background-color: #185A93;
    color: #ffffff;
    font-weight: bold;
    font-style: normal;
    font-size: 12px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    padding: 0;
    line-height: 1;
    flex-shrink: 0;
    vertical-align: middle;
}

.help-info-btn:focus-visible {
    outline: none;
    box-shadow: var(--k-fokus);
}

/* ── Help info alert ─────────────────────────────────────────────────── */

@keyframes helpAlertIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* An info alert (FieldHelpAlert: the manual's info pair, Kap. 4.4, via site.scss) that slides in. */
.help-info-alert {
    animation: helpAlertIn 0.15s cubic-bezier(.2, .9, .3, 1);
}

/* ── Field wrapper (used by all field components) ───────────────────── */

.field {
    margin-bottom: 0; /* spacing is controlled by the FormRenderer wrapper div.mb-3 */
}

.field label {
    display: block;
    font-weight: 600;
    font-size: 0.875rem;
    margin-bottom: 4px;
    color: var(--bs-body-color);
}

/* A checkbox beside fields whose label sits above their control (FieldLabel's
   .field-label--stacked) — two fields placed next to each other in the builder: without this, the
   checkbox sat level with their labels. Pushed down by one such label row (.field label: 0.875rem
   at line-height 1.5, plus its mb-1), less the checkbox's own top margin (.form-check-input: .25em
   at the label's 0.875rem), the box starts level with the top edge of the control beside it; a
   long text wraps on below. Not in a column that holds such a label itself (a field with
   annotations), and not in a row without any (checkboxes only): nothing to line up with there. */
.form-field-row:has(.field-label--stacked) > :not(:has(.field-label--stacked)) .field--checkbox {
    padding-top: calc(0.875rem * 1.5 + 0.25rem - 0.875rem * 0.25);
}

/* A help button (.help-info-btn, 24 px) makes that label row taller than its text — and the
   control below it starts lower. */
.form-field-row:has(.field-label--stacked .help-info-btn) > :not(:has(.field-label--stacked)) .field--checkbox {
    padding-top: calc(24px + 0.25rem - 0.875rem * 0.25);
}

.field-error {
    font-size: 0.875rem;
    color: var(--bs-danger);
    margin-top: 4px;
}

/* A value that passed its check (FieldValid), in place of the errors: green and with a check icon. */
.field-valid {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    font-size: 0.875rem;
    color: var(--bs-success-text-emphasis);
    margin-top: 4px;
}

/* A field with several inputs or options is a fieldset (FieldLabel Group): no frame of its own,
   it looks like any other field. */
.field-group {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

/* A block's title in its card header: a heading for screen readers (h3), looking as before. */
.block-heading {
    font-size: inherit;
    font-weight: inherit;
    line-height: inherit;
    margin: 0;
}

/* Headings focused by script (page change, see FormRenderer) don't need a ring of their own. */
.form-page-heading:focus,
h1[tabindex="-1"]:focus,
h2[tabindex="-1"]:focus {
    outline: none;
}

/* Markdig wraps content in <p>/<ul>/<ol> with Bootstrap's default 1rem bottom margin.
   For static-text containers (form/preview cards, dialog cards) we want the rendered
   block to close flush, so suppress only the trailing element's margin. */
.static-text-body > :last-child {
    margin-bottom: 0;
}

/* ── Static Markdown links (StaticMarkdown.cs) ──────────────────────────
   Authored links in static-text content render as small outline buttons
   instead of inline text links, so they read as clickable actions. They
   always open in a new tab; the arrow communicates that before the click. */
.static-markdown-link {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    margin: 0.15rem 0.35rem 0.15rem 0;
    text-decoration: none !important;
    vertical-align: middle;
}

.static-markdown-link::after {
    content: "\2197";
    font-size: 0.85em;
    line-height: 1;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--bs-success);
}

.invalid {
    outline: 1px solid var(--bs-danger);
}

.validation-message {
    color: var(--bs-danger);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #A31F1C;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "Es ist ein Fehler aufgetreten."
    }

.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;
}

/* ── Builder: dropzones expand only where the dragged element can be dropped ─ */
/* builderDragHandler.js adds .fb-dropzone-armed to the matching zones on        */
/* dragstart and removes it on dragend. These use global class names that        */
/* Blazor's scoped CSS does not rewrite; the leading `body` keeps them specific  */
/* enough to win over the scoped default height.                                 */

body .fb-dropzone-full.fb-dropzone-armed {
    height: 24px;
    margin: 4px 0;
}

body .fb-dropzone-compact.fb-dropzone-armed {
    height: 12px;
    margin: 2px 0;
}

body .fb-split-dropzone.fb-dropzone-full.fb-dropzone-armed {
    height: 32px;
    margin: 4px 0;
}

body .fb-split-dropzone.fb-dropzone-compact.fb-dropzone-armed {
    height: 20px;
    margin: 2px 0;
}

/* The vertical (mid-row column-split) zone's armed sizing grows only on its own axis — width,
   not height (see the .fb-dropzone-compact.fb-dropzone-armed override further down) — never
   align-self: stretch/height: auto. This zone sits in the same align-items-baseline flex row as
   every other vertical dropzone in that row; align-self: stretch couples an element's height to
   the row's tallest sibling, so arming ONE zone would stretch every OTHER (unarmed) vertical zone
   in the same row to match, growing zones that were never touched. Width-only avoids that. */

/* ── Builder: click/keyboard alternative to dragging ─────────────────────── */
/* builderDragHandler.js's armClickMode()/disarmClickMode() add and remove       */
/* .fb-dropzone-click-armed (own class, own look — never affects a real drag's   */
/* .fb-dropzone-armed above) and .fb-palette-item-armed. Reuses the exact same    */
/* expanded heights as .fb-dropzone-armed above so the two interaction styles     */
/* read as visually consistent, and additionally covers the vertical (mid-row     */
/* column-split) zone, which .fb-dropzone-armed never had sizing for at all.      */

body .fb-dropzone-full.fb-dropzone-click-armed {
    height: 28px;
    margin: 6px 0;
    border-color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
}

body .fb-dropzone-compact.fb-dropzone-click-armed {
    height: 16px;
    margin: 4px 0;
    border-color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
}

body .fb-split-dropzone.fb-dropzone-full.fb-dropzone-click-armed {
    height: 36px;
    margin: 6px 0;
    border-color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
}

body .fb-split-dropzone.fb-dropzone-compact.fb-dropzone-click-armed {
    height: 24px;
    margin: 4px 0;
    border-color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
}

/* Width-only, same reasoning as the real-drag vertical rule above — no align-self/height, or
   arming one zone in a row would stretch every other (unarmed) vertical zone in that same row. */
body .fb-split-dropzone-vertical.fb-dropzone-click-armed {
    width: 28px;
    border-color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
}

/* Dims every existing item at the same structural layer as whatever's currently armed (e.g.
   arming a field dims the other fields, not blocks/pages) — signals "not relevant to place this
   here" without hiding them outright. Toggled in armClickMode/disarmClickMode via the id prefixes
   already used for keyboard focus targeting (page-header-*/block-header-*/field-row-*). */
.fb-dim {
    opacity: 0.4;
    transition: opacity 0.15s;
}

/* Candidate highlight — the zone the user is currently pointing at or has
   Tab-focused. Plain CSS (:hover/:focus-visible), so it needs no JS/Blazor state
   and is naturally exclusive to whichever single zone the pointer/focus is on. */
body .fb-dropzone-click-armed:hover,
body .fb-dropzone-click-armed:focus-visible {
    border-color: var(--bs-primary) !important;
    border-style: solid;
    background: rgba(var(--bs-primary-rgb), 0.08);
    outline: none;
}

body .fb-palette-item-armed {
    background: var(--bs-tertiary-bg);
    outline: 2px solid var(--bs-primary);
    outline-offset: -2px;
}

/* Plain role="button" rows (page/block/field headers, palette items) aren't Bootstrap .btn/
   form-control elements, so they never picked up Bootstrap's own themed focus style — leaving
   whatever the browser's own default focus ring happens to be (a blue system color on Chromium,
   unrelated to the page's theme). Give every newly keyboard-reachable builder row a consistent,
   on-theme outline instead. Plain :focus (not :focus-visible) — this outline is also the only
   remaining "currently selected" indicator (the old custom border/background classes were removed
   as stale, since they tracked _selectedType/_selectedId rather than actual DOM focus), so it must
   still show for mouse-click selection, which most browsers suppress under :focus-visible.
   Inset (negative) offset, not outset — both the palette (.fb-sidebar) and the canvas (FormBuilder's
   own root) wrap their scrollable item list in an `overflow: hidden` ancestor to keep that list's
   own scrollbar contained, which silently clips an outset ring on any item flush against that
   boundary. An inset ring stays within the item's own border box, so it can never be clipped, at
   the cost of overlapping the last couple pixels of its padding — same tradeoff already accepted by
   .fb-palette-item-armed below. */
.fb-palette-item:focus,
.fb-field-card:focus,
.card-header[role="button"]:focus {
    outline: 2px solid var(--bs-primary);
    outline-offset: -2px;
}

/* ── Builder: draggable row/card affordance ───────────────────────────────── */
/* Applied by both BuilderFieldContent.razor (field rows) and BlockSection.razor  */
/* (block cards) — a class scoped to either one's .razor.css can't serve the      */
/* other, so it stays global rather than duplicated.                              */

.fb-draggable {
    cursor: grab;
    -webkit-user-select: none;
    user-select: none;
}

.fb-draggable:active {
    cursor: grabbing;
}

/* ── Dependency-graph legend dots ─────────────────────────────────────────── */
/* The <span class="drg-dot ..."> markup lives in the <Legend> RenderFragment    */
/* authored inside DisplayRulesGraphSidebar.razor / FieldFunctionsGraphSidebar.razor */
/* (the callers), so Blazor scopes it to THOSE components, not to                 */
/* DependencyGraphSidebar.razor — a rule in DependencyGraphSidebar.razor.css      */
/* can never match it. Neither caller has its own scoped stylesheet, so this      */
/* has to live globally to apply anywhere at all.                                 */

.drg-dot {
    display: inline-block;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    flex-shrink: 0;
}

.drg-dot-then {
    background: var(--bs-displayrules);
}

.drg-dot-and {
    background: var(--color-rule-and);
}

.drg-dot-or {
    background: var(--color-rule-or);
}

.drg-dot-fieldfunction {
    background: var(--bs-fieldfunctions);
}

/* ── Gemeinde-CSS-Vorschau: Musterformular ──────────────────────────────────
   Baseline look for MunicipalityCssStudio.BuildMockupBodyHtml, rendered inside the live-preview
   <iframe> on MunicipalityManagement.razor. Necessarily global rather than scoped: this whole
   block gets read from disk and inlined verbatim into that iframe's own, separate HTML document
   (see MunicipalityCssStudio.BuildPreviewDocument) — Blazor CSS isolation couldn't apply there
   even if this lived in a .razor.css file, since the iframe's document is never part of Blazor's
   render tree at all. Deliberately its own unscoped re-implementation of the theming rules in
   Form.razor.css / FormRenderer.razor.css (rather than reusing them directly) for the same reason
   in the other direction — those are Blazor CSS-isolated (compiled to e.g.
   ".form-stepper[b-xxxxxxxxxx]"), so they only ever match elements the real
   Form.razor/FormRenderer actually rendered. Everything below is scoped under .form-wrapper so it
   can never affect unrelated elements elsewhere on the admin page. ── */

.form-wrapper {
    --municipality-color-hover: color-mix(in srgb, var(--municipality-color) 85%, black);
    --municipality-color-active: color-mix(in srgb, var(--municipality-color) 80%, black);
}

.form-wrapper .btn-primary {
    --bs-btn-bg: var(--municipality-color);
    --bs-btn-border-color: var(--municipality-color);
    --bs-btn-hover-bg: var(--municipality-color-hover);
    --bs-btn-hover-border-color: var(--municipality-color-hover);
    --bs-btn-active-bg: var(--municipality-color-active);
    --bs-btn-active-border-color: var(--municipality-color-active);
}

/* Filled in the municipality's colour on hover and press — so the text turns white there, as on
   .btn-primary: .btn-outline-secondary's own hover text is the dark body text (site.scss), which
   left "Zurück" unreadable on the coloured fill. */
.form-wrapper .btn-outline-primary,
.form-wrapper .btn-outline-secondary {
    --bs-btn-color: var(--municipality-color);
    --bs-btn-border-color: var(--municipality-color);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--municipality-color);
    --bs-btn-hover-border-color: var(--municipality-color);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--municipality-color-active);
    --bs-btn-active-border-color: var(--municipality-color-active);
}

.form-wrapper a {
    color: var(--municipality-color);
}

.form-wrapper .form-check-input:checked {
    background-color: var(--municipality-color);
    border-color: var(--municipality-color);
}

.form-wrapper .form-control:focus,
.form-wrapper .form-select:focus {
    border-color: var(--municipality-color);
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--municipality-color) 25%, transparent);
}

.form-wrapper .form-stepper {
    display: flex;
    align-items: center;
}

.form-wrapper .form-stepper__step {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    background: none;
    border: none;
    padding: 0;
    flex-shrink: 0;
}

.form-wrapper .form-stepper__dot {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    font-weight: 600;
    background: #fff;
    border: 2px solid var(--bs-light);
    color: var(--bs-secondary);
}

.form-wrapper .form-stepper__step.is-current .form-stepper__dot {
    background: var(--municipality-color);
    border-color: var(--municipality-color);
    color: #fff;
}

.form-wrapper .form-stepper__step.is-past .form-stepper__dot {
    background: var(--bs-success);
    border-color: var(--bs-success);
    color: #fff;
}

.form-wrapper .form-stepper__label {
    font-size: 0.72rem;
    max-width: 90px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--bs-secondary);
    text-align: center;
}

.form-wrapper .form-stepper__step.is-current .form-stepper__label {
    color: var(--municipality-color);
    font-weight: 600;
}

.form-wrapper .form-stepper__step.is-past .form-stepper__label {
    color: var(--bs-success);
}

.form-wrapper .form-stepper__connector {
    flex: 1;
    height: 2px;
    background: var(--bs-light);
    margin: 0 4px 20px;
}

.form-wrapper .form-stepper__connector.is-past {
    background: var(--bs-success);
}

.form-wrapper .form-page-divider {
    height: 3px;
    width: 48px;
    background: var(--municipality-color);
    border-radius: 2px;
}

.form-wrapper .spacer {
    width: 100%;
}

/* ── Gemeinde-CSS-Editor: Syntax-Highlighting-Farben ─────────────────────────
   The rest of the editor's own look (the .css-editor/.css-editor-highlight/.css-editor-textarea
   overlay itself) is scoped CSS in MunicipalityManagement.razor.css, since those all target real
   elements that component renders. These .cssh-* token colors can't move there with them: they're
   applied to <span> elements municipalityCssEditor.js injects via innerHTML (the syntax-highlight
   pass), which are never part of Blazor's own render tree and so never receive the component's
   scope attribute — a scoped rule for them would silently never match anything. ── */

.cssh-comment { color: #6a737d; font-style: italic; }
.cssh-string { color: #032f62; }
.cssh-atrule { color: #d73a49; font-weight: 600; }
.cssh-variable { color: #005cc5; }
.cssh-property { color: #6f42c1; }
.cssh-selector { color: #22863a; font-weight: 600; }
.cssh-pseudo { color: #22863a; }
.cssh-punctuation { color: #24292f; font-weight: 600; }
.cssh-keyword { color: #d73a49; font-weight: 700; }

@media (prefers-color-scheme: dark) {
    .cssh-comment { color: #8b949e; }
    .cssh-string { color: #9ecbff; }
    .cssh-atrule { color: #ff7b72; }
    .cssh-variable { color: #79c0ff; }
    .cssh-property { color: #d2a8ff; }
    .cssh-selector { color: #7ee787; }
    .cssh-pseudo { color: #7ee787; }
    .cssh-punctuation { color: #d4d4d4; }
    .cssh-keyword { color: #ff7b72; }
}

/* Same overrides, keyed off an explicit theme attribute rather than the OS preference, in case
   this admin area ever opts into Bootstrap 5.3's data-bs-theme toggle. */
[data-bs-theme="dark"] .cssh-comment { color: #8b949e; }
[data-bs-theme="dark"] .cssh-string { color: #9ecbff; }
[data-bs-theme="dark"] .cssh-atrule { color: #ff7b72; }
[data-bs-theme="dark"] .cssh-variable { color: #79c0ff; }
[data-bs-theme="dark"] .cssh-property { color: #d2a8ff; }
[data-bs-theme="dark"] .cssh-selector { color: #7ee787; }
[data-bs-theme="dark"] .cssh-pseudo { color: #7ee787; }
[data-bs-theme="dark"] .cssh-punctuation { color: #d4d4d4; }
[data-bs-theme="dark"] .cssh-keyword { color: #ff7b72; }

/* Generic escape hatch for the "flex item won't shrink below its content's intrinsic size"
   default — needed anywhere a flex child (row, card-body, editor wrapper, …) is meant to grow to
   fill available space AND let its own overflow content scroll internally instead of pushing its
   ancestors taller. Bootstrap has no utility class for this. Stays global rather than living in a
   single component's scoped CSS because it's a genuine cross-component utility — used by both
   MunicipalityManagement.razor and FullWidthLayout.razor, each with their own distinct Blazor
   scope attribute, so a scoped copy in either one wouldn't reach the other. */
.min-h-0 {
    min-height: 0;
}

/* The same for width: a flex or grid child that should stay within its share of the row and cut
   or wrap its text (text-truncate, ellipsis) instead of growing to its content and pushing past
   its neighbours. Used across the builder (rule and function summaries, field cards in a row, the
   dependency graph) and the inbox. */
.min-w-0 {
    min-width: 0;
}

/* ── Gemeinde-CSS-Vorschau: Musterformular-Bereichsmarkierung ────────────────
   Toggled by the live preview's own "Klassennamen anzeigen" switch (see municipalityCssEditor.js's
   setAnnotated): reveals each data-class-label as a small badge so users can see which selector
   governs which region. Must stay global for the same reason as the Musterformular block above —
   this file gets read from disk and inlined into the preview iframe's own, separate document
   (MunicipalityCssStudio.BuildPreviewDocument), where the annotation class is toggled via JS,
   never present in the real, unmodified form page. */
.css-map-annotated [data-class-label] {
    position: relative;
    outline: 1px dashed rgba(var(--bs-primary-rgb), 0.35);
    outline-offset: 2px;
}

.css-map-annotated [data-class-label]::after {
    content: attr(data-class-label);
    position: absolute;
    top: -1px;
    left: -1px;
    transform: translateY(-100%);
    background: var(--bs-primary);
    color: #fff;
    font-family: var(--bs-font-monospace, monospace);
    font-size: 0.65rem;
    line-height: 1.4;
    padding: 0 4px;
    border-radius: 3px 3px 3px 0;
    white-space: nowrap;
    z-index: 1;
    pointer-events: none;
}

/* A labeled element that's also the very first thing inside its (labeled) parent — e.g.
   .card-header inside .card, or .form-label inside .field — would otherwise sit at nearly the
   same position as that parent's own label, so the two badges collide. Enough top margin pushes
   it down just far enough to keep both legible; harmless elsewhere since :first-child only ever
   matches elements that genuinely start flush with their container. */
.css-map-annotated [data-class-label]:first-child {
    margin-top: 1.25rem;
}

/* Vertical variant (between fields in a row) grows on its own axis — width, not
   height — while the rest still grow taller. */
body .fb-split-dropzone-vertical.fb-dropzone-compact.fb-dropzone-armed {
    width: 48px;
    margin: 1px 0;
}

/* ── Builder: the page/block/field currently being dragged ──────────────────── */
/* Applied/removed by builderDragHandler.js's delegated dragstart listener via raw   */
/* classList, never through Blazor state — see that listener's doc comment for why. */
body .fb-drag-source {
    border: 2px dashed var(--bs-primary) !important;
}

/* Pages and blocks darken a bit more than a field's plain bg-primary-subtle. */
body .fb-page-card.fb-drag-source,
body .fb-block-card.fb-drag-source {
    background-color: rgba(var(--bs-primary-rgb), 0.25) !important;
}

/* ── Builder: SplitDropZone's "new item" vs "reorder existing item" content ─── */
/* builderDragHandler.js toggles body.fb-reorder-drag the instant a drag carrying an  */
/* existing item's id starts (and removes it the instant one ends) — every           */
/* SplitDropZone across every block reacts to this single global class immediately   */
/* and uniformly, with no per-component Blazor state/re-render involved at all. See  */
/* SplitDropZone.razor's markup comment for why that matters.                        */
body .fb-label-reorder {
    display: none;
}

body.fb-reorder-drag .fb-label-new {
    display: none;
}

body.fb-reorder-drag .fb-label-reorder {
    display: inline;
}

/* Reorder mode narrows to a 3:1 left:right split (the duplicate action is secondary) */
body.fb-reorder-drag .fb-split-dropzone-left {
    flex: 3;
}

body.fb-reorder-drag .fb-split-dropzone-right {
    flex: 1;
}

body .fb-field-card.fb-drag-source {
    background-color: var(--bs-primary-bg-subtle) !important;
}
/* Values taken over from ID Austria or a register (FieldRenderer.SourceAddon): read-only, with the
   source's short code so the citizen always sees where the data came from. */
.prefill-badge {
    font-size: .75rem;
    font-weight: 600;
    color: var(--bs-success-text-emphasis);
    background-color: var(--bs-success-bg-subtle);
    border-color: var(--bs-success-border-subtle);
    white-space: nowrap;
}

span.prefill-badge:not(.input-group-text) {
    display: inline-flex;
    align-items: center;
    padding: .1rem .45rem;
    border: 1px solid var(--bs-success-border-subtle);
    border-radius: var(--bs-border-radius-pill);
    vertical-align: middle;
}

/* Register response explorer on the connector admin page (JsonPathTree). */
.json-tree-container {
    max-height: 32rem;
    overflow: auto;
    padding: .5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--bs-body-bg);
    font-family: var(--bs-font-monospace);
}

.json-tree summary { cursor: pointer; }
.json-tree__key { color: var(--bs-primary-text-emphasis); }
.json-tree__value { color: var(--bs-body-color); word-break: break-all; }
.json-tree__leaf { text-decoration: none; font-family: inherit; font-size: inherit; }
.json-tree__leaf:hover .json-tree__value { text-decoration: underline; }

/* ── Register-Konnektoren: JSON-Editor (jsonEditor.js overlay) and step overview ── */
.json-editor {
    display: flex;
    height: 32rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--bs-tertiary-bg);
    overflow: hidden;
    font-family: var(--bs-font-monospace);
    font-size: .8rem;
    line-height: 1.5;
}
.json-editor__gutter,
.json-editor__highlight,
.json-editor__textarea {
    margin: 0;
    padding: .75rem;
    font: inherit;
    line-height: inherit;
    white-space: pre;
    tab-size: 2;
}
.json-editor__gutter {
    flex: 0 0 auto;
    min-width: 3rem;
    text-align: right;
    color: var(--bs-secondary-color);
    border-right: 1px solid var(--bs-border-color);
    overflow: hidden;
    user-select: none;
}
.json-editor__body { position: relative; flex: 1 1 auto; min-width: 0; }
.json-editor__highlight {
    position: absolute;
    inset: 0;
    overflow: hidden;
    color: var(--bs-body-color);
    pointer-events: none;
}
.json-editor__textarea {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    resize: none;
    border: 0;
    outline: none;
    overflow: auto;
    background: transparent;
    color: transparent;
    caret-color: var(--bs-body-color);
}
.json-editor:focus-within { border-color: var(--k-brand-600); box-shadow: var(--k-fokus); }

.jsonh-key { color: #0550ae; }
.jsonh-string { color: #0a7a35; }
.jsonh-number { color: #953800; }
.jsonh-literal { color: #cf222e; font-weight: 600; }
.jsonh-punctuation { color: #6e7781; }
.jsonh-placeholder { color: #8250df; font-weight: 700; background: rgba(130, 80, 223, .1); border-radius: 2px; }
[data-bs-theme="dark"] .jsonh-key { color: #79c0ff; }
[data-bs-theme="dark"] .jsonh-string { color: #7ee787; }
[data-bs-theme="dark"] .jsonh-number { color: #ffa657; }
[data-bs-theme="dark"] .jsonh-literal { color: #ff7b72; }
[data-bs-theme="dark"] .jsonh-punctuation { color: #8b949e; }
[data-bs-theme="dark"] .jsonh-placeholder { color: #d2a8ff; }

.connector-steps { padding-left: 1.25rem; }
.connector-steps > li { margin-bottom: .4rem; }
.connector-steps__result { list-style: none; margin-left: -1.25rem; color: var(--bs-secondary-color); }
.connector-attr-path { max-width: 16rem; }
.connector-attr-path code { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; direction: rtl; text-align: left; }
@media (min-width: 1200px) { .connector-test { position: sticky; top: 1rem; } }

/* ── Builder: edit modals with a live preview column ──────────────────────── */
/* EditFieldModal / EditBlockModal pass this via the Modal's DialogCssClass. It  */
/* has to be global: .modal-dialog is rendered by Blazor.Bootstrap's Modal, not  */
/* by the hosting component, so a scoped (::deep) rule never reaches it.         */
/* modal-xl sets Bootstrap's --bs-modal-width on this same element; two classes  */
/* outrank its one.                                                              */
.modal-dialog.builder-preview-modal-dialog {
    --bs-modal-width: min(96vw, 1600px);
}

/* The field modal previews a single field, so it needs less room than the block modal's
   whole-block preview. Three classes outrank the rule above. */
.modal-dialog.builder-preview-modal-dialog.builder-preview-modal-dialog--compact {
    --bs-modal-width: min(94vw, 1320px);
}

/* ── Builder: reuse pickers (block, field, "Kopie mit Auswahl") ──────────── */
/* Passed via the Modal's BodyCssClass, together with IsScrollable: the dialog  */
/* never grows past the window (Bootstrap's modal-dialog-scrollable), and only  */
/* the list scrolls — the search box and type filter above it stay in view.     */
/* Global for the same reason as the preview modals above.                     */
.modal-body.builder-picker-modal-body {
    display: flex;
    flex-direction: column;
}

.modal-body.builder-picker-modal-body > .list-group {
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Builder field and block headers: "Nur digital" / "Nur PDF" icon, in the dark red people
   associate with PDFs. Global because it's on BlazorBootstrap's own Icon component, outside either
   header's CSS scope. */
.fb-availability-icon {
    color: #b30b00;
}

/* Tabs/inputs on the left, live preview on the right, split by a vertical rule. */
.builder-edit-body {
    display: flex;
    align-items: stretch;
    min-height: 0;
}

.builder-edit-body__form {
    flex: 1 1 55%;
    min-width: 0;
}

.builder-edit-body__divider {
    flex: 0 0 1px;
    background: var(--bs-border-color);
    margin: 0 1.25rem;
}

.builder-edit-body__preview {
    flex: 1 1 45%;
    min-width: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}

/* Takes the preview column's remaining height (below its "Vorschau" label) and centers what's
   inside vertically — used for a single field's preview, which would otherwise sit at the top of
   a column as tall as the whole edit form. */
.builder-edit-body__preview-center {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Every field carries a bottom margin (mb-3) to space it from the next row — with nothing below
   it here, that margin would push the field visibly above center. Bootstrap's spacing utilities
   are !important, so overriding one has to be too. */
.builder-edit-body__preview-center .row:last-child > .mb-3 {
    margin-bottom: 0 !important;
}

.builder-edit-body--compact .builder-edit-body__form {
    flex-basis: 64%;
}

.builder-edit-body--compact .builder-edit-body__preview {
    flex-basis: 36%;
}

/* The preview belongs to the right of the form. Only below Bootstrap's lg breakpoint (a small or
   split window) would the two columns each be too narrow — stack the preview below the form there,
   split by a horizontal rule. (Stacking from xxl down also hit ordinary laptop screens.) */
@media (max-width: 991.98px) {
    .builder-edit-body {
        flex-direction: column;
    }

    .builder-edit-body__form,
    .builder-edit-body__preview,
    .builder-edit-body--compact .builder-edit-body__form,
    .builder-edit-body--compact .builder-edit-body__preview {
        flex: 0 0 auto;
    }

    .builder-edit-body__preview {
        overflow-y: visible;
    }

    .builder-edit-body__divider {
        flex: 0 0 1px;
        height: 1px;
        margin: 1.25rem 0;
    }
}

/* ── Builder: block preview — display rules / field functions made visible ──
   Set only by the Builder's block preview (BlockPreviewPane → FormRenderer's RevealHidden /
   FieldAnnotations parameters); a citizen-facing form never gets these classes. */

/* A field a display rule currently hides, rendered anyway (and disabled). Fainter than a field a
   rule merely disables (which only gets its inputs' own disabled look), so hidden-by-rule and
   disabled-by-rule read differently at a glance. Applied to the field's input only — never to
   its annotation badges. */
.form-revealed-hidden {
    opacity: 0.4;
}

/* The field a rule or function depends on — dashed box in the rule/function color, with badges
   above the field naming what it depends on. */
.form-field-annotation {
    border: 2px dashed var(--form-annotation-color);
    background: var(--form-annotation-bg);
    border-radius: var(--bs-border-radius);
    padding: 0.5rem 0.75rem 0.75rem;
    min-width: 0;
}

.form-field-annotation--displayrules {
    --form-annotation-color: var(--bs-displayrules);
    --form-annotation-bg: var(--bs-displayrules-bg-subtle);
}

.form-field-annotation--fieldfunctions {
    --form-annotation-color: var(--bs-fieldfunctions);
    --form-annotation-bg: var(--bs-fieldfunctions-bg-subtle);
}

/* Targeted by both: left half in the display-rule color, right half in the field-function color.
   A dashed border can't change color partway, so the box's own border is kept (for its size) but
   made transparent, and each half's border is drawn by a pseudo-element over it. */
.form-field-annotation--both {
    position: relative;
    border-color: transparent;
    background: linear-gradient(to right, var(--bs-displayrules-bg-subtle) 50%, var(--bs-fieldfunctions-bg-subtle) 50%);
}

.form-field-annotation--both::before,
.form-field-annotation--both::after {
    content: "";
    position: absolute;
    top: -2px;
    bottom: -2px;
    border: 2px dashed;
    pointer-events: none;
}

.form-field-annotation--both::before {
    left: -2px;
    right: 50%;
    border-color: var(--bs-displayrules);
    border-right: none;
    border-radius: var(--bs-border-radius) 0 0 var(--bs-border-radius);
}

.form-field-annotation--both::after {
    left: 50%;
    right: -2px;
    border-color: var(--bs-fieldfunctions);
    border-left: none;
    border-radius: 0 var(--bs-border-radius) var(--bs-border-radius) 0;
}

.form-field-annotation__badges {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    margin-bottom: 0.5rem;
}

/* One badge, with its optional "assume met" checkbox in front of it. */
.form-field-annotation__badge-row {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    max-width: 100%;
}

/* Only display rules have one (see PreviewAnnotations) — colored as such also in a
   form-field-annotation--both box. */
.form-field-annotation__toggle {
    flex-shrink: 0;
    margin-top: 0.1rem;
    border-color: var(--bs-displayrules);
}

/* Bootstrap's .badge is single-line (white-space: nowrap) and site.css loads after this file —
   the extra class keeps a long badge wrapping inside its box instead of overflowing it. */
.form-field-annotation .badge.form-field-annotation__badge {
    font-weight: 500;
    white-space: normal;
    text-align: left;
    line-height: 1.3;
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
}

/* One condition ("… UND …") of a badge. Inline-block, so a badge that doesn't fit on one line
   breaks between conditions first, and only within one if that alone is still too long. */
.form-field-annotation__segment {
    display: inline-block;
    max-width: 100%;
}

/* A field or block named in a badge/caption: its icon, then its name. */
.form-field-annotation__ref > .bi {
    margin-right: 0.2em;
}

/* A field from outside the previewed block that the annotated field depends on (a field
   function's operand), fillable so the result can be tried out. */
/* Always a function's operand, so always in the field-function color — also inside a
   form-field-annotation--both box. */
.form-field-annotation__external {
    border: 1px solid var(--bs-fieldfunctions);
    background: var(--bs-body-bg);
    border-radius: var(--bs-border-radius-sm);
    padding: 0.4rem 0.6rem 0.5rem;
    margin-bottom: 0.5rem;
    font-size: 0.875em;
}

.form-field-annotation__external-caption {
    color: var(--bs-fieldfunctions);
    font-size: 0.75rem;
    font-weight: 600;
}

/* No toasts on a phone: they cover the top of a small screen, over the very content they comment
   on. Whatever matters also shows in the page itself (field errors, banners, the dialog's retry). */
@media (max-width: 767.98px) {
    .toast-container {
        display: none !important;
    }
}

/* ── Admin pages (Gemeindeeinstellungen, Benutzerkonten, Register-Konnektoren) ───────────────────
   One compact header for all of them: the layouts' own top padding (pt-4, shared with every other
   page) is partly taken back here instead of in the layouts, and the title is a step smaller than a
   bare h1 — these are working pages, the content matters more than their name. */
.admin-page {
    margin-top: -0.75rem;
    padding-bottom: 0.5rem;
}

.admin-page__header {
    margin-bottom: 1rem;
}

.admin-page__title {
    margin-bottom: 0.15rem;
    font-size: 1.4375rem; /* "Titel" (manual Kap. 5.3) */
    font-weight: 600;
}

.admin-page__subtitle {
    margin-bottom: 0;
    color: var(--bs-secondary-color);
    font-size: 0.9375rem;
}

/* ── Page scroll lock follows the open dialog ────────────────────────────────
   Bootstrap locks <body> (inline overflow: hidden and padding-right) while a modal or offcanvas is
   shown, and only releases it at the end of its own hide routine. Blazor knows nothing of that: a
   re-render or navigation that removes a dialog while it is open or still closing leaves the page
   locked — no scrollbar until a reload. So the lock is tied to what is on the page instead: without
   a shown dialog <body> scrolls, whatever was left behind. Bootstrap's JS alone sets aria-modal,
   from the start of showing until hiding has finished, so open and closing dialogs keep their lock.
   Blazor.Bootstrap's ConfirmDialog is the exception: it renders its own backdrop
   (.modal-backdrop-confirmation) only while open and locks <body> itself — so that counts too.
   !important beats the inline style. The leftover classes and backdrop elements are tidied by
   itkResetStuckBodyScrollLock (App.razor). */
body:not(:has(.modal[aria-modal="true"], .offcanvas[aria-modal="true"], .modal-backdrop-confirmation)) {
    overflow: visible !important;
    padding-right: 0 !important;
}

body:not(:has(.modal[aria-modal="true"], .offcanvas[aria-modal="true"], .modal-backdrop-confirmation)) > .modal-backdrop,
body:not(:has(.modal[aria-modal="true"], .offcanvas[aria-modal="true"], .modal-backdrop-confirmation)) > .offcanvas-backdrop {
    display: none !important;
}

/* ── Account pages (Login, ForgotPassword, ResetPassword) ────────────────────
   The k360 login card (manual Kap. 10.2), as in k360 Sign: centered on the app ground, 12 px radius,
   1 px edge, the product logo on top. The brand gradient may sit behind the card as a large, faint
   surface and as a thin bar on its top edge — it carries no text there (Kap. 10.3/11.2). Global rather
   than scoped: the three pages share every rule. */
.account-page {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 2rem 1rem;
    background:
        linear-gradient(112deg, rgb(11 107 203 / 0.14) 0%, rgb(91 63 214 / 0.14) 50%, rgb(8 129 153 / 0.14) 100%),
        var(--k-papier);
}

.account-card {
    position: relative;
    width: 100%;
    max-width: 440px;
    padding: 2.5rem 2rem 2rem;
    background: #fff;
    border: 1px solid var(--k-linie);
    border-radius: 12px;
    box-shadow: var(--k-sch-1);
    overflow: hidden;
}

    .account-card::before {
        content: "";
        position: absolute;
        inset: 0 0 auto 0;
        height: 4px;
        background: var(--k-markenverlauf);
    }

.account-card__header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.75rem;
    text-align: center;
}

.account-card__title {
    margin: 0;
    font-size: 1.4375rem;
}

.account-card__lead {
    margin: 0;
    color: var(--bs-secondary-color);
}

.account-card__link-row {
    display: flex;
    justify-content: flex-end;
    margin-top: 0.4rem;
}

.account-card__footer {
    margin-top: 1.5rem;
    text-align: center;
}
