/* =============================================================================
 * vsuite — vtable.css
 *
 * Styling für die geteilten UX-Komponenten `assets/vtable.js` (sortier-/
 * filterbare Tabellen) und `assets/vselect.js` (durchsuchbare Dropdowns).
 *
 * BRAND-NEUTRAL: alle Farben leiten sich aus Bootstrap-5-Tokens ab
 * (`--bs-primary`, `--bs-primary-rgb`, `--bs-warning-rgb`, `--bs-border-color`),
 * die jede VIERLING App ohnehin setzt → die Komponenten übernehmen automatisch
 * das App-Branding. Pro App überschreibbar via:
 *   --vt-accent       Akzentfarbe (Chips, Auswahl)  [Default: --bs-primary]
 *   --vt-accent-rgb   Akzent als RGB-Tripel          [Default: --bs-primary-rgb]
 *   --vt-hl-bg        Hintergrund der Filter-Treffer [Default: warning-subtil]
 * ========================================================================== */

:root {
    --vt-accent:     var(--bs-primary, #0d6efd);
    --vt-accent-rgb: var(--bs-primary-rgb, 13, 110, 253);
    --vt-hl-bg:      rgba(var(--bs-warning-rgb, 255, 193, 7), 0.5);
}

/* ---- vtable.js (Sortier-/Filter-Tabellen) ------------------------------- */
.vtable-toolbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
    flex-wrap: wrap;
}
.vtable-filter { max-width: 22rem; }
.vtable-count { white-space: nowrap; }
/* In Cards (Tabelle randlos) den Filter etwas einrücken, statt an der Kante zu kleben. */
.card > .vtable-toolbar,
.card-body > .vtable-toolbar { padding: 0.65rem 0.75rem 0; }

/* Pager-Leiste (data-vtable-page-size) unter der Tabelle. */
.vtable-pager {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.5rem;
    flex-wrap: wrap;
}
.vtable-pager-info { white-space: nowrap; }
.vtable-pager-size {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    white-space: nowrap;
    margin-inline-start: auto;
}
.vtable-pager-size .form-select { width: auto; }
.card > .vtable-pager,
.card-body > .vtable-pager { padding: 0 0.75rem 0.65rem; }

/* Paginierte Tabellen: Zeilen bis zur Initialisierung verstecken — sonst
   flackern erst tausende Zeilen auf, bevor vtable.js den Seitenausschnitt
   schneidet (initTable setzt .vtable-ready). */
table.vtable[data-vtable-page-size]:not(.vtable-ready) > tbody > tr { display: none; }

th.vtable-sortable {
    cursor: pointer;
    user-select: none;
    position: relative;
    padding-right: 1.3rem;
}
th.vtable-sortable:hover { color: var(--vt-accent); }
th.vtable-sortable::after {
    content: "\F575"; /* bi-chevron-expand */
    font-family: "bootstrap-icons";
    position: absolute;
    right: 0.45rem;
    opacity: 0.3;
    font-size: 0.8em;
}
th.vtable-sort-asc::after  { content: "\F235"; opacity: 0.9; } /* bi-chevron-up */
th.vtable-sort-desc::after { content: "\F229"; opacity: 0.9; } /* bi-chevron-down */

/* Spaltenbreite per Ziehen (data-vtable-resize). Der Griff ist bewusst breiter
   als der sichtbare Strich — 1 px trifft niemand mit der Maus. */
th.vtable-resizable { position: relative; }
th .vtable-resizer {
    position: absolute;
    top: 0;
    right: -3px;
    bottom: 0;
    width: 7px;
    cursor: col-resize;
    z-index: 2;
    touch-action: none;
}
th .vtable-resizer::before {
    content: "";
    position: absolute;
    top: 25%;
    bottom: 25%;
    left: 3px;
    width: 1px;
    background: currentColor;
    opacity: 0.18;
}
th:hover .vtable-resizer::before,
table.vtable-resizing th .vtable-resizer::before { opacity: 0.55; }
/* Eingefrorene Breiten: die gesetzte Breite ist die AUSSENbreite. Ohne
   border-box käme das Zellen-Padding obendrauf, und jede Spalte wüchse beim
   ersten Anfassen um ein paar Pixel. */
table.vtable-resized > thead > tr > th { box-sizing: border-box; }
/* Eingefrorene Breiten: Überlauf abschneiden statt die Spalte aufzuspreizen. */
table.vtable-resized > tbody > tr > td { overflow: hidden; text-overflow: ellipsis; }
table.vtable-resizing { user-select: none; cursor: col-resize; }

mark.vtable-hl {
    background: var(--vt-hl-bg);
    color: inherit;
    padding: 0;
    border-radius: 0.15rem;
}

/* Pro-Spalten-Filterzeile (opt-in via data-vtable-colfilter). */
.vtable-filterrow > .vtable-filtercell {
    padding: 0.3rem 0.4rem;
    font-weight: 400;
    vertical-align: middle;
}
.vtable-filterrow > .vtable-filtercell:empty { padding: 0; }
/* Nicht als Sortier-Kopf missverstehen: kein Zeiger, kein Chevron. */
.vtable-filterrow > .vtable-filtercell::after { content: none; }
.vtable-filterrow .form-control,
.vtable-filterrow .form-select { min-width: 6rem; }

/* ---- vselect.js (durchsuchbare Dropdowns) ------------------------------- */
.vselect { position: relative; }
/* Das native <select> bleibt im DOM (Form-Post), ist aber unsichtbar. min-/max-width
   MÜSSEN mit: eine App-seitige Breitenangabe am <select> (z. B. min-width:19rem für
   das Control) würde sonst width:1px schlagen und die Seite horizontal aufreißen. */
.vselect-native {
    position: absolute !important;
    width: 1px !important; height: 1px !important;
    min-width: 0 !important; max-width: 1px !important;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0);
    border: 0;
}
.vselect-control {
    text-align: left;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.25rem;
    min-height: calc(1.5em + 0.75rem + 2px);
    width: 100%;
}
.vselect-control.form-select-sm { min-height: calc(1.5em + 0.5rem + 2px); }
.vselect-label { flex: 1 1 auto; min-width: 0; }
.vselect-label.vselect-placeholder { color: #6c757d; }

.vselect-chip {
    background: var(--vt-accent);
    color: #fff;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}
.vselect-chip { max-width: 100%; min-width: 0; }
.vselect-chip-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.vselect-chip-x { cursor: pointer; font-weight: 700; line-height: 1; flex: 0 0 auto; }
.vselect-chip-x:hover { opacity: 0.7; }

/* Breite = längster Eintrag (nie schmaler als das Control, gedeckelt auf den
   Viewport). Ein Dropdown, das seine Einträge umbricht, ist unlesbar — lieber
   breiter werden und im Extremfall mit Ellipse kürzen. */
.vselect-panel {
    position: absolute;
    z-index: 1056; /* über Modals/Dropdowns */
    top: calc(100% + 2px);
    left: 0;
    width: max-content;
    min-width: 100%;
    max-width: min(42rem, calc(100vw - 1.5rem));
    background: #fff;
    /* Textfarbe explizit setzen, NICHT erben: das Panel bringt seinen eigenen
       weissen Grund mit und haengt oft in einem eingefaerbten Container (z. B.
       einer Aktionsleiste mit color:#fff). Ohne diese Zeile erbt es die
       Schriftfarbe des Containers — weisse Schrift auf weissem Panel. */
    color: var(--bs-body-color, #212529);
    border: 1px solid var(--bs-border-color, rgba(0, 0, 0, 0.15));
    border-radius: 0.5rem;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
    padding: 0.4rem;
}
/* Aus demselben Grund die Eingabe im Panel: erbt sonst die Container-Farbe. */
.vselect-panel .vselect-search,
.vselect-panel .vselect-search input { color: var(--bs-body-color, #212529); }
/* Nahe am rechten Rand nach links aufklappen (setzt vselect.js beim Öffnen). */
.vselect-panel-end { left: auto; right: 0; }
/* Unten im Viewport (z. B. fixierte Aktionsleiste) nach oben aufklappen —
   sonst liegt das Panel ausserhalb des Bildes (setzt vselect.js beim Öffnen). */
.vselect-panel-up { top: auto; bottom: calc(100% + 2px); }
/* Steckt das Dropdown in einem Scroll-Kasten (.table-responsive, overflow-auto,
   Modal-Koerper), wird ein absolut positioniertes Panel an dessen Kante
   abgeschnitten. Dann setzt vselect.js es per Viewport-Koordinaten — die
   Ausrichtungsklassen oben duerfen dabei nicht mehr mitreden. */
.vselect-panel-fixed {
    position: fixed;
    right: auto;
    bottom: auto;
    max-width: calc(100vw - 1rem);
}
.vselect-search { margin-bottom: 0.35rem; }
.vselect-options { max-height: 20rem; overflow-y: auto; }
.vselect-option {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.35rem 0.5rem;
    border-radius: 0.35rem;
    cursor: pointer;
    line-height: 1.3;
}
.vselect-option:hover,
.vselect-option.vselect-active { background: rgba(var(--vt-accent-rgb), 0.1); }
.vselect-option.vselect-selected { font-weight: 600; color: var(--vt-accent); }
.vselect-option-disabled { opacity: 0.5; cursor: not-allowed; }
.vselect-check { color: var(--vt-accent); }
.vselect-empty { padding: 0.5rem; text-align: center; }

/* Abschnittsüberschrift aus <optgroup label="…">. */
.vselect-group {
    padding: 0.5rem 0.5rem 0.15rem;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #8a94a0;
}
.vselect-group:not(:first-child) {
    margin-top: 0.25rem;
    border-top: 1px solid var(--bs-border-color, rgba(0, 0, 0, 0.12));
    padding-top: 0.5rem;
}

/* Label + optionale Erklärzeile (data-hint) untereinander — beide einzeilig. */
.vselect-option-body { display: flex; flex-direction: column; min-width: 0; }
.vselect-option-body > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.vselect-option-hint {
    font-size: 0.72rem;
    font-weight: 400;
    line-height: 1.25;
    color: #8a94a0;
}

/* Struktur-Icon vor dem Label (data-icon). */
.vselect-option-icon { flex: 0 0 auto; color: #8a94a0; font-size: 0.9em; }
.vselect-option.vselect-selected .vselect-option-icon { color: inherit; }

/* Hierarchie (data-depth) als Einrückung mit dezenter Führungslinie — der
   Optionstext bleibt dadurch frei von „› ›"-Präfixen und bricht nicht um. */
.vselect-option-nested {
    padding-inline-start: calc(0.5rem + var(--vselect-depth, 0) * 0.85rem);
    position: relative;
}
.vselect-option-nested::before {
    content: "";
    position: absolute;
    inset-block: 0.15rem;
    inset-inline-start: calc(0.25rem + (var(--vselect-depth, 1) - 1) * 0.85rem);
    border-inline-start: 1px solid var(--bs-border-color, rgba(0, 0, 0, 0.15));
}

/* ---- vfiltermenu.js (Spaltenfilter mit Checkbox-Liste) ------------------ */
.vfm {
    position: fixed;
    z-index: 1080;
    width: 18rem;
    display: flex;
    flex-direction: column;
    gap: .4rem;
    padding: .6rem;
    background: var(--bs-body-bg, #fff);
    color: var(--bs-body-color);
    border: 1px solid var(--bs-border-color);
    border-radius: .5rem;
    font-size: .85rem;
    overflow: hidden;
}
.vfm-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vfm-sort { display: flex; flex-wrap: wrap; gap: .3rem; }
.vfm-sort .btn { flex: 1 1 auto; }
.vfm-bulk { display: flex; gap: .75rem; align-items: center; }
.vfm-list { overflow-y: auto; min-height: 2rem; flex: 1 1 auto; overscroll-behavior: contain; }
.vfm-item { margin: 0; padding: .15rem .1rem .15rem 1.6rem; border-radius: .25rem; }
.vfm-item:hover { background: var(--bs-tertiary-bg); }
.vfm-item .form-check-label { display: flex; gap: .35rem; align-items: baseline; width: 100%; cursor: pointer; min-width: 0; }
.vfm-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vfm-hint { color: var(--bs-secondary-color); font-size: .75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vfm-count { margin-left: auto; color: var(--bs-secondary-color); font-size: .75rem; font-variant-numeric: tabular-nums; }
.vfm-empty { color: var(--bs-secondary-color); padding: .25rem; }

/* vtable-Filterzeile im Modus data-vtable-filter="checks" */
.vtable-checks-btn { width: 100%; min-width: 6rem; text-align: left; }
.vtable-checks-btn.is-on { border-color: var(--vt-accent); color: var(--vt-accent); font-weight: 600; }
