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

/* BootstrapBlazor 11 paints every .card-body in --bs-body-bg, which in Skote is the page grey, so
   cards and the accordions in them blended into the page. Transparent lets the card's own
   background show again, as before 11. */
.card {
    --bs-card-body-bg: transparent;
}

.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;
}
/* One step per level, counted in nested <li> rather than in the component's class names:
   the row for level 3 has three <li> above it whatever the wrapper markup is called. Without
   this every row sits at the top-level padding, because the base rule overrides the inline
   padding-left the component computes from Indent * IndentSize. */
#sidebar-menu .menu li li .nav-link {
    padding-left: 2rem !important;
}
#sidebar-menu .menu li li li .nav-link {
    padding-left: 3rem !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. */
/* Course type names run to 80 characters; unclamped they push the row actions off a full HD
   screen. The title attribute carries the full name. */
.cell-clamp {
    display: inline-block;
    max-width: 18rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

/* A table cell lays its content out in a row; a second line (a deadline, a date) needs its own
   block to go underneath. */
.cell-stack {
    display: flex;
    flex-direction: column;
}

.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;
    text-decoration: none;            /* also used as a link, e.g. the slot date switcher */
}

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

/* Fachbereich pills, shared by the county overview and the quick-filter row of the lists: one
   look for one filter, whichever page it is read on. Inactive: outline only. Active: solid, same
   as the coloured entries in the month sheet. */
.filter-tabs-pills {
    align-items: center;
    gap: .375rem;
    padding-block: .375rem;
}

.field-filter {
    padding: .25rem .7rem;
    border: var(--bs-border-width) solid var(--field-color);
    border-radius: 999px;
    background-color: transparent;
    color: var(--bs-secondary-color);
    font-size: .8125rem;
    font-weight: 500;
    line-height: 1.5;
    white-space: nowrap;
}

.field-filter:hover {
    background-color: color-mix(in srgb, var(--field-color) 12%, transparent);
}

.field-filter-active {
    background-color: var(--field-color);
    border-color: var(--field-color);
    color: var(--field-text, #fff);
    font-weight: 600;
}

.field-filter-active:hover {
    background-color: var(--field-color);
    color: var(--field-text, #fff);
    filter: brightness(1.12);
}

/* Overview tiles: a count and a line or two around it. The theme gives every card a 24px bottom
   margin and no border, which in a gutter grid left uneven gaps and edges nobody could see. */
.overview-tile {
    margin-bottom: 0;
    border: 1px solid var(--bs-border-color);
}

.overview-tile-count {
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.3;
}

.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 organization picker carries the longest labels of all - "KBM-Ber. Land" plus a Feuerwehr
   name - and its dropdown inherits this width. Shrinks further when the strip is tight. */
.filter-bar-main .multi-select {
    flex-basis: 20rem;
    min-width: 13rem;
}

/* Filter button and hit count, kept together at the end of the strip. */
.filter-bar-actions {
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* 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;
}

/* The group separator in a multi-select list is a Divider: a 1px strip whose text is absolutely
   positioned and centered, so the label floated over the option above it. Turned into a plain
   full-width section header with the line above it. */
.multi-select .divider {
    height: auto;
    margin: 1.5rem 0 0;
    background-color: transparent;
    /* Derived from the text colour - --bs-border-color vanishes on the dark dropdown. */
    border-top: 1px solid rgba(var(--bs-body-color-rgb), 0.18);
}

.multi-select .divider .divider-mask {
    display: none;
}

/* Each group is closed by a divider of its own, so a closing one always meets the next opening
   one and the last group leaves one dangling. Only the opening one names what follows. */
.multi-select .divider:has(+ .divider),
.multi-select .divider:last-child {
    display: none;
}

.multi-select .divider .divider-text.is-center {
    position: static;
    left: auto;
    transform: none;
    display: block;
    width: 100%;
    padding: 1.25rem 0.75rem 0.5rem;
    background-color: transparent;
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
    font-weight: 600;
    text-align: start;
    text-transform: uppercase;
}

/* 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;
}

/* The dark palette mixes the alert tints at 25% of a bright hue, which over the card grey turns
   the amber warning into a muddy brown block. A lighter wash, carried by the border instead of
   the fill, keeps it a hint. */
[data-bs-theme="dark"] .alert {
    --bs-primary-bg-subtle: rgba(85, 110, 230, .12);
    --bs-secondary-bg-subtle: rgba(116, 120, 141, .12);
    --bs-success-bg-subtle: rgba(52, 195, 143, .12);
    --bs-info-bg-subtle: rgba(80, 165, 241, .12);
    --bs-warning-bg-subtle: rgba(241, 180, 76, .12);
    --bs-danger-bg-subtle: rgba(244, 106, 106, .12);
}

/* A soft button keeps its own hue, so on an alert's tint it reads as a second, unrelated colour --
   blue-on-brown again. Inside an alert it borrows the alert's text colour; a solid .btn-primary
   stays untouched, that one is meant to stand out. */
.alert .btn[class*="btn-soft-"] {
    color: inherit;
    background-color: rgba(var(--bs-emphasis-color-rgb), .08);
    border-color: rgba(var(--bs-emphasis-color-rgb), .35);
}

.alert .btn[class*="btn-soft-"]:hover,
.alert .btn[class*="btn-soft-"]:focus,
.alert .btn[class*="btn-soft-"]:focus-visible,
.alert .btn[class*="btn-soft-"]:active {
    color: inherit;
    background-color: rgba(var(--bs-emphasis-color-rgb), .18);
    border-color: currentColor;
}

/* Occupancy of a slot date. Narrow and short: it sits beside the figure it illustrates, and a bar
   the width of the card would read as a page-wide progress indicator. */
.slot-load-bar {
    height: 8px;
    max-width: 22rem;
}

/* A window that can be booked is itself the button. */
.slot-bookable {
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.slot-bookable:hover,
.slot-bookable:focus-visible {
    border-color: var(--bs-primary) !important;
    box-shadow: 0 0 0 .15rem rgba(var(--bs-primary-rgb), .2);
    outline: none;
}

/* Colour of a Fachbereich in its list row. The markup was there before the rule was, so the
   swatch rendered as an empty span — square rather than round, because it stands for a label on
   cards and calendar entries, not for a status. */
.course-field-swatch {
    display: inline-block;
    flex: 0 0 auto;
    width: .875rem;
    height: .875rem;
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, .12);
}

/* Alarmierung: map markers drawn by Leaflet outside any component's CSS scope. */
.alarm-map-unit span {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
    color: #fff;
    font-size: 11px;
    font-weight: 600;
}

.alarm-map-bma span {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 4px;
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
    background: #6d4c41;
    color: #fff;
    font-size: 12px;
    cursor: pointer;
}

.alarm-legend-swatch {
    display: inline-block;
    width: .875rem;
    height: .875rem;
    border-radius: 3px;
    border: 2px solid;
}

.alarm-map-handle span {
    display: block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 2px solid #d32f2f;
}
