/* ═══════════════════════════════════════════════════════════════════════════════
 * ViCORE — ZENTRALES TABELLENSYSTEM (Optik)
 *
 * EINE Definition für ALLE Listen des Systems: ein Tabellenkopf, eine Zeilenhöhe,
 * eine Schriftgröße, ein Radius, ein Schatten, eine Trennlinie, ein Sortiericon,
 * eine Statusdarstellung, ein Aktionsknopf, ein Leer-/Lade-/Fehlerzustand.
 *
 * Waagerecht gescrollt wird AUSSCHLIESSLICH in `.vi-tbl-scroll` — nie die Seite.
 * Unter 720 px Containerbreite rendert dieselbe Spaltenkonfiguration Karten.
 *
 * Nur Tokens aus design-system.css; die Tabellenmaße stehen zentral in `.vi-tbl`.
 * Doku: docs/TABLE_STANDARD.md
 * ═══════════════════════════════════════════════════════════════════════════════ */

.vi-tbl {
  /* Zeilenhöhe — Dichte „Normal". Seit Phase 2 (03.09.2026) aus den zentralen
     Maß-Tokens: 44 px sind der ViCORE-Standard (vorher 46 px, hausgemachte Zahl).
     Vier zusätzliche Pixel je Zeile kosten auf 1366 × 768 rund eine ganze Datenzeile. */
  --vt-row-h: var(--row-h-normal, 44px);
  --vt-head-h: var(--bar-h-tools, 38px);
  --vt-pad-x: var(--space-4, 16px);
  --vt-fs: var(--text-md, 14px);
  --vt-r: var(--radius-lg, 12px);
  --vt-bd: var(--border-color, var(--gray-300, #D8DFDC));
  --vt-line: var(--table-row-line, var(--gray-200, #E5EAE8));
  /* Der Kopf ist eine ruhige helle Bande, keine dunkle Vollfläche.
     Eine Liste soll ihre DATEN zeigen; die Spaltennamen sind Beschriftung. */
  --vt-head-bg: var(--table-head-bg, var(--gray-50, #F4F6F5));
  --vt-head-fg: var(--table-head-color, var(--gray-500, #5F6B66));
  --vt-head-line: var(--table-head-line, var(--gray-300, #D8DFDC));
  --vt-ink: var(--text-primary, var(--gray-900, #141A17));
  --vt-muted: var(--text-muted, var(--gray-500, #5F6B66));
  --vt-accent: var(--brand-accent, var(--color-sage, #147352));
  --vt-hover: var(--table-row-hover, var(--gray-100, #EFF2F1));
  --vt-sel: var(--table-row-sel, var(--green-50, #EDF7F2));
  display: flex; flex-direction: column; gap: var(--space-2, 8px);
  font-family: var(--font-body);
  min-width: 0;
}
/* ── DREI Dichten, app-weit umschaltbar ────────────────────────────────────────
   Kompakt      — viele Datensätze im Blick (Auswertungen, Abgleich)
   Normal       — der ViCORE-Standard; muss OHNE Umschalten gut funktionieren
   Komfortabel  — Listen mit Unterzeilen (Objekt + Ort, Vorgang + Nummer)
   Die Dichte ist ein Angebot, kein Einrichtungsschritt: „Normal" ist die Vorgabe
   und niemand muss sie ändern, damit eine Liste lesbar ist. */
.vi-tbl--compact { --vt-row-h: var(--row-h-compact, 36px); --vt-head-h: var(--bar-h-listhead, 32px); --vt-fs: var(--text-sm, 13px); --vt-pad-x: var(--space-3, 12px); }
.vi-tbl--comfortable { --vt-row-h: var(--row-h-comfort, 56px); --vt-head-h: var(--control-h-lg, 40px); }

/* ── Werkzeugleiste: Anzahl links, Steuerung rechts ─────────────────────────── */
.vi-tbl-toolbar {
  display: flex; align-items: center; gap: var(--space-3, 12px); flex-wrap: wrap;
  padding: 0 2px;
}
.vi-tbl-count { font: var(--fw-medium, 500) 13px/1.4 var(--font-body); color: var(--vt-muted); }
.vi-tbl-tools { margin-left: auto; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.vi-tbl-tool {
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 var(--space-3, 12px);
  border: 1px solid var(--vt-bd); border-radius: var(--radius-md, 10px);
  background: var(--color-surface, #fff); color: var(--text-secondary, #3A4441);
  font: var(--fw-medium, 500) 12.5px/1 var(--font-body);
  transition: all var(--transition, 150ms ease);
}
.vi-tbl-tool:hover { border-color: var(--gray-400); color: var(--vt-ink); background: var(--gray-50); }
.vi-tbl-tool.is-primary { background: var(--green-600, #147352); border-color: var(--green-600, #147352); color: var(--color-surface); }
.vi-tbl-tool:focus-visible, .vi-tbl-sortbtn:focus-visible, .vi-tbl-act:focus-visible,
.vi-tbl-row:focus-visible, .vi-tbl-card:focus-visible, .vi-tbl-pg:focus-visible, .vi-tbl-menu-i:focus-visible {
  outline: 2px solid var(--vt-accent); outline-offset: 1px;
}
.vi-tbl-tool-n {
  min-width: 18px; height: 18px; padding: 0 4px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--green-600, #147352); color: var(--color-surface); font-size: var(--text-xxs); font-weight: var(--fw-bold, 700);
}

/* ── Rahmen + Scrollcontainer ───────────────────────────────────────────────── */
/* EIN Rahmen um die Tabellenfläche — und sonst keiner. Keine senkrechten Linien,
   keine Karte um die Karte, kein Schatten (eine Tabelle ist kein Knopf). Wer die
   Tabelle in eine Karte legt, bekommt strukturell den flachen Fall (siehe
   `.ds-card .ds-card` in design-system.css).

   `overflow: hidden` bleibt — es lässt den Radius auch am Kopf greifen. Das war
   früher zugleich die Ursache für abgeschnittene Hoveranzeigen; die liegen jetzt
   im zentralen Overlay-Layer an <body> und sind von diesem Container gar nicht
   mehr erreichbar (siehe vi-overlay.js). */
.vi-tbl-wrap {
  background: var(--color-surface, #fff);
  border: 1px solid var(--vt-bd);
  border-radius: var(--vt-r);
  overflow: hidden;
  min-width: 0;
}
.vi-tbl-scroll { overflow-x: auto; overflow-y: visible; -webkit-overflow-scrolling: touch; }
/* Waagerechtes Scrollen ist der FALLBACK, nicht der Normalfall. Tritt es ein,
   sagt eine weiche Kante rechts, dass dort noch etwas steht — sonst sieht eine
   abgeschnittene Spalte aus wie ein Fehler. */
.vi-tbl-scroll.is-scrolling {
  -webkit-mask-image: linear-gradient(to right, var(--gray-900, #141A17) calc(100% - 24px), transparent 100%);
  mask-image: linear-gradient(to right, var(--gray-900, #141A17) calc(100% - 24px), transparent 100%);
}
.vi-tbl-scroll.is-scrolling:hover, .vi-tbl-scroll.is-scrolling:focus-within {
  -webkit-mask-image: none; mask-image: none;
}
.vi-tbl-scroll::-webkit-scrollbar { height: 9px; }
.vi-tbl-scroll::-webkit-scrollbar-thumb { background: var(--gray-300, #D8DFDC); border-radius: var(--radius-pill); }
.vi-tbl-scroll::-webkit-scrollbar-track { background: transparent; }
/* MUSS die Tabelle waagerecht scrollen (zusätzliche optionale Spalten), bleibt
   die AKTIONSSPALTE rechts angeheftet — ein Knopf, den man erst durch Scrollen
   erreicht, ist keiner (Nutzerregel 28.08.2026). Zellhintergründe sind ohnehin
   deckend (Kopf `--vt-head-bg`, Zellen `--color-surface`, Hover/Auswahl setzen
   ihre Farbe an der Zelle), die weiche Linkskante zeigt die Überdeckung an.
   Die Ausblend-Maske am rechten Rand entfällt in diesem Fall — sie würde die
   angeheftete Spalte selbst verschleiern. */
.vi-tbl-scroll.is-scrolling:has(.vi-tbl-actcol) { -webkit-mask-image: none; mask-image: none; }
.vi-tbl-scroll.is-scrolling th.vi-tbl-actcol,
.vi-tbl-scroll.is-scrolling td.vi-tbl-actcol {
  position: sticky; right: 0; z-index: 2;
  box-shadow: -8px 0 8px -8px rgba(20, 26, 23, .28);
}

.vi-tbl-table {
  width: 100%; border-collapse: separate; border-spacing: 0;
  font-size: var(--vt-fs); color: var(--vt-ink);
  /* Feste Spaltenaufteilung (15.08.2026) — EIN vorhersagbares Tabellenverhalten.
     Mit `auto` bestimmt der Inhalt die Spaltenbreite: ein langer Betreff sprengt die
     Tabelle über den Container (gemessen 1383 px bei 1084 px Platz) und erzwingt
     Querscrollen, obwohl Platz da wäre; umgekehrt bleiben Spalten bei kurzem Inhalt
     schmaler als der Container. `fixed` nimmt die Breiten aus der colgroup, verteilt
     den Rest auf die Spalten ohne Vorgabe und trifft den Container exakt (1084/1084).
     Zu lange Texte werden über `.vi-tbl-td.is-ell` sauber mit Auslassungspunkten
     gekürzt. `colresize.js` arbeitet ohnehin bereits in diesem Modus. */
  table-layout: fixed;
}

/* ── Kopf ─────────────────────────────────────────────────────────────────────
   Der Kopf ist BESCHRIFTUNG, nicht Inhalt. Gesperrte Versalien („NÄCHSTE AKTION")
   waren lauter als die Daten darunter, brauchten mehr Platz als der Wert, den sie
   beschriften, und mussten deshalb als Erste gekürzt werden. Satzschreibung in
   ruhigem Grau ordnet, ohne zu rufen. (Ausnahme der alten CI-Regel „Versalien im
   Tabellenkopf" — bewusst aufgehoben, Redesign 16.08.2026.) */
.vi-tbl-head th {
  background: var(--vt-head-bg); color: var(--vt-head-fg);
  height: var(--vt-head-h); padding: 0 var(--vt-pad-x);
  text-align: left; vertical-align: middle; white-space: nowrap;
  font: var(--fw-semibold, 600) var(--text-xs, 12px)/1 var(--font-body);
  letter-spacing: 0; text-transform: none;
  border: 0; border-bottom: 1px solid var(--vt-head-line);
  /* Ist eine Spalte einmal zu schmal, wird die Überschrift sauber gekürzt statt
     mitten im Buchstaben abgeschnitten („Anhän"). */
  overflow: hidden; text-overflow: ellipsis;
}
/* Wird der Platz knapp, bricht die Überschrift auf ZWEI Zeilen um, statt die
   Spalte auf ihre volle einzeilige Breite zu zwingen (28.08.2026): „Letzte
   Durchführung" steht dann als „Letzte / Durchführung". Die Breitenrechnung
   (`headWordMin`) stellt sicher, dass das längste Wort immer ganz passt —
   Auslassungspunkte im Kopf bleiben der pathologische Ausnahmefall. */
.vi-tbl-head th > span,
.vi-tbl-head th .vi-tbl-sortbtn > span {
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden; white-space: normal; min-width: 0;
  line-height: 1.25; text-align: inherit;
}
.vi-tbl-head.is-sticky th { position: sticky; top: 0; z-index: 3; }
.vi-tbl-th.is-right { text-align: right; }
.vi-tbl-th.is-center { text-align: center; }
/* Die aktive Sortierung ist ein Zustand und darf ihn zeigen. */
.vi-tbl-th.is-sorted { color: var(--vt-ink); }
.vi-tbl-sortbtn {
  appearance: none; border: 0; background: none; cursor: pointer; padding: 0;
  display: inline-flex; align-items: center; gap: 5px;
  color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit;
}
.vi-tbl-sortbtn:hover { color: var(--vt-ink); }
/* RUHIGER KOPF: Nur die aktive Sortierung trägt dauerhaft ein Symbol. Zwölf
   graue Doppelpfeile nebeneinander zeigen keine Information an — sie zeigen nur,
   dass zwölf Spalten sortierbar SIND. Das erfährt man beim Überfahren. */
.vi-tbl-sort-i {
  flex: 0 0 auto; opacity: 0;
  transition: opacity var(--transition, 150ms ease);
}
.vi-tbl-th.is-sortable:hover .vi-tbl-sort-i,
.vi-tbl-sortbtn:focus-visible .vi-tbl-sort-i { opacity: .5; }
.vi-tbl-sort-i.is-on { opacity: 1; }
.vi-tbl-th.is-right .vi-tbl-sortbtn { flex-direction: row-reverse; }
@media (hover: none) { .vi-tbl-sort-i { opacity: .4; } }

/* ── Zeilen und Zellen ──────────────────────────────────────────────────────────
   Hover ist NEUTRAL (nur eine Spur dunkler), Auswahl trägt die Markenfarbe plus
   einen Balken an der linken Kante. Wäre der Hover grün, sähe jede Zeile unter dem
   Mauszeiger nach „ausgewählt" aus — Farbe muss hier Bedeutung tragen, nicht
   Bewegung anzeigen. */
.vi-tbl-row { transition: background var(--transition, 150ms ease); }
.vi-tbl-row.is-clickable { cursor: pointer; }
.vi-tbl-row:hover > .vi-tbl-td { background: var(--vt-hover); }
.vi-tbl-row.is-sel > .vi-tbl-td { background: var(--vt-sel); }
.vi-tbl-row.is-sel > .vi-tbl-td:first-child { box-shadow: inset 3px 0 0 var(--vt-accent); }
.vi-tbl-td {
  height: var(--vt-row-h); padding: var(--space-1, 4px) var(--vt-pad-x);
  border-top: 1px solid var(--vt-line);
  vertical-align: middle; background: var(--color-surface, #fff);
  white-space: nowrap;
}
/* ── Kürzen oder umbrechen? ───────────────────────────────────────────────────
   Reihenfolge der Mittel (Regel 18 des Redesigns): erst genug Spaltenbreite, dann
   die flexible Hauptspalte, dann Umbruch — Auslassungspunkte NUR als letzter
   Ausweg. Kompakte Werte (Nummer, Datum, Status) bleiben einzeilig, weil sie kurz
   sind; inhaltstragende Spalten brechen um, statt „Dokumentation Dachzusta…" zu
   zeigen. Der Umbruch ist auf zwei Zeilen begrenzt, damit eine einzelne lange
   Beschreibung die Liste nicht auseinanderzieht; der vollständige Wert steht dann
   im zentralen Tooltip (VIOverlay), NICHT im `title` des Browsers. */
.vi-tbl-td.is-ell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vi-tbl-td.is-wrap { white-space: normal; overflow: hidden; }
.vi-tbl-cw {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-clamp: 2; overflow: hidden;
  /* KEINE SILBENTRENNUNG IN TABELLEN (Nutzerregel 03.09.2026, Phase 2).
     `hyphens: auto` + `overflow-wrap: anywhere` zerlegten Fachbegriffe und
     Eigennamen mitten im Wort — „Brand-/schutztür", „Kumero-/wer Hof". Ein
     Objektname, den man buchstabieren muss, ist keine Ortsangabe mehr.
     `break-word` bricht NUR, wenn ein einzelnes Wort allein nicht passt (lange
     Kennungen ohne Leerzeichen); normale Wörter bleiben ganz. */
  hyphens: none; overflow-wrap: break-word;
  /* Zwei Zeilen müssen in die 44-px-Zeile passen — mit normaler Laufweite tun sie
     das nicht (2 × 21 px + 8 px Polsterung = 50 px). */
  line-height: var(--lh-tight, 1.3);
}
/* Zellen mit eigener Unterzeile (Objekt, Vorgang) brauchen die zweite Zeile für
   die Unterzeile — der Haupttext bleibt dort einzeilig und wird gekürzt.
   ENGERE ZEILENHÖHE: zwei Zeilen mit normaler Laufweite (2 × 21 px) sprengen die
   44-px-Zeile um sechs Pixel — und zwar in JEDER Zeile der Liste. Mit 1,3 bleiben
   Haupt- und Unterzeile zusammen unter der Zeilenhöhe, ohne enger zu wirken. */
.vi-tbl-cw:has(.vi-tbl-sub) { display: block; line-height: var(--lh-tight, 1.3); }
.vi-tbl-cw:has(.vi-tbl-sub) > * { line-height: var(--lh-tight, 1.3); }
/* DIESELBE ENGERE ZEILENHÖHE AUCH OHNE WRAPPER (03.09.2026): Zellen, die ihr
   Zweizeiler-Markup selbst mitbringen (`<div class="vi-tbl-primary">` +
   `<div class="vi-tbl-sub">` aus einem render()), haben KEIN `.vi-tbl-cw` um sich.
   Sie erbten damit die volle Zellen-Laufweite von 21 px je Zeile — zwei Zeilen
   ergaben 42 px + 8 px Polsterung = 50 px, und das trieb JEDE Zeile der Liste
   sechs Pixel über die Zeilenhöhe (gemessene Ursache der 50-px-Zeilen). */
.vi-tbl-td .vi-tbl-primary,
.vi-tbl-td .vi-tbl-sub { line-height: var(--lh-tight, 1.3); }
/* DIE ELLIPSE GEHÖRT AN DAS ELEMENT, DAS DEN TEXT TRÄGT (03.09.2026).
   `text-overflow` am `<td>` wirkt nicht auf den Inhalt eines Block-Kindes: ein
   `<div class="vi-tbl-primary">` in einer einzeiligen Zelle wurde deshalb HART
   abgeschnitten — „Feststellanlagen (Haltemagnete Brandschu" ohne „…". Der
   vollständige Wert steht ohnehin im zentralen Hover; sichtbar fehlte nur das
   Zeichen, das die Kürzung ankündigt. */
.vi-tbl-td.is-ell .vi-tbl-primary,
.vi-tbl-td.is-ell .vi-tbl-sub,
.vi-tbl-cw > .vi-tbl-sub {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vi-tbl-cw:has(.vi-tbl-sub) > .vi-tbl-obj-n,
.vi-tbl-cw .vi-tbl-obj:has(> .vi-tbl-sub) > .vi-tbl-obj-n,
.vi-tbl-cw:has(.vi-tbl-sub) .vi-tbl-sub {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* ZWEI ZEILEN JE ZELLE, NICHT DREI (Nutzerregel 03.09.2026, Phase 3).
   Hat eine Zelle eine Unterzeile, bleibt der Primärtext EINZEILIG und wird gekürzt
   — sonst ergeben zwei Zeilen Titel plus Unterzeile drei Zeilen, die Zeilenhöhe
   springt auf 71 px und es passen fünf statt neun Datensätze auf den Bildschirm
   (gemessen 03.09.2026). Der vollständige Titel steht im zentralen Hover.
   Ohne Unterzeile darf der Primärtext weiterhin auf zwei Zeilen umbrechen. */
.vi-tbl-cw:has(.vi-tbl-sub) > .vi-tbl-primary {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Auch die Zwei-Zeilen-Begrenzung der Komfort-Dichte gilt dann nicht: drei Zeilen
   sind auch dort eine Zeile zu viel. */
.vi-tbl--comfortable .vi-tbl-cw:has(.vi-tbl-sub) > .vi-tbl-primary { -webkit-line-clamp: 2; line-clamp: 2; white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; }
.vi-tbl--comfortable .vi-tbl-cw { -webkit-line-clamp: 3; line-clamp: 3; }
.vi-tbl-table tbody tr:first-child > .vi-tbl-td { border-top: 0; }
.vi-tbl-td.is-right { text-align: right; }
.vi-tbl-td.is-center { text-align: center; }
/* Spaltenhierarchie: der Primärwert trägt Gewicht, alles andere tritt zurück.
   Genau daran erkennt man in einer Zeile mit zwölf Spalten, worum es geht.
   Die HAUPTSPALTE (`primary: true`) ist der Orientierungspunkt der Zeile — sie
   bekommt bevorzugt den freien Platz UND das visuelle Gewicht. */
.vi-tbl-primary { font-weight: var(--fw-semibold, 600); color: var(--vt-ink); letter-spacing: -0.005em; }
.vi-tbl-td.is-primary { color: var(--vt-ink); }
.vi-tbl-th.is-primary { color: var(--text-secondary, #3A4441); }
/* Beim Überfahren der Zeile tritt der Hauptwert eine Spur hervor — das ist der
   Anker, auf den der Klick zielt. Kein Unterstreichen, keine Farbe: die Zeile
   ist bereits als klickbar markiert. */
.vi-tbl-row.is-clickable:hover .vi-tbl-td.is-primary .vi-tbl-primary { color: var(--color-forest, var(--green-700, #0F5C42)); }
.vi-tbl-meta { color: var(--vt-muted); }
.vi-tbl-sub { display: block; font-size: var(--text-sm, 13px); color: var(--vt-muted); margin-top: 1px; }
.vi-tbl-dash { color: var(--vt-muted); }
/* Technische Daten spaltengerecht: Ziffern immer gleich breit */
.vi-tbl-num { font-variant-numeric: lining-nums tabular-nums; font-feature-settings: "lnum", "tnum"; }
.vi-tbl-obj-n { font-weight: var(--fw-medium, 500); }

/* Status: EINE Darstellung — Punkt + getönte Fläche in der Statusfarbe */
.vi-tbl-status {
  --st-c: var(--vt-accent);
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 10px; border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--st-c) 14%, transparent);
  color: color-mix(in srgb, var(--st-c) 78%, var(--gray-900, #141A17));
  font: var(--fw-semibold, 600) 12px/1 var(--font-body); white-space: nowrap;
}
.vi-tbl-status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--st-c); flex: 0 0 auto; }
/* Änderbarer Status: dieselbe Pille, ein kleiner Pfeil — KEIN Formular-Auswahlfeld.
   Ein <select> in jeder Zeile lässt die Liste wie eine Maske mit 200 Feldern
   aussehen; der Pfeil sagt dasselbe und trägt keinen Rahmen. */
.vi-tbl-status.is-editable { cursor: pointer; padding-right: 6px; }
.vi-tbl-status.is-editable::after {
  content: ''; width: 10px; height: 10px; flex: 0 0 auto; opacity: .6;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center/10px no-repeat;
  mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") center/10px no-repeat;
}
.vi-tbl-row:hover .vi-tbl-status.is-editable::after { opacity: 1; }
.vi-tbl-badge {
  --bd-c: var(--gray-500, #5F6B66);
  display: inline-flex; align-items: center; height: 22px; padding: 0 8px; border-radius: var(--radius-sm, 6px);
  background: color-mix(in srgb, var(--bd-c) 13%, transparent);
  color: color-mix(in srgb, var(--bd-c) 80%, var(--gray-900, #141A17));
  font: var(--fw-semibold, 600) 11.5px/1 var(--font-body); white-space: nowrap;
}

/* ── Auswahl- und Aktionsspalte: Kopf UND Zelle nach denselben Regeln ────────
   Die Grundregel für Kopfzellen ist elementqualifiziert (`.vi-tbl-head th`,
   Spezifität 0,1,1) und schlug damit die Spaltenklasse `.vi-tbl-selcol` (0,1,0).
   Der Kopf behielt deshalb die normale Textpolsterung (2 × 16 px) und die
   Kürzungsregel `text-overflow: ellipsis`. In einer 44 px breiten Spalte passte
   das 16-px-Häkchen damit nicht mehr in den Inhaltsbereich, und der Browser
   zeichnete die Auslassungspunkte einer Zelle, die überhaupt keinen Text hat —
   das sichtbare „…" neben dem Kopf-Häkchen (gemeldet 24.08.2026).
   In der Datenzelle fiel es nicht auf, weil `.vi-tbl-td` dieselbe Spezifität hat,
   aber weiter oben in dieser Datei steht: dort gewinnt die Spaltenklasse über die
   Reihenfolge. Genau diese Asymmetrie war der Fehler.
   Die Regeln sind deshalb ausdrücklich für BEIDE Zellarten qualifiziert — nicht
   per `!important` und nicht durch Absenken der Grundregel, die alle übrigen
   Kopfzellen trägt. Dasselbe gilt für die Aktionsspalte, deren Kopf sonst links
   ausgerichtet über rechtsbündigen Knöpfen steht. */
.vi-tbl-head th.vi-tbl-selcol,
.vi-tbl-td.vi-tbl-selcol {
  width: 44px; text-align: center; padding: 0 0 0 12px;
  overflow: visible; text-overflow: clip;
}
.vi-tbl-head th.vi-tbl-actcol { text-align: right; }
/* Eine Aktionszelle enthält Bedienelemente, keinen Text. `overflow: hidden` sägt
   dort den Knopf ab, statt eine Zeichenkette zu kürzen — so entstand der halbe
   Knopf „Öffn…" am rechten Rand. Die Breite kommt jetzt aus der Beschriftung
   (`actionsIdeal` in vi-table.js), verborgen wird nichts mehr. */
.vi-tbl-td.vi-tbl-actcol { overflow: visible; text-overflow: clip; }
.vi-tbl-cb { width: 16px; height: 16px; accent-color: var(--vt-accent); cursor: pointer; }

/* ── Zeilenaktionen ───────────────────────────────────────────────────────────
   Die Aktionsspalte beansprucht so wenig Raum wie möglich: EIN „⋯". In Ruhe ist
   er zurückgenommen, beim Überfahren der Zeile tritt er hervor. Hundert Zeilen
   mit je drei beschrifteten Knöpfen sind dreihundert Bedienelemente, die um die
   Daten konkurrieren — die Funktion bleibt, nur ihre Ankündigung wird leiser. */
.vi-tbl-actcol { text-align: right; white-space: nowrap; }
.vi-tbl-actions { display: inline-flex; align-items: center; gap: 5px; justify-content: flex-end; }
.vi-tbl-rowmenu { color: var(--vt-muted); opacity: .55; transition: opacity 120ms ease, background-color 120ms ease; }
.vi-tbl-row:hover .vi-tbl-rowmenu,
.vi-tbl-row:focus-within .vi-tbl-rowmenu { opacity: 1; color: var(--vt-ink); }
.vi-tbl-rowmenu:focus-visible { opacity: 1; }
/* Auf Touch-Geräten gibt es kein „Überfahren" — dort steht der Knopf immer. */
@media (hover: none) { .vi-tbl-rowmenu { opacity: 1; } }
.vi-tbl-act {
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 5px;
  height: 30px; padding: 0 var(--space-3, 12px);
  border: 1px solid var(--vt-bd); border-radius: var(--radius-md, 10px);
  background: var(--color-surface, #fff); color: var(--text-secondary, #3A4441);
  font: var(--fw-medium, 500) 12.5px/1 var(--font-body); white-space: nowrap;
  transition: all var(--transition, 150ms ease);
}
.vi-tbl-act:hover { border-color: var(--gray-400); color: var(--vt-ink); background: var(--gray-50); }
.vi-tbl-act.is-primary { background: var(--green-600, #147352); border-color: var(--green-600, #147352); color: var(--color-surface); }
.vi-tbl-act.is-primary:hover { background: var(--green-700, #0F5C42); border-color: var(--green-700, #0F5C42); }
.vi-tbl-act.is-danger { color: var(--color-danger-ink, #A32C22); border-color: var(--color-danger-soft, #FBE8E5); }
.vi-tbl-act.is-danger:hover { background: var(--color-danger-soft, #FBE8E5); border-color: var(--color-danger, #C0392C); }
.vi-tbl-act.is-ghost { border-color: transparent; background: transparent; }

/* Sammelaktionen */
.vi-tbl-bulk {
  display: flex; align-items: center; gap: var(--space-3, 12px); flex-wrap: wrap;
  padding: var(--space-2, 8px) var(--space-3, 12px);
  background: var(--green-50, #EDF7F2);
  border: 1px solid var(--green-200, #AFDCC6);
  border-radius: var(--radius-md, 8px);
}
.vi-tbl-bulk-n { font: var(--fw-semibold, 600) 13px/1 var(--font-body); color: var(--green-700, #0F5C42); }
.vi-tbl-bulk-acts { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }

/* ── Zustände: leer · lädt · Fehler ─────────────────────────────────────────── */
.vi-tbl-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-2, 8px); padding: var(--space-7, 48px) var(--space-4, 16px);
  text-align: center; color: var(--vt-muted);
}
.vi-tbl-state-i { color: var(--gray-300, #D8DFDC); }
.vi-tbl-state-t { margin: 0; font: var(--fw-semibold, 600) 14.5px/1.4 var(--font-body); color: var(--text-secondary, #3A4441); }
.vi-tbl-state-x { margin: 0; font-size: var(--text-sm); max-width: 460px; }
.vi-tbl-state-acts { display: flex; gap: var(--space-2, 8px); flex-wrap: wrap; justify-content: center; margin-top: var(--space-2, 8px); }
.vi-tbl-error .vi-tbl-state-i { color: var(--color-danger, #C0392C); }
.vi-tbl-error .vi-tbl-state-t { color: var(--color-danger-ink, #A32C22); }
.vi-tbl-loading { padding: var(--space-3, 12px); gap: 0; }
.vi-tbl-sk-row { display: flex; gap: var(--space-4, 16px); width: 100%; padding: var(--space-3, 12px) var(--vt-pad-x); }
.vi-tbl-sk {
  height: 12px; border-radius: var(--radius-sm); background: var(--gray-100, #EFF2F1);
  animation: vi-tbl-pulse 1.3s ease-in-out infinite;
}
@keyframes vi-tbl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
.vi-tbl-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ── Blättern ───────────────────────────────────────────────────────────────── */
.vi-tbl-pager { display: flex; align-items: center; gap: var(--space-3, 12px); flex-wrap: wrap; padding: 0 2px; }
.vi-tbl-pg-i { font-size: var(--text-xs); color: var(--vt-muted); font-variant-numeric: tabular-nums; }
.vi-tbl-pg-b { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.vi-tbl-pg {
  appearance: none; cursor: pointer; height: 32px; padding: 0 var(--space-3, 12px);
  border: 1px solid var(--vt-bd); border-radius: var(--radius-md, 10px);
  background: var(--color-surface, #fff); color: var(--text-secondary, #3A4441);
  font: var(--fw-medium, 500) 12.5px/1 var(--font-body);
}
.vi-tbl-pg:hover:not([disabled]) { border-color: var(--vt-accent); color: var(--vt-ink); }
.vi-tbl-pg[disabled] { opacity: .45; cursor: default; }
.vi-tbl-pg-n { font-size: var(--text-xs); color: var(--vt-muted); font-variant-numeric: tabular-nums; }

/* ── Menü (Spaltensteuerung) ────────────────────────────────────────────────── */
.vi-tbl-menu {
  position: fixed; z-index: var(--vdlg-z-pop, 7000); min-width: 230px; max-height: 60vh; overflow-y: auto;
  background: var(--color-surface, #fff); border: 1px solid var(--gray-300, #D8DFDC);
  border-radius: var(--radius-lg, 12px); box-shadow: var(--shadow-pop, var(--shadow-md)); padding: 5px;
}
.vi-tbl-menu-i {
  /* justify-content MUSS hier stehen: design-system.css setzt global
     "button { justify-content: center }" — ohne diese Angabe stünden die
     Einträge zentriert, das text-align greift im Flex-Container nicht. */
  appearance: none; cursor: pointer; display: flex; align-items: center; justify-content: flex-start;
  gap: 9px; width: 100%;
  min-height: 32px; padding: 0 var(--space-2, 8px); border: 0; border-radius: var(--radius-sm, 6px);
  background: none; color: var(--text-primary, #141A17);
  font: var(--fw-medium, 500) 13px/1.3 var(--font-body); text-align: left;
}
.vi-tbl-menu-i:hover { background: var(--gray-100, #EFF2F1); }
/* Symbolspalte exakt so breit wie das Auswahlkästchen darüber → eine Textkante. */
.vi-tbl-menu-ic {
  flex: 0 0 15px; width: 15px; height: 15px;
  display: inline-flex; align-items: center; justify-content: center; color: var(--vt-muted, #6B655C);
}
.vi-tbl-menu-ic svg { display: block; }
.vi-tbl-menu-i:hover .vi-tbl-menu-ic { color: var(--text-primary, #141A17); }
.vi-tbl-menu-mark {
  width: 15px; height: 15px; flex: 0 0 auto; border-radius: 4px;
  border: 1.5px solid var(--gray-300, #D8DFDC); background: var(--color-surface);
}
.vi-tbl-menu-i.is-on .vi-tbl-menu-mark {
  background: var(--color-sage, #147352); border-color: var(--color-sage, #147352);
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  background-size: 11px; background-position: center; background-repeat: no-repeat;
}
.vi-tbl-menu-l { flex: 1 1 auto; min-width: 0; }
/* Automatisch zurückgestellt (kein Platz) — das ist etwas anderes als „vom Nutzer
   ausgeblendet" und muss im Menü unterscheidbar sein, sonst wirken die Spalten
   einfach verschwunden. */
.vi-tbl-menu-note {
  flex: 0 0 auto; font-size: var(--text-xxs, 11px); font-weight: var(--fw-medium, 500);
  color: var(--vt-muted); padding: 1px 6px; border-radius: var(--radius-sm, 6px);
  background: var(--gray-100, #EFF2F1);
}
.vi-tbl-menu-i.is-parked .vi-tbl-menu-mark { border-style: dashed; }
.vi-tbl-menu-sep { height: 1px; background: var(--gray-300, #D8DFDC); margin: 5px 0; }
/* ── Der Ton eines Eintrags ────────────────────────────────────────────────
   EINE Aktion steht als Knopf in der Zeile, ZWEI falten sich ins „…"-Menü.
   Dieselbe Aktion, zwei Darstellungen — also muss auch ihr Ton in beiden
   ankommen. Bis zum 15.09.2026 war `is-danger` nur am Knopf gestaltet; im
   Menü stand „Endgültig löschen" im selben Grau wie „Öffnen". */
.vi-tbl-menu-i.is-danger { color: var(--color-danger-ink, #A32C22); }
.vi-tbl-menu-i.is-danger:hover { background: var(--color-danger-soft, #FBE8E5); }
.vi-tbl-menu-i.is-danger .vi-tbl-menu-ic,
.vi-tbl-menu-i.is-danger:hover .vi-tbl-menu-ic { color: inherit; }
.vi-tbl-menu-i.is-primary { color: var(--green-700, #0F5C42); font-weight: var(--fw-semibold, 600); }
.vi-tbl-menu-i.is-primary:hover { background: var(--green-50, #EDF7F2); }
.vi-tbl-menu-i.is-primary .vi-tbl-menu-ic,
.vi-tbl-menu-i.is-primary:hover .vi-tbl-menu-ic { color: inherit; }

/* ── Mobile Kartenansicht (dieselben Spalten, andere Form) ──────────────────── */
.vi-tbl-cards { display: flex; flex-direction: column; }
.vi-tbl-card {
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-top: 1px solid var(--vt-line); background: var(--color-surface, #fff);
  display: flex; flex-direction: column; gap: 6px;
}
.vi-tbl-cards > .vi-tbl-card:first-child { border-top: 0; }
.vi-tbl-card[tabindex] { cursor: pointer; }
.vi-tbl-card.is-sel { background: var(--vt-sel); box-shadow: inset 3px 0 0 var(--vt-accent); }
.vi-tbl-card-t { margin: 0; font: var(--fw-semibold, 600) 14.5px/1.3 var(--font-body); color: var(--vt-ink); }
.vi-tbl-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: var(--text-sm); }
.vi-tbl-card-rows { margin: 4px 0 0; display: flex; flex-direction: column; gap: 3px; }
.vi-tbl-card-row { display: flex; gap: 10px; font-size: var(--text-xs); }
.vi-tbl-card-row dt { flex: 0 0 42%; color: var(--vt-muted); }
.vi-tbl-card-row dd { margin: 0; flex: 1 1 auto; min-width: 0; color: var(--vt-ink); }
.vi-tbl-card-acts { margin-top: 6px; }
.vi-tbl-card-acts .vi-tbl-actions { justify-content: flex-start; flex-wrap: wrap; }

@media (prefers-reduced-motion: reduce) {
  .vi-tbl *, .vi-tbl-sk { transition: none !important; animation: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════════
   RUHIGE INLINE-EDITOREN IN LISTENZEILEN (Pilot B, 16.08.2026)
   ───────────────────────────────────────────────────────────────────────────────
   Manche Listen erlauben es, Werte direkt in der Zeile zu ändern (Status,
   Zuständigkeit). Das ist eine gute Funktion — aber wenn 100 Zeilen gleichzeitig
   je zwei Auswahlfelder mit Rahmen und Pfeil zeigen, sieht die Liste aus wie ein
   Formular mit 200 Feldern, und die eigentlichen Daten verschwinden dahinter.

   REGEL: In Ruhe zeigt die Zelle nur den WERT. Das Bedienelement (Rahmen, Pfeil,
   Fläche) erscheint erst bei Zeiger oder Tastaturfokus auf der Zeile. Die Funktion
   bleibt unverändert — nur ihre Ankündigung wird leiser.
   ═══════════════════════════════════════════════════════════════════════════════ */
.vi-tbl-td .cases-inline-select,
.vi-tbl-td select.cases-inline-select {
  border-color: transparent;
  background-color: transparent;
  background-image: none;
  color: var(--vt-ink);
  padding-left: 4px;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.vi-tbl-row:hover .vi-tbl-td .cases-inline-select,
.vi-tbl-td .cases-inline-select:focus,
.vi-tbl-td .cases-inline-select:focus-visible {
  border-color: var(--gray-300);
  background-color: var(--color-surface);
}

/* Status-Chip: der Wert trägt die Farbe, nicht ein Knopf. Der Aufklapp-Pfeil
   erscheint erst, wenn die Zeile angesteuert wird. */
.vi-tbl-td .csd-btn { border-color: transparent; box-shadow: none; }
.vi-tbl-row:hover .vi-tbl-td .csd-btn,
.vi-tbl-td .csd-btn:focus-visible { border-color: currentColor; }

/* Zeilenwerkzeuge (z. B. „Titel bearbeiten") erst bei Bedarf. */
.vi-tbl-td .cases-title-edit { opacity: 0; transition: opacity 120ms ease; }
.vi-tbl-row:hover .vi-tbl-td .cases-title-edit,
.vi-tbl-td .cases-title-edit:focus-visible { opacity: 1; }
@media (hover: none) { .vi-tbl-td .cases-title-edit { opacity: 1; } }

/* ═══════════════════════════════════════════════════════════════════════════════
   PHASE 2 (03.09.2026) — Gruppierung · Master/Detail · Fußzeile · Cursor · Zweizeiler
   Alles Fähigkeiten DIESER Tabelle. Es gibt bewusst keine zweite Tabellen-
   komponente daneben: eine `GroupedDataTable` hätte Breitenrechnung, Dichte,
   Spaltenmenü, Export und mobile Karten ein zweites Mal gebraucht.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ── Zweizeilige Standardzelle (`sub` an beliebiger Spalte) ────────────────── */
.vi-tbl-2l { display: block; min-width: 0; }
.vi-tbl-2l > .vi-tbl-primary,
.vi-tbl-2l > .vi-tbl-sub { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Gruppenkopf ───────────────────────────────────────────────────────────────
   Er ist eine ZEILE, keine Karte: gleiche Spaltenbreiten, gleiche Trennlinien.
   Sticky unter dem Tabellenkopf, damit beim Scrollen immer sichtbar bleibt,
   in welcher Gruppe man sich befindet. */
.vi-tbl-grp-c {
  padding: 0; margin: 0; text-align: left; font-weight: inherit;
  background: var(--gray-50, #F4F6F5);
  border-top: 1px solid var(--vt-head-line);
  border-bottom: 1px solid var(--vt-line);
  position: sticky; top: var(--vt-head-h); z-index: 1;
}
.vi-tbl-grp:first-child .vi-tbl-grp-c { border-top: 0; }
.vi-tbl-grp-b {
  display: flex; align-items: center; gap: var(--space-2, 8px);
  width: 100%; border: 0; background: none; cursor: pointer;
  padding: var(--space-2, 8px) var(--vt-pad-x);
  font: inherit; font-size: var(--text-sm, 13px); color: var(--vt-ink); text-align: left;
}
.vi-tbl-grp-b:hover { background: var(--vt-hover); }
.vi-tbl-grp-car { color: var(--vt-muted); flex: 0 0 auto; }
.vi-tbl-grp-l { font-weight: var(--fw-semibold, 600); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vi-tbl-grp-n {
  flex: 0 0 auto; color: var(--vt-muted); font-variant-numeric: tabular-nums;
  background: var(--gray-100); border-radius: var(--radius-sm, 6px);
  padding: 0 var(--space-2, 8px);
}
.vi-tbl-grp-m { margin-left: auto; color: var(--vt-muted); font-size: var(--text-xs, 12px); }

/* ── Master/Detail ─────────────────────────────────────────────────────────────
   Links die Liste, rechts GENAU EIN Datensatz. Beide teilen eine Fläche und einen
   Rahmen — Karte in Karte ist ausgeschlossen. */
.vi-tbl-md {
  display: grid; grid-template-columns: var(--vt-md-cols, minmax(0, 1fr) minmax(0, 1.6fr));
  gap: 0; min-width: 0;
  border: 1px solid var(--vt-bd); border-radius: var(--vt-r); overflow: hidden;
  background: var(--color-surface);
}
.vi-tbl-md-list { min-width: 0; display: flex; flex-direction: column; }
/* ── Verschiebbare Trennlinie ──────────────────────────────────────────────────
   Die Teilung gehört dem NUTZER: er zieht die Linie, die Wahl bleibt je Tabelle
   gespeichert (vi-table.js `mdSplit`). Die Linie IST der Trenner — deshalb trägt
   die Listenspalte keinen eigenen Rahmen mehr, sonst stünden zwei Striche
   nebeneinander. Griff-Fläche 9 px (Fitts), sichtbar bleibt 1 px; erst beim
   Überfahren, beim Fokus und beim Ziehen wird sie zur Marken-Kante. */
.vi-tbl-md-split {
  position: relative; align-self: stretch; min-width: 0;
  cursor: col-resize; touch-action: none;
  background: none; border: 0; padding: 0;
}
.vi-tbl-md-split::before {
  content: ''; position: absolute; inset: 0 4px;
  background: var(--vt-line); transition: background var(--transition, 150ms ease), inset var(--transition, 150ms ease);
}
.vi-tbl-md-split:hover::before,
.vi-tbl-md-split.is-drag::before { inset: 0 3px; background: var(--brand-primary, #147352); }
.vi-tbl-md-split:focus-visible { outline: none; }
.vi-tbl-md-split:focus-visible::before { inset: 0 3px; background: var(--brand-primary, #147352); box-shadow: var(--focus-ring); }
@media (prefers-reduced-motion: reduce) { .vi-tbl-md-split::before { transition: none; } }
.vi-tbl-md-list .vi-tbl-scroll { border: 0; border-radius: 0; }
/* DIE LISTE IM MASTER/DETAIL IST KEINE EIGENE KARTE. Rahmen und Rundung gehören dem
   gemeinsamen Container `.vi-tbl-md` — ohne diese Regel steht eine 12-px-gerundete
   Tabellenkarte MITTEN in der Fläche, die Naht zum Detail bekommt eine zweite Kante,
   und unter der letzten Zeile klafft ein Loch, weil die Karte kürzer ist als die Spalte. */
.vi-tbl-md-list > .vi-tbl-wrap { border: 0; border-radius: 0; flex: 1 1 auto; min-height: 0; }
.vi-tbl-md-det { min-width: 0; padding: var(--space-4, 16px); overflow-y: auto; }
.vi-tbl-md-none { color: var(--vt-muted); font-size: var(--text-sm, 13px); padding: var(--space-3, 12px) 0; }
/* Die im Detail geöffnete Zeile ist deutlich, aber ruhig markiert — 3-px-Balken
   links wie bei der Mehrfachauswahl, damit es EINE Auswahlsprache bleibt. */
.vi-tbl-row.is-open > .vi-tbl-td { background: var(--vt-sel); }
.vi-tbl-row.is-open > .vi-tbl-td:first-child { box-shadow: inset 3px 0 0 var(--vt-accent); }

/* Unter 1100 px stapeln Liste und Detail — das Detail rutscht UNTER die Liste,
   die Auswahl bleibt dieselbe. Kein zweiter Bildschirm, kein Dialog. */
@media (max-width: 1100px) {
  .vi-tbl-md { grid-template-columns: minmax(0, 1fr); }
  .vi-tbl-md-list { border-right: 0; border-bottom: 1px solid var(--vt-line); }
  /* Gestapelt gibt es nichts zu verschieben — die Trennlinie ist dann die Kante
     zwischen den beiden Blöcken und gehört der Listenspalte. */
  .vi-tbl-md-split { display: none; }
}

/* ── Fußzeile (Summen) ─────────────────────────────────────────────────────── */
.vi-tbl-foot > tr > .vi-tbl-td {
  background: var(--gray-50, #F4F6F5);
  border-top: 1px solid var(--vt-head-line);
  font-weight: var(--fw-semibold, 600); color: var(--vt-ink);
  position: sticky; bottom: 0;
}

/* ── „Weitere laden" (Cursor-Blättern) ─────────────────────────────────────── */
.vi-tbl-more { display: flex; justify-content: center; padding: var(--space-2, 8px) 0; }

/* ── UX-Phase 4: der Zeilenstandard gilt auch für Zellen mit EIGENEM Markup ──────
   Zwei Fälle aus der Listenmigration, beide gemessen am 03.09.2026:
   · Die Objektzelle der Vorgangsliste (`.cases-obj-*`) bringt bis zu DREI Blöcke
     mit (Wirtschaftseinheit, Objekt, Detailort) — die Zeile wuchs auf 57 px.
   · Das Medium-Symbol der Energie (`.vp-tile`) ist als Kachel 38 px hoch und
     sprengte damit die 44-px-Zeile.
   Beides bleibt inhaltlich erhalten: die Zelle wird auf zwei Zeilen geklemmt (der
   vollständige Pfad steht im zentralen Hover), das Symbol wird zeilengerecht. */
.vi-tbl-td .cases-obj-name,
.vi-tbl-td .cases-obj-sub {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  line-height: var(--lh-tight, 1.3);
}
.vi-tbl-td .cases-obj-name ~ .cases-obj-sub ~ * { display: none; }
.vi-tbl-td .vp-tile {
  width: var(--space-4, 16px); height: var(--space-4, 16px);
  min-width: var(--space-4, 16px); min-height: var(--space-4, 16px);
  font-size: var(--text-xxs, 11px); line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
