.toast-container {
    position: fixed !important;
}

/* Hides the select column IsExcel forces on (it sets IsMultipleSelect itself). Head and body
   only: the select column never reaches the footer, and a footer that spans the whole row
   starts with the cell this rule would hide. Card view is listed separately -- it renders no
   <table>, so .table-excel is absent and only the checkbox in the cell identifies it. Without
   :has() this hid the first data field of every table below 768px, where RenderMode="Auto"
   switches to cards and the leading cell is a column like any other. */
.table-excel > tbody > tr > td:first-child,
.table-excel > thead > tr > th:first-child,
.table-card .table-row .table-cell:first-child:has(.form-check),
.table .fr .form-check {
    display: none
}

/* Opt-in: re-show the multi-select checkbox column hidden by the rules above. */
.table-select .table-excel > tbody > tr > td:first-child,
.table-select .table-excel > thead > tr > th:first-child {
    display: table-cell;
    width: 3rem;
    text-align: center;
    vertical-align: middle;
}

.table-select .table .fr .form-check,
.table-select .table-card .table-row .table-cell:first-child:has(.form-check) {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The checkbox lives in a .table-cell wrapper that collapses without a width. */
.table-select .table-excel > tbody > tr > td:first-child > .table-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    overflow: visible;
}

.table-select .table-excel > tbody > tr > td:first-child > .table-cell > .form-check {
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 6px 8px;
    min-height: auto;
}

/* Bootstrap's .form-check indents for a floated input; the table checkbox is centered instead. */
.table-select .table-excel > tbody > tr > td:first-child .form-check-input,
.table-select .table-excel > thead > tr > th:first-child .form-check-input {
    float: none;
    margin: 0;
}

.table-md-spacing .table-striped.table > :not(caption):not(thead) > * > *,
.table-md-spacing .table-excel.table > :not(caption):not(thead) > * > * {
    padding: .75rem .75rem;
    vertical-align: middle;
}

.table-sm-spacing .table-striped.table > :not(caption):not(thead) > * > *,
.table-sm-spacing .table-excel.table > :not(caption):not(thead) > * > * {
    padding: .25rem .25rem;
    vertical-align: middle;
}

.table-striped > tbody > tr:nth-of-type(odd) > *,
.table-excel > tbody > tr:nth-of-type(odd) > * {
    --bs-table-color-type: var(--bs-table-striped-color);
    --bs-table-bg-type: var(--bs-table-striped-bg)
}

.badge.bg-secondary
{
    color: #fff !important;
}

/* <Badge> emits text-bg-*, not bg-*, and Bootstrap pins the text colour there with !important --
   so a .bg-* rule never reaches it. .text-bg-light pins #000 while Skote flips --bs-light to the
   dark #32394e, and BootstrapBlazor pins #212529 on the mid-grey secondary. */
.badge.text-bg-light {
    color: var(--bs-emphasis-color) !important;
}

.badge.text-bg-secondary {
    color: #fff !important;
}

.datetime-picker .form-control.has-icon {
    padding-left: 33px;
}


/* ==========================================================================
   Sidebar navigation – BootstrapBlazor <Menu> styled to match the Skote
   sidebar. Replaces the former metismenu (.mm-active) styling. Active state /
   parent expansion is handled by the component itself.

   The colours come from the variables below rather than from literals: the
   sidebar is white in light mode and #2a3042 in dark mode, so the same text
   colour cannot serve both. Values are Skote's own ($sidebar-menu-* and
   $sidebar-dark-menu-* in _variables.scss), except the active colour, which is
   our red instead of Skote's near-black $red-800.
   ========================================================================== */
/* DOM rendered by <Menu IsVertical>:
   ul.menu.is-vertical > .nav > li
     > a.nav-link[.active]
         > div.submenu-link > i.<icon> + span.menu-text
         > i.arrow                         (only on parent rows)
     > ul.nav.submenu.collapse[.show]     (nested children)            */
/* Light sidebar (default) -- also the fallback if data-sidebar is missing. */
#sidebar-menu {
    --kfvkt-menu-color: #545a6d;
    --kfvkt-menu-icon-color: #7f8387;
    --kfvkt-menu-hover-color: #383c40;
    --kfvkt-menu-active-color: var(--bs-danger);
}

body[data-sidebar="dark"] #sidebar-menu {
    --kfvkt-menu-color: #a6b0cf;
    --kfvkt-menu-icon-color: #6a7187;
    --kfvkt-menu-hover-color: #ffffff;
    --kfvkt-menu-active-color: #ff6b6f;    /* our red lightened; #D92529 sinks into #2a3042 */
}

#sidebar-menu .menu,
#sidebar-menu .menu.is-vertical {
    --bb-menu-active-color: var(--kfvkt-menu-active-color);
    padding: 10px 0 30px 0;                /* override the component's 0 .5rem side padding */
    border: none;
    background: transparent;
    width: 100%;
}
#sidebar-menu .menu ul,
#sidebar-menu .menu .submenu {
    padding-left: 0;
    margin: 0;
    list-style: none;
}
#sidebar-menu ul li a i {
    font-size: 0.75rem;
    margin-left: -0.5rem;
}
#sidebar-menu .menu .nav {
    width: 100%;
    padding: 0;
    border-bottom: none;
}
#sidebar-menu .menu > .nav > li {
    border-bottom: none;
}
/* remove the default blue active indicator bar */
#sidebar-menu .menu > .nav > li:has(.active):after,
#sidebar-menu .menu > .nav > li:after {
    display: none;
}
/* top-level rows – force a single flex row so the arrow stays inline */
#sidebar-menu .menu .nav-link {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    /* !important beats the component's inline padding-left (Indent * IndentSize) */
    padding: 0.625rem 0.5rem 0.625rem 1.25rem !important;
    font-size: 13px;
    color: var(--kfvkt-menu-color);
    border-radius: 0;
    transition: all 0.4s;
}
#sidebar-menu .menu .nav-link > .submenu-link {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    display: flex;
    align-items: center;
    gap: 0.35rem;             /* space between icon and label */
    overflow: visible;        /* don't clip the label text */
    white-space: nowrap;
}
#sidebar-menu .menu .nav-link .submenu-link > i {
    display: inline-block;
    min-width: 1.75rem;
    font-size: 1.1rem;
    line-height: 1.40625rem;
    vertical-align: middle;
    color: var(--kfvkt-menu-icon-color);
    transition: all 0.4s;
}
#sidebar-menu .menu .submenu .submenu .nav-link .submenu-link > i {
    font-size: 0.9rem;
}
#sidebar-menu .menu .nav-link .menu-text {
    font-size: 13px;
    margin: 0;
}
#sidebar-menu .menu .nav-link > .arrow {
    flex: 0 0 auto;
    margin-left: auto;
    color: var(--kfvkt-menu-color);
}
#sidebar-menu .menu .nav-link:not(.disabled):hover {
    color: var(--kfvkt-menu-hover-color);
    background: transparent;
}
#sidebar-menu .menu .nav-link:not(.disabled):hover .submenu-link > i {
    color: var(--kfvkt-menu-hover-color);
}
/* The active row is the one place the brand colour shows in the menu. */
#sidebar-menu .menu .nav-link.active,
#sidebar-menu .menu .nav-link.active .submenu-link > i {
    color: var(--kfvkt-menu-active-color);
    background: transparent;
}
#sidebar-menu .menu .submenu .submenu .nav-link {
    padding-left: 2rem !important;
}
#sidebar-menu .menu .submenu .nav-link:not(.disabled):hover {
    color: var(--kfvkt-menu-hover-color);
}
#sidebar-menu .menu .submenu .nav-link.active {
    color: var(--kfvkt-menu-active-color);
}

@media print {
    .table-toolbar, .table-search, .table .filter-icon, .table thead .sort-icon, .table-page-info {
        display: none;
    }
}

/* Equipment badge. Global because several rental pages share it and scoped CSS would
   only reach the component it is defined in. */
.rental-badge {
    display: inline-block;
    background-color: var(--rental-color, #6B7280);
    color: #fff;
    padding: .15rem .55rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 500;
    white-space: nowrap;
}

/* Rental popover header. Global, not scoped: Bootstrap moves the popover out of the
   component. The page script supplies --pop-color. */
.rental-pop .popover-header {
    background-color: var(--pop-color, #B02A2A);
    color: #fff;
    border-bottom: none;
    font-weight: 600;
}

/* Consent checkboxes carry a full sentence. BootstrapBlazor sets nowrap + ellipsis on
   .form-check-label, which truncates the text on narrow screens instead of wrapping it. */
.form-check-wrap .form-check-label {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

/* ==========================================================================
   Page header — replaces the LayoutBreadcrumb + <h2> pair
   ========================================================================== */
.page-header {
    margin-bottom: 1.5rem;
}

/* Title left, actions right, on one line. min-height is a button's height, so the block is
   equally tall with and without actions and the title does not move between pages. */
.page-header-main {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 1rem;
    row-gap: .5rem;
    min-height: 2.375rem;
}

.page-header-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem;
    min-width: 0;
}

.page-header-actions {
    margin-left: auto;
}

.page-header-heading {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.3;
}

.page-header-subtitle {
    margin-left: .5rem;
    font-size: .8125rem;
    color: var(--bs-secondary-color);
}

/* iOS has no visible back button in a home-screen web app. */
.page-header-back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    margin-right: .25rem;
    border-radius: 50%;
    color: var(--bs-secondary-color);
    font-size: 1.1rem;
    text-decoration: none;
}

.page-header-back:hover,
.page-header-back:focus-visible {
    color: var(--kfvkt-accent);
    background-color: rgba(var(--bs-primary-rgb), .1);
}

/* The switcher is an ActionMenu; its chevron carries more presence than a row kebab. */
.page-header-title .action-menu-wrap {
    display: inline-flex;
}

.page-header-title .action-menu > .dropdown-toggle {
    font-size: 1.05rem;
    padding: .125rem .35rem;
}

@media (max-width: 575.98px) {
    .page-header-heading {
        font-size: 1.125rem;
    }

    /* Own line instead of competing with the title for width. */
    .page-header-subtitle {
        flex-basis: 100%;
        margin-left: 0;
    }

    /* Actions onto their own row: sharing it with the title leaves neither enough width. */
    .page-header-actions {
        flex-basis: 100%;
        margin-left: 0;
    }
}


/* ==========================================================================
   Sub-navigation — underline tabs. The stretched, filled pills they replace read
   as buttons next to the real action buttons.
   ========================================================================== */
.subnav {
    display: flex;
    align-items: stretch;
    gap: 1.5rem;
    margin-top: .875rem;
    border-bottom: 1px solid var(--bs-border-color);
    overflow-x: auto;
    scrollbar-width: none;
}

.subnav::-webkit-scrollbar {
    display: none;
}

.subnav .nav-link {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .625rem 0;
    margin-bottom: -1px;              /* the bar sits on the baseline */
    border-bottom: 2px solid transparent;
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    font-weight: 500;
    white-space: nowrap;
}

.subnav .nav-link:hover {
    color: var(--bs-body-color);
    border-bottom-color: var(--bs-secondary-color);
}

.subnav .nav-link.active {
    color: var(--kfvkt-accent);
    border-bottom-color: var(--kfvkt-accent);
    font-weight: 600;
}

.subnav .subnav-count {
    padding: .2rem .4rem;
    border-radius: 999px;
    background-color: rgba(var(--bs-emphasis-color-rgb, 33, 37, 41), .07);
    color: inherit;
    font-size: .6875rem;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.subnav .nav-link.active .subnav-count {
    background-color: rgba(var(--bs-primary-rgb), .12);
}

/* ==========================================================================
   Row actions — the kebab, and the clickable row it belongs to
   ========================================================================== */

/* BootstrapBlazor splats `class` onto the outer btn-group, so the toggle itself
   is reached from here rather than through a parameter. */
.action-menu-wrap {
    display: inline-flex;
}

.action-menu > .dropdown-toggle {
    padding: .25rem .5rem;
    line-height: 1.2;
    color: var(--bs-secondary-color);
    background-color: transparent;
    border-color: transparent;
}

.action-menu > .dropdown-toggle:hover,
.action-menu > .dropdown-toggle:focus-visible,
.action-menu.show > .dropdown-toggle {
    color: var(--kfvkt-accent);
    background-color: rgba(var(--bs-primary-rgb), .1);
}

.action-menu > .dropdown-toggle::after {
    display: none;                    /* the icon already says "menu" */
}

/* .is-clickable and its pointer cursor come from the Table; only the tint is ours. */
.is-clickable .table > tbody > tr:hover > * {
    --bs-table-bg-type: rgba(var(--bs-primary-rgb), .06);
}

/* Card view: the action column would otherwise be a full-width row labelled "Aktionen". */
.table-card .table-row {
    position: relative;
    padding-right: 3rem;
}

.table-card .table-row .table-cell-actions {
    position: absolute;
    top: .5rem;
    right: .5rem;
    padding-bottom: 0;
}

.table-card .table-row .table-cell-actions > label {
    display: none;
}

.row-link {
    color: inherit;
    font-weight: 600;
    text-decoration: none;
}

.row-link:hover {
    color: var(--kfvkt-accent);
    text-decoration: underline;
}

/* ==========================================================================
   Form footer — sticky, so Speichern stays reachable in the long forms
   ========================================================================== */

/* Skote's overflow: hidden makes .main-content a scroll container that never scrolls, so
   sticky has nothing to stick to; clip does not. Scoped, because unlike hidden it establishes
   no block formatting context and would stop containing floats app-wide. */
.main-content:has(.form-footer) {
    overflow: clip;
}

/* Sticky clamps to the containing block, so on a form shorter than the viewport the bar
   stopped wherever the card ended. The page fills the viewport instead, and the chain from
   .page-content down to the bar becomes a column flex box so the bar's auto margin can eat
   the slack. :has() picks exactly the bar's ancestors, whatever the individual form wraps it
   in — card, card-body, the ValidateForm's <form>. */
.main-content:has(.form-footer) .page-content {
    /* box-sizing: border-box, so this is the viewport exactly. */
    min-height: 100vh;
    /* Skote's 60px would leave the bar floating above the lower edge. */
    padding-bottom: 0;
    display: flex;
    flex-direction: column;
}

.main-content:has(.form-footer) .page-content *:has(.form-footer) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.form-footer {
    position: sticky;
    bottom: 0;
    /* Above Leaflet, whose controls reach 1000, and below Bootstrap's modal at 1055. */
    z-index: 1020;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    margin-top: auto;
    padding: .75rem 0;
    background-color: var(--bs-body-bg);
    border-top: 1px solid var(--bs-border-color);
    /* Bleeds through the padding of what it closes off, so the rule reaches that block's
       edges while the buttons keep their distance from them. */
    margin-inline: calc(var(--bs-gutter-x, 1.5rem) / -2);
    padding-inline: calc(var(--bs-gutter-x, 1.5rem) / 2);
}

/* The forms that sit in a card: there the enclosing block is the card, not the container. */
.card-body .form-footer {
    margin-inline: calc(var(--bs-card-spacer-x, 1.25rem) * -1);
    padding-inline: var(--bs-card-spacer-x, 1.25rem);
}

/* ==========================================================================
   Filter bar — replaces the collapsible "Suche" card above a list
   ========================================================================== */

/* Opt-in per list: turns the float-based toolbar into a flex row, so the filter bar and
   the table buttons share one strip instead of stacking. */
.list-toolbar .table-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: .75rem 1rem;
    margin-bottom: .75rem;
}

.list-toolbar .table-toolbar > .float-start {
    float: none !important;
    flex: 1 1 22rem;
    min-width: 0;
}

.list-toolbar .table-toolbar > .table-column-right {
    float: none !important;
    flex: 0 0 auto;
    margin-left: auto;
}

/* The action column takes its width from its content instead of a fixed one. That is what keeps
   the rows filling the container: BootstrapBlazor sums the <col> widths in getTableWidth and pins
   the total on the table as an inline width, and a pinned column made that sum fall short. With
   no width on any column there is nothing to sum, and width: 1% collapses the cell to the kebab
   while the remaining columns share what is left.

   Not in card view, where the same cell is pinned to the card's corner. */
table td.table-cell-actions,
table th.table-cell-actions {
    width: 1%;
    white-space: nowrap;
}

/* Belt and braces for tables whose widths were pinned before, e.g. from localStorage: the
   property wins against the inline attribute without capping tables that really are wider
   than the viewport. Keyed on the action column as well as the list wrapper, because the same
   table sits on pages without a filter bar around it, e.g. the persons of a youth group. */
.list-toolbar table,
.table-responsive table:has(.table-cell-actions),
.list-toolbar .table-container,
.list-toolbar .table-wrapper,
.list-toolbar .table-scroll {
    min-width: 100%;
}

.filter-bar {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

/* The quick-filter line above the strip: underline tabs, as the sub-navigation uses them, so
   neither row is mistaken for buttons. The label stays put while the tabs scroll. */
.filter-tabs-row {
    display: flex;
    align-items: stretch;
    gap: 1rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.filter-tabs-label {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    padding: .5rem 0;
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    font-weight: 600;
    white-space: nowrap;
}

/* min-width: 0 is what lets it scroll instead of stretching its flex parent — in the table
   toolbar the bar only gets a share of the row, next to Aktualisieren/Spalten/Export. */
.filter-tabs {
    display: flex;
    align-items: stretch;
    flex: 1 1 auto;
    min-width: 0;
    gap: 1.25rem;
    overflow-x: auto;
    scrollbar-width: none;
}

.filter-tabs::-webkit-scrollbar {
    display: none;
}

.filter-tab {
    padding: .5rem 0;
    margin-bottom: -1px;              /* the bar sits on the row's baseline */
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    font-weight: 500;
    white-space: nowrap;
}

.filter-tab:hover {
    color: var(--bs-body-color);
    border-bottom-color: var(--bs-secondary-color);
}

.filter-tab.active {
    color: var(--kfvkt-accent);
    border-bottom-color: var(--kfvkt-accent);
    font-weight: 600;
}

.filter-bar-main {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem;
}

/* Same height as the table buttons, so the strip reads as one row. */
.filter-bar-main .form-control,
.filter-bar-main .dropdown-toggle,
.filter-bar-toggle {
    min-height: 2.375rem;
}

.filter-bar-search {
    flex: 1 1 20rem;
    min-width: 14rem;
}

/* Room for the longest option instead of truncating it. */
.filter-bar-main .select,
.filter-bar-main .multi-select {
    flex: 0 1 14rem;
    min-width: 11rem;
}

/* The multi-select grows with its chosen items; capped here so two areas cannot push the
   strip into a second row. */
.filter-bar-main .multi-select .dropdown-toggle {
    max-height: 2.375rem;
}

/* A checkbox among the fields. Bootstrap's .form-check is a block with a bottom margin, so it
   would hang above the baseline of the search field instead of sitting on it. */
.filter-bar-main .form-check {
    display: flex;
    align-items: center;
    min-height: 2.375rem;
    margin-bottom: 0;
}

/* A button sitting at the end of a text field — the magnifier of the search box, the plus of
   the tag picker. Saves explaining in the placeholder that Enter is what applies the field. */
.field-with-action {
    position: relative;
}

.field-with-action .form-control {
    padding-right: 2.5rem;
}

.field-inline-btn {
    position: absolute;
    top: 50%;
    right: .25rem;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 0;
    border-radius: .25rem;
    background: none;
    color: var(--bs-secondary-color);
    font-size: 1.05rem;
    line-height: 1;
}

.field-inline-btn:hover,
.field-inline-btn:focus-visible {
    color: var(--kfvkt-accent);
    background-color: rgba(var(--bs-primary-rgb), .1);
}

.field-inline-btn:disabled {
    opacity: .4;
}

.field-inline-btn:disabled:hover {
    color: var(--bs-secondary-color);
    background: none;
}

.field-inline-btn.is-static {
    pointer-events: none;
}

/* Number of active filters. */
.filter-bar-count {
    display: inline-block;
    min-width: 1.25rem;
    margin-left: .35rem;
    padding: 0 .3rem;
    border-radius: 999px;
    background-color: rgba(var(--bs-primary-rgb), .18);
    color: var(--kfvkt-accent);
    font-size: .6875rem;
    font-weight: 600;
    line-height: 1.25rem;
    font-variant-numeric: tabular-nums;
}

.filter-bar-result {
    margin-left: .25rem;
    margin-right: .25rem;
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.filter-bar-more {
    margin-top: .25rem;
    padding: .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .375rem;
    background-color: rgba(var(--bs-emphasis-color-rgb, 33, 37, 41), .02);
}

.filter-bar-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

/* line-height: 1 on both children, height from the padding: the label carries emoji and the
   close icon its own font, and their differing half-leading is what pushed the text off centre. */
.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: transparent;
    color: var(--bs-body-color);
    font-size: .8125rem;
    line-height: 1;
}

.filter-chip:hover,
.filter-chip:focus-visible {
    border-color: var(--kfvkt-accent);
    color: var(--kfvkt-accent);
}

.filter-chip > i {
    font-size: 1rem;
    line-height: 1;
    opacity: .6;
}

/* Quiet on purpose: as a dark button it was the loudest element on the page. */
.filter-bar-reset {
    padding: .25rem .5rem;
    border: 0;
    background: none;
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    text-decoration: underline;
}

.filter-bar-reset:hover,
.filter-bar-reset:focus-visible {
    color: var(--kfvkt-accent);
}

/* Table buttons (Aktualisieren / Spalten / Export): as dark filled buttons they
   outweighed the filters next to them, though they are the least used controls here. */
.list-toolbar .table-column-right .btn {
    background-color: rgba(var(--bs-secondary-rgb), .1);
    border-color: transparent;
    color: var(--bs-secondary-color);
}

.list-toolbar .table-column-right .btn:hover,
.list-toolbar .table-column-right .btn:focus-visible,
.list-toolbar .table-column-right .show > .btn {
    background-color: rgba(var(--bs-primary-rgb), .12);
    color: var(--kfvkt-accent);
}

/* Hidden visually, never removed: the refresh button carries no title, so this text is
   its only accessible name. At every width, so phones keep it too. */
.list-toolbar .table-column-right .btn > span.d-sm-inline-block {
    position: absolute !important;
    display: inline-block !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Bootstrap's pressed inset shadow reads as a stray dark edge on flat icon buttons.
   Keyboard focus keeps a ring, in the accent colour. */
.list-toolbar .table-column-right .btn:focus,
.list-toolbar .table-column-right .btn:active,
.list-toolbar .table-column-right .btn.active,
.list-toolbar .table-column-right .btn.show,
.list-toolbar .table-column-right .show > .btn,
.action-menu > .dropdown-toggle:focus,
.action-menu > .dropdown-toggle:active,
.action-menu.show > .dropdown-toggle {
    box-shadow: none;
    border-color: transparent;
}

.list-toolbar .table-column-right .btn:focus-visible,
.action-menu > .dropdown-toggle:focus-visible {
    box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .25);
}

/* ==========================================================================
   Table summary — the footer band of a list
   ========================================================================== */

/* The totals belong to no single column, so they get one band across the row instead of the
   badge grid in a col-md-2 raster that lined up with nothing. */
.table-summary {
    padding: .75rem 1rem;
    /* Bootstrap paints its table cells with an inset shadow, so the tint has to go through the
       variable that shadow reads — a background-color alone stays behind it and never shows. */
    --bs-table-bg-type: var(--bs-tertiary-bg);
    background-color: var(--bs-tertiary-bg);
    border-top: 2px solid var(--bs-border-color);
}

.table-summary-stats {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 2rem;
}

.table-summary-stat {
    display: flex;
    flex-direction: column;
    gap: .125rem;
}

/* Small, spaced and quiet: the number is what the band is read for. */
.table-summary-label {
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--bs-secondary-color);
}

/* tabular-nums, so the digits of neighbouring stats stand under each other. */
.table-summary-value {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    color: var(--bs-emphasis-color);
}

.table-summary-note {
    margin-left: .25rem;
    font-size: .75rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

/* ==========================================================================
   Sort list — a list whose order is the data
   ========================================================================== */

/* Rows instead of a table: the order of these lookup types is a field of their own, and
   dragging is the only way to set it that does not make people type numbers. */
.sort-list {
    display: flex;
    flex-direction: column;
    gap: .375rem;
}

.sort-list-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .5rem .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: .375rem;
    background-color: var(--bs-body-bg);
}

/* Only the grip drags: the row carries a link and a kebab menu, and a drag started on those
   would swallow the click meant for them. */
.sort-list-handle {
    color: var(--bs-secondary-color);
    cursor: grab;
}

.sort-list-handle:active {
    cursor: grabbing;
}

/* Placeholder in the disabled state, so the rows keep their columns while sorting is off. */
.sort-list-handle.is-disabled {
    opacity: .35;
    cursor: default;
}

.sort-list-title {
    flex: 1 1 auto;
    min-width: 0;
}

.sort-list-meta {
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    white-space: nowrap;
}

/* While dragging: the gap the row would fall into. */
.sort-list-ghost {
    opacity: .4;
    background-color: var(--bs-tertiary-bg);
}

.sort-list-note {
    margin: .75rem 0 0;
    font-size: .8125rem;
    color: var(--bs-secondary-color);
}

/* Step header of the public wizards (handover, booking request). Decorative only — the
   navigation sits in the card below it, so the component's own body stays hidden. */
.rental-steps .step-body {
    display: none;
}

/* Bulk-action strip above a list, shown only while rows are ticked. The tint is kept very light
   and carries a border instead: at .08 the soft action buttons inside it stopped standing out. */
.selection-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem;
    margin-bottom: .75rem;
    padding: .5rem .75rem;
    border: 1px solid rgba(var(--bs-primary-rgb), .25);
    border-radius: var(--bs-border-radius);
    background-color: rgba(var(--bs-primary-rgb), .03);
}

.selection-bar-count {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    color: var(--kfvkt-accent);
    font-size: .8125rem;
    font-weight: 500;
}

.selection-bar-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

/* Pushed to the far end so it is not mistaken for one of the actions. */
.selection-bar-clear {
    margin-left: auto;
}

/* The card-specific rule for this row drops align-items, so the delete button sits too high. */
.upload .upload-body.is-card .upload-item .upload-item-actions {
    align-items: center;
}

/* Same box as the zoom and delete buttons so all three line up. */
.upload-item-actions .attachment-main-toggle {
    display: flex;
    align-items: center;
    padding: .25rem;
    line-height: 1;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.upload-item-actions .attachment-main-toggle[title="Als Hauptbild verwenden"] {
    cursor: pointer;
}

.upload-item-actions .attachment-main-toggle[title="Als Hauptbild verwenden"]:hover {
    background-color: var(--bs-secondary-bg);
}

/* Every card we render is already stored, so the green ribbon is noise; the red one stays. */
.upload .upload-body.is-card .upload-item.is-valid .upload-item-label {
    display: none;
}

/* Same for the green frame: match the add tile's neutral border. */
.upload .upload-body.is-card .upload-item.is-valid {
    border-color: var(--bs-border-color);
}

/* Ships as a filled btn-secondary, the heaviest element in the row; match the outline style. */
.upload .upload-body.is-card .upload-item-actions .btn-zoom {
    color: var(--bs-secondary-color);
    background-color: transparent;
    border: 1px solid var(--bs-border-color);
}

.upload .upload-body.is-card .upload-item-actions .btn-zoom:hover {
    color: var(--bs-body-color);
    background-color: var(--bs-secondary-bg);
}

/* Round the thumbnail to match the initials avatar. */
.person-avatar,
.person-avatar .bb-viewer,
.person-avatar .bb-img {
    border-radius: 50%;
    overflow: hidden;
}

/* Avatar's own #fff on #c0c4cc is about 2:1; an emphasis tint flips with the theme. */
.person-avatar-initials > .avatar {
    --bb-avatar-bg: rgba(var(--bs-emphasis-color-rgb), .1);
    --bb-avatar-color: var(--bs-emphasis-color);
    font-weight: 600;
}

/* --- Theme switch --------------------------------------------------------

   The switch keeps no state of its own. Which icon shows and which entry reads as chosen is
   decided here, from the attributes theme.js writes on <html> -- the markup in ThemeToggle.razor
   never changes, so a Blazor rerender cannot revert it, and the account pages (static SSR, no
   circuit) get the same behaviour for free. */

/* Dropdown renders a plain btn; give it the header-item look the fullscreen button has. */
.theme-switch > .dropdown-toggle {
    height: 70px;
    padding: 0 0.75rem;
    border: 0;
    border-radius: 0;
    background-color: transparent;
    color: var(--bs-header-item-color);
    box-shadow: none;
}

.theme-switch > .dropdown-toggle i {
    font-size: 22px;
    vertical-align: middle;
}

.theme-switch > .dropdown-toggle::after {
    display: none;                    /* the icon already says what this is */
}

.theme-switch > .dropdown-toggle:hover,
.theme-switch > .dropdown-toggle:focus-visible,
.theme-switch.show > .dropdown-toggle {
    color: var(--kfvkt-accent);
    background-color: rgba(var(--bs-primary-rgb), .1);
}

.theme-switch-icon {
    display: none;
}

html[data-theme-choice="light"] .theme-switch-icon[data-for="light"],
html[data-theme-choice="dark"] .theme-switch-icon[data-for="dark"],
html[data-theme-choice="auto"] .theme-switch-icon[data-for="auto"] {
    display: inline-block;
}

.theme-switch .dropdown-menu {
    min-width: 11rem;
}

.theme-switch .dropdown-item {
    display: flex;
    align-items: center;
}

.theme-switch-check {
    margin-left: auto;
    visibility: hidden;
}

html[data-theme-choice="light"] .theme-switch [data-choice="light"],
html[data-theme-choice="dark"] .theme-switch [data-choice="dark"],
html[data-theme-choice="auto"] .theme-switch [data-choice="auto"] {
    color: var(--kfvkt-accent);
    font-weight: 600;
}

html[data-theme-choice="light"] .theme-switch [data-choice="light"] .theme-switch-check,
html[data-theme-choice="dark"] .theme-switch [data-choice="dark"] .theme-switch-check,
html[data-theme-choice="auto"] .theme-switch [data-choice="auto"] .theme-switch-check {
    visibility: visible;
}

.theme-switch-hint {
    padding: 0.15rem 1rem 0.35rem;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

/* The hint only says something while we are following the system. */
html:not([data-theme-choice="auto"]) .theme-switch-hint,
html:not([data-theme-choice="auto"]) .theme-switch-hint-divider {
    display: none;
}

.theme-switch-hint [data-when-theme] {
    display: none;
}

html[data-bs-theme="light"] .theme-switch-hint [data-when-theme="light"],
html[data-bs-theme="dark"] .theme-switch-hint [data-when-theme="dark"] {
    display: inline;
}

/* Bootstrap keeps the light link colour in dark mode, and #556ee6 barely lifts off
   #222736 -- worst of all on the tinted alert backgrounds. Lighten the link tokens so
   every plain <a>, .alert-link and .btn-link follows. */
[data-bs-theme="dark"] {
    --bs-link-color: #8fa2ff;
    --bs-link-color-rgb: 143, 162, 255;
    --bs-link-hover-color: #b3c0ff;
    --bs-link-hover-color-rgb: 179, 192, 255;
}

/* --bs-primary is light-only, so accent text -- active tab, hover states, count chips -- had the
   links' 3:1. It rides the link tokens instead; the rgba() tints stay, they are backgrounds. One
   declaration covers both themes: data-bs-theme sits on <html>, the same element as :root. */
:root {
    --kfvkt-accent: var(--bs-link-color);
}

/* Alerts tint their own text; a link inside one has to sit on that tint, not on the
   page background, or it turns into the blue-on-brown we had. */
.alert .alert-link,
.alert a:not(.btn) {
    color: inherit;
    text-decoration-color: rgba(var(--bs-body-color-rgb), .4);
    font-weight: 600;
}

.alert .alert-link:hover,
.alert a:not(.btn):hover {
    color: inherit;
    text-decoration-color: currentColor;
}
