/* ==========================================================================
   vFlow theme overrides on top of UI5 sap_horizon.
   Tokens are the source of truth (./tokens.css) - only selector-level
   mapping onto UI5-rendered DOM classes happens here. See CLAUDE.md
   (project root) for the full design-system guide this implements.
   ========================================================================== */

html,
body.sapUiBody {
  font-family: var(--vf-font-sans);
  background: var(--vf-bg);
  color: var(--vf-text);
}

/* ---- Horizon theme parameters: brand color throughout the app ----------
   Per CLAUDE.md: map tokens onto Horizon CSS custom properties rather than
   fighting individual control CSS classes (some, e.g. Button's "Inverted"
   fill, live in the UI5 CDN stylesheet and aren't overridable by class
   alone since the color itself is read from these variables). !important
   is needed here: UI5's own theme :root rule is injected at runtime after
   this stylesheet, so equal-specificity source order would otherwise win. */
:root {
  --sapBrandColor: var(--vf-primary) !important;
  --sapHighlightColor: var(--vf-primary-hover) !important;
  --sapSelectedColor: var(--vf-primary-hover) !important;
  --sapActiveColor: var(--vf-brand-100) !important;
  --sapLinkColor: var(--vf-link) !important;
  --sapContent_FocusColor: var(--vf-primary) !important;
  --sapButton_Emphasized_Background: var(--vf-primary) !important;
  --sapButton_Emphasized_BorderColor: var(--vf-primary) !important;
  --sapButton_Emphasized_TextColor: var(--vf-neutral-0) !important;
  --sapButton_Emphasized_Hover_Background: var(--vf-primary-hover) !important;
  --sapButton_Emphasized_Hover_BorderColor: var(--vf-primary-hover) !important;
  --sapButton_Emphasized_Active_Background: var(--vf-primary-active) !important;
  --sapButton_Emphasized_Active_BorderColor: var(--vf-primary-active) !important;
  /* Platzhalter: Horizons Vorgabe #556b82 ist zu kraeftig und laesst ein
     leeres Formular vorbelegt aussehen (Testerbefund 21.09.2026). Eine
     Variable genuegt fuer Input, TextArea und SearchField - in der
     laufenden Seite nachgemessen. Die Kursive kommt vom Theme und bleibt. */
  --sapField_PlaceholderTextColor: var(--vf-text-placeholder) !important;
}

/* ---- Typography baseline ------------------------------------------------ */
.sapMText,
.sapMLabel,
.sapMTitle,
.sapMInputBaseInner,
.sapMBtnContent {
  font-family: var(--vf-font-sans);
}

/* Technical values (flow keys, correlation IDs, timestamps) - applied via
   class="vfMono" on the relevant sap.m.Text controls. */
.vfMono {
  font-family: var(--vf-font-mono) !important;
  font-size: var(--vf-fs-sm);
  color: var(--vf-text-secondary);
}

/* A mono technical value that is also a link (the e-mail address in the
   contacts table): keep the mono face and size, but not the muted colour -
   grey link text does not read as clickable. */
a.sapMLnk.vfMono {
  color: var(--vf-primary);
}

/* Editable technical fields (CSV column lists, element names) - mono font but
   normal input color/size, unlike the read-only .vfMono above. Applied via
   class="vfMonoField" on sap.m.Input / sap.m.TextArea (targets the inner
   editable element). */
.vfMonoField .sapMInputBaseInner,
.vfMonoField textarea {
  font-family: var(--vf-font-mono) !important;
}

/* ---- Page header / top bar --------------------------------------------- */
.sapMPageHeader {
  background: var(--vf-surface);
  border-bottom: 1px solid var(--vf-border);
  box-shadow: none;
}

.sapMPageHeader .sapMTitle {
  font-weight: var(--vf-fw-semibold);
  color: var(--vf-text);
}

/* ---- Buttons ------------------------------------------------------------ */
/* Emphasized (primary) button color comes from the --sapButton_Emphasized_*
   theme parameters above, not from a class override - Horizon renders the
   Button's colored fill on the outer element via those variables. */
.sapMBtn {
  border-radius: var(--vf-radius-sm);
}

/* ---- Inputs -------------------------------------------------------------- */
.sapMInputBase {
  border-radius: var(--vf-radius-sm);
}

.sapMInputBaseContentWrapper {
  border-color: var(--vf-border-strong);
}

.sapMInputBase.sapMInputBaseIconContainer:focus-within,
.sapMInputBase:focus-within {
  box-shadow: var(--vf-shadow-focus);
}

/* ---- IconTabBar: active brand color instead of stock Fiori blue --------- */
.sapMITBFilter .sapMITBText {
  color: var(--vf-text-secondary);
}

.sapMITBFilter.sapMITBSelected .sapMITBText {
  color: var(--vf-primary);
}

.sapMITBFilter .sapMITBFilterIcon {
  background: transparent;
  border-color: var(--vf-border-strong);
  color: var(--vf-text-secondary);
}

.sapMITBFilter.sapMITBSelected .sapMITBFilterIcon {
  background: var(--vf-primary);
  border-color: var(--vf-primary);
  color: var(--vf-neutral-0);
}

.sapMITBFilter.sapMITBSelected .sapMITBContentArrow {
  border-top-color: var(--vf-primary);
}

/* Selection underline bar is a ::after pseudo-element, not a real child. */
.sapMITBFilter.sapMITBSelected::after {
  border-bottom-color: var(--vf-primary) !important;
}

/* Reiterleiste und Karte auf denselben linken Rand (.vfTabsAligned).

   sapUiResponsiveContentPadding gibt der Kopfleiste (.sapMITH) 3rem, dem
   Inhaltsbereich (.sapMITBContent) aber nur 2rem. Wo eine Karte direkt im
   Reiter liegt, beginnt sie dadurch 16 px weiter links als der Reiter
   darueber - auf der Transport-Seite ist das Stefan am 27.08.2026
   aufgefallen.

   Bewusst eine eigene Klasse und keine Regel auf sapUiResponsiveContentPadding:
   Package-Detail schiebt seine Karten ueber eine zusaetzliche Zeile noch einmal
   16 px nach innen und steht damit heute schon buendig - eine globale Regel
   haette genau dort einen neuen Versatz erzeugt. Nachgemessen, nicht geschaetzt.

   UI5 reicht eigene Klassen an die Kopfleiste durch, deshalb greift der
   Nachfahren-Selektor. !important, weil die UI5-Regel dieselbe Klasse
   auswertet und sonst gewinnt - gleiche Falle wie bei .vfCard/.vfEditorHeader. */
.sapMITB.vfTabsAligned > .sapMITH {
  padding-left: 2rem !important;
  padding-right: 2rem !important;
}

/* ---- Einstellungen: die Beschriftungsspalte darf wachsen ---------------- */
/*
   Eine Einstellungszeile ist eine HBox mit justifyContent="SpaceBetween":
   links Beschriftung und Hilfetext, rechts das Feld. Die linke VBox stand auf
   `flex: 0 1 auto` und schrumpfte damit auf die Wunschbreite ihres Inhalts -
   bei umbrechendem Text sind das rund 190 px. Der Hilfetext brach auf vier
   Zeilen um, waehrend in der Mitte der Zeile 500 px leer blieben (Befund S1,
   27.08.2026).

   min-width: 0, weil eine Flex-Box sonst nicht unter die Breite ihres
   laengsten Wortes schrumpfen darf - ohne das kann die Zeile am rechten Feld
   vorbeiwachsen.
*/
.vfSettingsCard .sapMHBox.sapMFlexBoxJustifySpaceBetween > .sapMVBox:first-child {
  flex: 1 1 auto;
  min-width: 0;
}

/*
   Die rechte Spalte ist in JEDER Zeile gleich breit (Stefan, 28.09.2026:
   "das Design der Seiten ist teils unterschiedlich"). Vorher bestimmte jede
   Zeile ihre Breite selbst (5,9 bis 20,5 rem, manche gar keine): Schalter
   standen bei drei verschiedenen x-Positionen, und bei langem Hilfetext
   wurde die Spalte so schmal, dass "Tage" senkrecht umbrach. Jetzt beginnen
   alle Felder an derselben Kante; die Beschriftung nimmt den Rest.
*/
.vfSettingsCard .sapMHBox.sapMFlexBoxJustifySpaceBetween > :last-child:not(:first-child) {
  flex: 0 0 20.5rem;
  margin-left: var(--vf-space-5);
}

/* ---- Waagerecht scrollende Tabelle: den Balken sichtbar lassen ---------- */
/*
   Eine breite Tabelle steckt in vFlow in einer ScrollContainer, weil sap.m.Page
   sie sonst BESCHNEIDET (siehe Kommentar in Monitoring.view.xml). Scrollen ging
   also - nur sah man es nicht: macOS blendet den Balken aus, solange niemand
   scrollt, und eine halb sichtbare Spalte sieht abgeschnitten aus, nicht
   verschiebbar (Befund M10, 27.08.2026).

   Schmal und in Randfarbe, damit der Balken nicht mit den Daten konkurriert.
   NUR ::-webkit-scrollbar, ausdruecklich OHNE das standardisierte
   scrollbar-width: sobald das gesetzt ist, ignoriert Chrome die
   ::-webkit-Regeln - und der Balken bleibt ein Overlay, das erst beim
   Scrollen erscheint. Genau das war im Browser zu sehen (offsetHeight ==
   clientHeight, also null Platz fuer den Balken). Firefox bringt von Haus
   aus einen sichtbaren schmalen Balken mit und braucht die Regel nicht.

   Zwei Selektoren je Regel, weil UI5 die Klasse AN das scrollende Element
   selbst haengt (.sapMScrollCont.vfQuerScroll) und nicht an eine Huelle
   darum. Nur mit dem Nachfahren-Selektor griff gar nichts - nachgesehen im
   Browser, nicht angenommen.
*/
.vfQuerScroll.sapMScrollCont::-webkit-scrollbar,
.vfQuerScroll .sapMScrollCont::-webkit-scrollbar {
  height: 8px;
}

.vfQuerScroll.sapMScrollCont::-webkit-scrollbar-track,
.vfQuerScroll .sapMScrollCont::-webkit-scrollbar-track {
  background: transparent;
}

.vfQuerScroll.sapMScrollCont::-webkit-scrollbar-thumb,
.vfQuerScroll .sapMScrollCont::-webkit-scrollbar-thumb {
  background: var(--vf-border-strong);
  border-radius: var(--vf-radius-xs);
}

/* ---- Tables: dense rows, zebra, sticky header, right-aligned numerics --- */
.sapMTableTHead {
  background: var(--vf-surface-sunk);
  border-bottom: 1px solid var(--vf-border);
}

.sapMListTblHeaderCell {
  font-weight: var(--vf-fw-medium);
  color: var(--vf-text-secondary);
  font-size: var(--vf-fs-sm);
}

.sapMListTbl .sapMLIB:nth-child(even) {
  background: var(--vf-surface-sunk);
}

.sapMListTbl .sapMLIB:hover {
  background: var(--vf-brand-50);
}

/* ---- Status badges: pill with leading dot instead of plain colored text - */
.sapMObjStatus {
  display: inline-flex;
  align-items: center;
  gap: var(--vf-space-2);
  padding: 1px var(--vf-space-4) 1px var(--vf-space-3);
  border-radius: var(--vf-radius-pill);
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-medium);
  border: 1px solid transparent;
}

.sapMObjStatus::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex: none;
}

.sapMObjStatusSuccess {
  background: var(--vf-success-bg);
  border-color: var(--vf-success-border);
  color: var(--vf-success);
}
.sapMObjStatusSuccess::before {
  background: var(--vf-success);
}

.sapMObjStatusWarning {
  background: var(--vf-warning-bg);
  border-color: var(--vf-warning-border);
  color: var(--vf-warning);
}
.sapMObjStatusWarning::before {
  background: var(--vf-warning);
}

.sapMObjStatusError {
  background: var(--vf-error-bg);
  border-color: var(--vf-error-border);
  color: var(--vf-error);
}
.sapMObjStatusError::before {
  background: var(--vf-error);
}

/* Information war als einziger Zustand nicht als Pille gestaltet - er fiel
   deshalb auf die UI5-Vorgabe zurueck und erschien als blauer Text, der wie
   ein Link aussieht. Aufgefallen am Zustand "freigegeben" eines
   Transportauftrags (Befund K2, 27.08.2026), betrifft aber jede kuenftige
   Verwendung. Die Tokens dafuer gab es laengst. */
.sapMObjStatusInformation {
  background: var(--vf-info-bg);
  border-color: var(--vf-info-border);
  color: var(--vf-info);
}
.sapMObjStatusInformation::before {
  background: var(--vf-info);
}

.sapMObjStatusNone {
  background: var(--vf-surface-sunk);
  border-color: var(--vf-border);
  color: var(--vf-text-secondary);
}
.sapMObjStatusNone::before {
  background: var(--vf-text-muted);
}

/* ---- Dialogs / popovers: vFlow radii + shadows -------------------------- */
.sapMDialog {
  border-radius: var(--vf-radius-lg);
  box-shadow: var(--vf-shadow-lg);
}

.sapMDialogTitleGroup {
  font-weight: var(--vf-fw-semibold);
}

.sapMPopover {
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-md);
}

/* ---- Dashboard stat tiles (Cards, CLAUDE.md Abschnitt 6) ----------------- */

/* Kachelreihe (Stefan, 2026-08-19, Package-Uebersicht). Ersetzt dort
   sap.ui.layout.Grid, das zwei sichtbare Fehler hatte:

   1. Es setzt auf jede Spalte ein seitliches Padding (hSpacing, Vorgabe 1).
      Die erste Kachel begann dadurch ein halbes rem weiter rechts als die
      Karten darunter - eine Kante, die nirgends fluchtete.
   2. Seine Spalten sind Floats. Kacheln mit unterschiedlich vielen Zeilen
      wurden deshalb unterschiedlich hoch; die Kachel mit einer dritten Zeile
      ragte nach unten heraus.

   Ein CSS-Grid loest beides ohne Zutun: `stretch` ist die Vorgabe fuer
   Grid-Items, also sind alle Kacheln so hoch wie die hoechste, und der
   Abstand kommt aus `gap` statt aus Innenabstaenden (CLAUDE.md Abschnitt 4:
   flex/grid mit gap statt Margins).

   `auto-fit` statt fester Umbruchpunkte: die Reihe legt selbst um, sobald
   eine Kachel unter 200px fiele - vier Spalten am Schreibtisch, zwei auf dem
   Tablet, eine auf dem Telefon, ohne L3/M6/S12 zu pflegen.

   !important, weil UI5 auf jede FlexBox eine eigene .sapMFlexBox-Regel mit
   `display:flex` legt, die nach vflow.css injiziert wird und sonst gewinnt -
   dieselbe Falle wie bei .vfMetadataRow. Die Reihe braucht ausserdem
   renderType="Bare" in der View, sonst wickelt UI5 jede Kachel in ein
   .sapMFlexItem-div, und die Grid-Items waeren die Wrapper statt der
   Kacheln. */
.vfStatTileRow {
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--vf-space-4);
}

.vfStatTile {
  background: var(--vf-surface);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-sm);
  padding: var(--vf-space-6);
  gap: var(--vf-space-2);
  /* Fuellt die vom Grid zugeteilte Zeilenhoehe aus - ohne das bliebe die
     Kachel auf ihrer Inhaltshoehe stehen und der Rahmen endete zu frueh. */
  height: 100%;
  box-sizing: border-box;
}

/* Untere Zeile einer Kachel (Kontext zum Wert). Der Abstand nach oben
   entsteht aus `margin-top:auto`, damit sie am unteren Rand sitzt statt
   direkt unter dem Wert zu kleben - erst dadurch sieht eine Reihe aus
   gleich hohen Kacheln auch ruhig aus. */
.vfStatTileSub {
  margin-top: auto;
}

.vfStatTileLabel {
  color: var(--vf-text-secondary);
  font-size: var(--vf-fs-sm);
}

/* Klickbare Kacheln (Stefan-Wunsch 2026-07-20: "37 Failed" -> direkt zur
   gefilterten Liste springen). VBox hat kein eigenes press-Event, siehe
   Dashboard.controller.js#onAfterRendering - hier nur die visuelle/
   Tastatur-Fokus-Seite davon. */
.vfStatTileClickable {
  cursor: pointer;
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.vfStatTileClickable:hover {
  box-shadow: var(--vf-shadow-md);
  border-color: var(--vf-border-strong);
}
.vfStatTileClickable:focus-visible {
  outline: none;
  box-shadow: var(--vf-shadow-focus);
}

.vfStatTileValue {
  font-size: var(--vf-fs-display);
  font-weight: var(--vf-fw-semibold);
  color: var(--vf-text);
}

.vfStatTileError {
  /* !important: UI5's own text-color rule for .sapMText is injected at
     runtime after this stylesheet, so equal specificity would win by
     source order otherwise - same trap as the Button color override. */
  color: var(--vf-error) !important;
}

.vfStatTileSuccess {
  color: var(--vf-success) !important;
}

.vfStatTileWarn {
  color: var(--vf-warning) !important;
}

/* Icon-Badge oben in jeder Stat-Kachel (Stefan, 2026-07-17: "Kacheln ein
   wenig aufwerten") - gleiches Rounded-Square-Rezept wie .vfCardIconBadge,
   nur etwas größer und mit Tint-Varianten je Kachel-Semantik statt fix
   violett. */
.vfStatTileIcon {
  box-sizing: border-box;
  width: 28px !important;
  height: 28px !important;
  line-height: 28px !important;
  margin: 0 !important;
  border-radius: var(--vf-radius-sm);
  font-size: 15px !important;
  text-align: center;
}
.vfStatTileIconNeutral {
  background: var(--vf-surface-sunk);
  color: var(--vf-text-secondary) !important;
}
.vfStatTileIconPrimary {
  background: var(--vf-primary-subtle);
  color: var(--vf-primary) !important;
}
.vfStatTileIconError {
  background: var(--vf-error-bg);
  color: var(--vf-error) !important;
}
.vfStatTileIconSuccess {
  background: var(--vf-success-bg);
  color: var(--vf-success) !important;
}

/* ---- Dashboard welcome header + Fuchs-Maskottchen (Valcoba-Branding,
   Stefan-Wunsch 2026-07-17) - bewusst nur hier, kein Wiederholungsmotiv:
   vFlows eigener Indigo-Akzent bleibt der einzige Funktionsfarbton (CLAUDE.md
   §2), der Fuchs ist reine Markenpflege im Willkommens-Header, keine
   UI-Farbänderung. ---------------------------------------------------------- */
.vfWelcomeHeader {
  background: var(--vf-surface);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-sm);
  padding: var(--vf-space-6) var(--vf-space-7);
  overflow: hidden;
}

.vfWelcomeFox {
  height: 96px;
  width: auto;
  flex: none;
  /* Leichter Versatz nach unten/rechts raus - der Fuchs "sitzt" am
     Kartenrand statt mittig zu schweben. */
  margin: 0 calc(var(--vf-space-7) * -1) calc(var(--vf-space-4) * -1) 0;
}

/* Handy-Ansicht Dashboard/Alerts (Stefan, 2026-08-06: "kurz auf dem Handy
   nach dem Rechten schauen") - bewusst nur diese beiden Screens, alles
   andere (Monitoring-Tabellen, FlowEditor) bleibt Desktop-fokussiert.
   599px = UI5s eigene Phone-Grenze (sap.ui.Device.media, dieselbe Schwelle,
   die minScreenWidth="Tablet" in den *.view.xml-Popin-Spalten meint). Der
   Fuchs ist reines Branding (siehe oben) - auf dem schmalen Screen frisst er
   nur Platz, den die Begrüßung sonst hätte. */
@media (max-width: 599px) {
  .vfWelcomeFox {
    display: none;
  }
}

/* Valcoba-Logo auf der About-Seite (Kontakt-Kachel, Stefan-Wunsch
   2026-08-05) - bewusst nur dort, nicht im Shell-Header: die Topbar ist
   vFlows eigene, prominenteste Markenfläche (CLAUDE.md §2, "own accent
   color"), Orange neben dem Indigo-Primary würde dort wie eine zweite,
   konkurrierende Marke wirken. Im Kontaktblock ist es reine Firmen-Info,
   unproblematisch wie beim Fuchs oben. */
.vfValcobaLogo {
  height: 40px;
  width: auto;
}

/* ---- Dashboard-Widgets (Braucht Aufmerksamkeit / Letzte Aktivität / Offene
   Alerts) - je eine .vfCard mit Titel+Untertitel-Kopf und einer dichten
   Tabelle (CLAUDE.md §6: Tables sind der Workhorse von Dashboard &
   Monitoring). ---------------------------------------------------------- */
.vfDashboardWidgetHead {
  gap: var(--vf-space-1);
}

.vfDashboardCount {
  font-family: var(--vf-font-mono) !important;
  font-weight: var(--vf-fw-semibold);
}

/* ---- Flow-Editor Pipeline (Sender-Adapter-Routing-Mapping-Adapter-Receiver)
   Feste Breite (statt min-width) auf Boxen/Pfeilen/Labels, damit die
   Kopfzeile mit den Spaltenbeschriftungen exakt über den Box-Reihen der
   einzelnen Zweige fluchtet. */
.vfPipelineBox {
  width: 140px;
  flex: none;
}

.vfPipelineBox .sapMBtnInner {
  border-radius: var(--vf-radius-md) !important;
  border: 1px solid var(--vf-border-strong) !important;
  background: var(--vf-surface) !important;
  color: var(--vf-text) !important;
  height: 48px !important;
  white-space: normal !important;
}

/* Waagerechter Verbinder zwischen zwei Pipeline-Karten: echte Linie von
   Kante zu Kante (Schaft + Pfeilspitze) statt eines freistehenden Glyphs. Die
   Karten liegen ohne Gap direkt neben dem 32px-Element, daher berührt die
   Linie beide Kartenränder. Der →-Glyph wird über font-size:0 ausgeblendet. */
.vfPipelineArrow {
  width: var(--vf-pipeline-gap);
  flex: none;
  /* Der Verbinder ist genau so hoch wie eine Karte und traegt seine Linie auf
     halber Hoehe (top:50% unten) - damit trifft er die Kartenmitte, ganz egal
     wie die umgebende HBox ausgerichtet ist. Vorher war er 12px hoch und mit
     align-self:center zentriert; das ging aus zwei Gruenden schief (Stefan,
     2026-08-08: "Wieso ist der Pfeil bei den ersten zwei Boxen oben und dann
     wechselt es in die Mitte"):
       1. align-self wirkte gar nicht. UI5 haengt jedes FlexBox-Kind in einen
          eigenen <div class="sapMFlexItem"> - ausgerichtet wird dieser, nicht
          das Control darin. In der oberen Kette steht alignItems="Start"
          (FlowEditor.view.xml), die 29px hohe Huelle klebte also oben in der
          96px hohen Reihe: Pfeil 25px zu hoch.
       2. Auch in den zentrierten Zweig-Reihen sass er 8px zu tief, weil
          .sapMText das Control auf inline-block zwingt - als Inline-Box steht
          es auf der Textgrundlinie, und die Huelle wird um die Unterlaenge
          hoeher als der Pfeil selbst.
     align-self:flex-start ist wichtig fuer den Bridge-Modus: dort ist die
     Sender-Spalte hoeher als eine Karte (Antwort-Box darunter), zentriert
     wuerde der Verbinder auf die Mitte dieses Stapels rutschen statt auf die
     Kartenreihe. */
  align-self: flex-start;
  /* !important: UI5 laedt .sapMText NACH dem App-CSS bei gleicher
     Spezifitaet - ohne !important bliebe es bei inline-block (Grund 2 oben)
     und der ausgeblendete →-Glyph sichtbar (font-size). */
  display: block !important;
  position: relative;
  height: var(--vf-pipeline-card-h);
  font-size: 0 !important;
  color: transparent;
}
.vfPipelineArrow::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  right: 5px;
  height: 2px;
  margin-top: -1px;
  background: var(--vf-border-strong);
}
.vfPipelineArrow::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  margin-top: -5px;
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 7px solid var(--vf-border-strong);
}

.vfPipelineArrowSpacer {
  width: var(--vf-pipeline-gap);
  flex: none;
}

/* Async-Sync Bridge (adapter-plugin.md Abschnitt 7): Rückspur unter der
   Hinspur. Der Response-Adapter stand früher als eigene Spalte unter dem
   SENDER, mit einem senkrechten Pfeil dazwischen - das legte nahe, die
   Antwort ginge an den Sender zurück. Sie geht aber an ein frei gewähltes,
   unabhängiges Ziel (§7: "kein Bezug zum Sender- oder Receiver-Adaptertyp";
   Stefans Testflow hat einen REST-Sender und schreibt die Antwort in eine
   Datei). Deshalb jetzt eine eigene Reihe, gelesen von rechts nach links:
   Receiver -> Response-Mapping -> Response-Adapter -> hinaus. Die Verbinder
   dieser Reihe zeichnet _drawBranchConnectors als SVG, weil sie über die
   Grenze zwischen linker Kette und Zweig-Stapel hinweglaufen. */
.vfResponseRow {
  margin-top: var(--vf-space-7);
}
/* Hält den Response-Adapter unter dem Inbound-Adapter (Breite von Sender-
   Karte + Verbinder), statt ihn an den linken Rand zu setzen. */
.vfResponseRowSpacer {
  width: calc(var(--vf-pipeline-card-w) + var(--vf-pipeline-gap));
  flex: none;
}

.vfPipelineLabel {
  width: 140px;
  flex: none;
  text-align: center;
  color: var(--vf-text-secondary);
  font-size: var(--vf-fs-sm);
  font-weight: var(--vf-fw-medium);
}

/* Senkrechter Verbinder Routing -> Zweige, unter der Routing-Box zentriert
   (flow-editor.md Layout-Korrektur, ASCII-Diagramm Abschnitt 4). */
/* Fan-out-Canvas: geteilte Kette links, Zweig-Stapel rechts. Die
   Fan-out-Verbinder zeichnet _drawBranchConnectors als absolutes SVG-Overlay
   ueber diese (relativ positionierte) Stage. */
/* Eigener Scroll-Bereich fuer das Flussdiagramm (CLAUDE.md Abschnitt 4:
   nur Tabellen, Diagramme und Code duerfen breiter sein - jedes in seinem
   eigenen overflow-x-Container, damit die SEITE nie waagerecht scrollt).
   Bis 22.09.2026 fehlte er: eine lange Kette schob Seitennavigation und
   Kopfleiste aus dem Bild. */
.vfFlowStageScroll {
  overflow-x: auto;
  /* Platz fuer die Scrollleiste, damit sie nicht auf der untersten
     Kartenreihe liegt. */
  padding-bottom: var(--vf-space-2);
}

.vfFlowStage {
  position: relative;
}
.vfSharedChain {
  flex: none;
}
.vfBranchStack {
  flex: none;
  /* Luecke fuer die Fan-out-Verbinder zwischen Routing und Mapping. */
  margin-left: 64px;
}
.vfBranchItem {
  margin-bottom: 16px;
}
/* SVG-Overlay: unter den Karten, faengt keine Klicks ab; currentColor traegt
   die Verbinderfarbe an stroke/fill weiter. */
.vfFanoutSvg {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  color: var(--vf-border-strong);
}

.vfBranchesSection {
  gap: var(--vf-space-2);
}

/* Zweig-Liste: eigene Boxen tragen bereits Rahmen/Schatten - die Listenzeile
   selbst soll unsichtbar bleiben, kein doppelter Rahmen/Zebra-Hintergrund. */
.vfBranchesList .sapMLIB {
  background: transparent;
  border: none;
  padding: 0;
}

.vfBranchesList .sapMLIB:hover {
  background: transparent;
}

/* Kleingedrucktes unter einem Adapter-Config-Feld (adapter-config-schema.ts
   auf dem Backend, field.helpText) - z. B. "Default 30 Sekunden". */
/* Ein Auswahlfeld, in dem noch NICHTS gewaehlt ist, sieht leer aus - wie ein
   Feld mit Platzhalter. Gesetzt wird die Klasse von model/auswahl.js, das auch
   erklaert, warum ein Eintrag mit leerem Key ("Alle Packages", "Keine") KEINE
   Aufforderung ist und dunkel bleibt.

   !important, weil sap.m.Select keinen Platzhalter kennt - es gibt also kein
   Steuerelement, das den Zustand ausdrueckt (CLAUDE.md laesst !important genau
   dafuer zu). UI5s eigene Regel fuer .sapMSltLabel kommt zur Laufzeit NACH
   dieser Datei und gewinnt sonst.

   Und eine Lehre zur Messung: die erste Fassung stand ohne !important, weil
   eine Probe im Browser gewirkt hatte - die war per <style> ans ENDE des
   <head> gehaengt und damit an einer Position, die vflow.css nie hat.
   Ausgerollt war sie wirkungslos. Eine Probe muss dort stehen, wo die echte
   Datei steht (21.09.2026). */
.vfSelectAufforderung .sapMSltLabel {
  color: var(--vf-text-placeholder) !important;
  font-style: italic !important;
}

.vfFieldHelp {
  display: block;
  /* !important: UI5s .sapMText wird erst zur Laufzeit nach dem App-CSS geladen
     und gewinnt sonst bei gleicher Spezifität (14px/Default-Farbe) - dadurch
     wirkten Untertexte/Hinweise faelschlich so gross wie normaler Text. */
  color: var(--vf-text-muted) !important;
  font-size: var(--vf-fs-caption) !important;
}

/* Beschriftungsspalte einer Einstellungszeile (Settings.view.xml).

   Die Zeilen sind HBoxen mit justifyContent="SpaceBetween": links Titel plus
   Hilfetext, rechts das Eingabefeld in einer festen Breite. Ohne Begrenzung
   nimmt sich die linke Seite so viel Platz, wie ihr Text braucht - und
   schiebt das Eingabefeld nach rechts. Zeilen mit langem Hilfetext standen
   dadurch sichtbar weiter rechts als ihre Nachbarn (Stefan, 2026-08-17:
   "die Box etwas nach links nehmen, damit sie unter den anderen liegt").

   flex-basis 0 statt auto: die Spalte bekommt den RESTPLATZ zugeteilt statt
   ihren Inhalt als Ausgangsbreite zu nehmen. min-width 0 hebt die
   Flexbox-Vorgabe auf, unter die Inhaltsbreite nicht zu schrumpfen - erst
   damit umbricht der Hilfetext, statt zu draengeln. */
.vfSettingsLabel {
  flex: 1 1 0;
  min-width: 0;
}

/* Beschreibungstext in einer dichten Tabellenzeile auf zwei Zeilen kappen.
   Gebraucht seit dem Messages-Standard-Katalog (docs/architecture/
   message-catalog.md): Katalog-Beschreibungen sind ganze Saetze und trieben
   die Zeilenhoehe von den im Design-System vorgesehenen 36-40px auf ueber
   120px. Der volle Text bleibt ueber das Title-Attribut/den Dialog
   erreichbar. */
.vfClamp2 {
  display: -webkit-box !important;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Zweispaltiges Formular im Property-Panel des Flow Editors (SAP-Integration-
   Suite-Optik): Label links (fett, rechtsbündig), Eingabefeld rechts.
   Aufgebaut in FlowEditor.controller.js#_addFormRow als HBox[Label | VBox]. */
/* ZWEISPALTIGES RASTER, Label ueber dem Feld (Design-Handoff
   "Eigenschaften-Panel", 11.09.2026, Option 1c).
   ===========================================================================
   Bis dahin stand das Label in einer schmalen Spalte LINKS neben dem Feld,
   und jede Zeile nahm die volle Panelbreite ein. Das war die Ursache des
   Befunds "das Formular passt nicht ins Bottom-Panel": bei 20 Feldern sind
   das 20 Zeilen, von denen jede zu zwei Dritteln leer ist.

   Jetzt: zwei Spalten, Label darueber. Alles, was KEINE Formularzeile ist -
   Einleitungssatz, Zwischenueberschrift, Tabelle, Knopfleiste - nimmt
   automatisch die volle Breite. Das ist die Regel herum statt einer Liste
   von Ausnahmen, und sie gilt damit auch fuer alles, was spaeter dazukommt.

   Bekannte Grenze: die Umschaltung auf eine Spalte haengt am FENSTER, nicht
   an der Panelbreite. Wer den Splitter weit nach rechts zieht, hat auf einem
   breiten Bildschirm zwei enge Spalten. Eine Container-Query kann das
   Raster nicht auf sich selbst anwenden; sauber waere ein ResizeHandler auf
   dem Panel - lohnt sich, sobald es jemanden stoert. */
/* ZWEI Klassen, nicht eine - und das ist der ganze Grund, warum das Raster
   bis zum 14.09.2026 NIE gezeichnet wurde: UI5s `.sapMFlexBox { display:
   flex }` (0,1,0) kommt zur Laufzeit ins Dokument und gewinnt gegen ein
   `.vfPanelRaster { display: grid }` derselben Staerke. Im Browser auf DEV
   gemessen: computed display "flex", grid-template-columns brav gesetzt und
   wirkungslos. Der Handoff-Entwurf vom 11.09. war ausgeliefert, die
   Selects standen trotzdem in voller Breite - genau das Bild, das Stefan
   als "nicht ganz getroffen" zurueckgab. Mit der UI5-Klasse als zweitem
   Glied sind es (0,2,0), und es braucht kein !important. */
.vfPanelRaster.sapMFlexBox {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--vf-space-7, 24px);
  row-gap: var(--vf-space-5, 16px);
  align-items: start;
}
.vfPanelRaster > * {
  grid-column: 1 / -1;
}
.vfPanelRaster > .vfFormRow {
  grid-column: auto;
}
/* Felder, die mit einer halben Zeile nicht auskommen: Pfade, Ausdruecke mit
   ${...}, Spaltenlisten, Cron. Der Handoff nennt sie einzeln; hier
   entscheidet der Feldtyp, damit ein neues Textarea-Feld nicht vergessen
   wird. */
.vfPanelRaster > .vfFormRowBreit {
  grid-column: 1 / -1;
}
@media (max-width: 1100px) {
  .vfPanelRaster.sapMFlexBox {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Die Spaltenrichtung kommt vom CONTROL (sap.m.VBox), nicht von hier.
   Warum das nicht egal ist: `flex-direction` stand bis zum 11.09.2026 in
   dieser Regel - und verlor. UI5 bringt `.sapMHBox { flex-direction: row }`
   mit, GLEICHE Spezifitaet (0,1,0), und sein Stylesheet wird vom Bootstrap
   erst zur Laufzeit nachgeladen, also NACH diesem hier. Der Handoff-Entwurf
   war damit ausgeliefert, und die Labels standen trotzdem links.
   Dieselbe Falle steckt in den `!important` weiter unten (Textfarbe,
   Ausrichtung) - dort war sie schon zweimal umschifft worden, statt sie
   einmal zu benennen. Merksatz: bei gleicher Spezifitaet gewinnt UI5.
   Wer ein Layout gegen eine UI5-Klasse stellt, hat es schon verloren. */
.vfFormRow {
  align-items: stretch;
  gap: var(--vf-space-1, 4px);
  padding: 0;
}
.vfFormRow > .vfFormLabel {
  flex: 0 0 auto;
  max-width: 100%;
  min-width: 0;
  /* linksbündig (Stefan-Review 2026-07-10: die frühere rechtsbündige SAP-Optik
     drückte die Labels an die Feldspalte; linksbündig + schmalere Spalte liest
     sich ruhiger). !important, da UI5s .sapMLabel eine eigene text-align-Regel
     mitbringt, die sonst bei gleicher Spezifität nach dem App-CSS gewinnt. */
  text-align: left !important;
  /* Das Label steht ueber dem Feld - kein Ausrichten auf eine Feldzeile
     mehr noetig (Handoff 11.09.2026). */
  padding-top: 0;
  /* !important: UI5s .sapMLabel-Farbe wird erst zur Laufzeit nach dem App-CSS
     geladen und gewinnt sonst bei gleicher Spezifität (gedämpftes Grau) -
     Stefan möchte kräftigere Labels (siehe CLAUDE.md §4). */
  color: var(--vf-text) !important;
}
/* UI5 rendert das Label als inline-flex (.sapMLabelInner) und packt den
   Textteil per justify-content ans Ende - text-align auf dem Label greift bei
   Flex-Kindern nicht. Für echte Linksbündigkeit hier den inneren Flex umstellen. */
.vfFormRow > .vfFormLabel .sapMLabelInner {
  justify-content: flex-start !important;
}
/* Eine Label-Zeile ist immer gleich hoch - mit ⓘ wie ohne.
   Vorher trug das ⓘ seine Knopfhoehe in die Zeile (32px statt 16px), und
   damit begann das Feld der Nachbarspalte 16px hoeher: "Zeitplan ⓘ" neben
   "Abfrageintervall" stand auf 423 zu 407 (im Panel gemessen, 21.09.2026).
   Zwei Felder nebeneinander, die versetzt stehen, lesen sich wie zwei
   verschiedene Abschnitte.
   Die Regel greift beide Faelle: `.vfFormLabel` traegt sowohl das nackte
   Label als auch die HBox mit ⓘ.
   Grenze: ein Label, das auf ZWEI Zeilen umbricht, ist wieder hoeher als
   sein Nachbar - dagegen hilft nur ein kuerzeres Label. */
.vfFormRow > .vfFormLabel {
  min-height: var(--vf-label-line);
  line-height: var(--vf-label-line);
}
.vfFormRow > .vfFormLabel .sapMLabelInner {
  line-height: var(--vf-label-line);
}
/* Ein Label MIT ⓘ steckt in einer HBox (.vfFormLabelMitHilfe) und ist damit
   kein direktes Kind der Zeile mehr - die Farbregel darueber (`.vfFormRow >
   .vfFormLabel`) traf nur die Huelle, das Label darin blieb in UI5s
   gedaempftem Grau. Im Browser auf DEV gemessen (14.09.2026): rgb(85,107,130)
   mit ⓘ, rgb(23,26,34) ohne. Ein Formular, in dem die Labels mit Hilfe
   blasser sind als die ohne, liest sich, als waeren sie weniger wichtig. */
.vfFormRow .vfFormLabelMitHilfe > .sapMLabel {
  color: var(--vf-text) !important;
}
.vfFormRow > .vfFormField {
  flex: 1 1 auto;
  /* min-width:0, damit lange Werte/Inputs in der Flex-Spalte schrumpfen dürfen
     statt die Zeile zu sprengen. */
  min-width: 0;
  gap: var(--vf-space-1);
}
/* Mehrere Felder nebeneinander in EINER Formularzeile ("Abfrageintervall
   [5] [Sekunden]", "Zeitfenster [von] [bis]"). Gleiche Breite je Zelle, damit
   die Spalten mehrerer Gruppenzeilen untereinander fluchten - ungleiche
   Breiten laesen die Zeilen wie versehentlich verrutscht aussehen. */
.vfFormFieldGroup {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--vf-space-4);
}
.vfFormGroupCell {
  flex: 1 1 0;
  /* Damit ein langer Hinweistext die Zelle nicht auseinanderdrueckt. */
  min-width: 0;
  gap: var(--vf-space-1);
}

/* Kicker-Überschrift einer Feld-Untergruppe (adapter-config-schema.ts
   field.section), analog SAP CONNECTION/ADVANCED SETTING. */
.vfFormSection {
  display: block;
  margin: var(--vf-space-5) 0 var(--vf-space-2);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  /* !important: gleiche .sapMText-Übersteuerung wie bei .vfFieldHelp. */
  font-size: var(--vf-fs-caption) !important;
  font-weight: 600 !important;
  color: var(--vf-text-secondary) !important;
}
.vfFormSection:first-child {
  margin-top: 0;
}

/* Mapping Studio (mapping-studio.md): Kicker neben dem Typ-Select ohne
   Block-Abstand, und etwas Luft zwischen den Sample-Steuerelementen. */
.vfStudioKicker {
  margin: 0 var(--vf-space-3) 0 0 !important;
}
.vfStudioSampleBar {
  gap: var(--vf-space-2);
  align-items: center;
}

/* ---- Mapping Studio, Redesign 1b (Design-Handoff 11.09.2026) -------------
   Zweispaltig: Seitenleiste 300px, Hauptbereich nimmt den Rest. Die Masse
   stammen aus dem Handoff, die FARBEN aus den vFlow-Token - der Mockup nennt
   Hex-Werte des SAP-Horizon-Themes, vFlow hat eigene (CLAUDE.md §2). */
.vfStudioSpalten {
  height: 100%;
  align-items: stretch;
}
.vfStudioSeitenleiste {
  width: 300px;
  min-width: 300px;
  padding: var(--vf-space-4) var(--vf-space-5);
  gap: var(--vf-space-5);
  background: var(--vf-bg);
  border-right: 1px solid var(--vf-border);
  /* Eigener Scrollbereich: die Leiste darf laenger werden als der Dialog,
     ohne ihn zu strecken. Der Innenabstand unten gehoert dazu - ohne ihn
     klebte der Kennzahlen-Block an der Kante und wurde angeschnitten (im
     Browser gesehen). */
  overflow-y: auto;
  padding-bottom: var(--vf-space-5);
  box-sizing: border-box;
}
.vfStudioHaupt {
  flex: 1 1 auto;
  min-width: 0;
  background: var(--vf-surface);
}
/* Der Kennzahlen-Block sitzt unten - dafuer muss die Leiste ihn schieben
   koennen, und der Block selbst darf nicht mitwachsen. */
.vfStudioKennBlock {
  margin-top: auto;
  padding-top: var(--vf-space-3);
  border-top: 1px solid var(--vf-border);
  gap: var(--vf-space-1);
}
.vfStudioKennZeile {
  gap: var(--vf-space-3);
}
.vfStudioKennLabel {
  color: var(--vf-text-muted);
  font-size: 12.5px;
}
.vfStudioKennWert {
  font-size: 12.5px;
  color: var(--vf-text);
}
.vfKennGut { color: var(--vf-success) !important; font-weight: 600; }
.vfKennWarn { color: var(--vf-warning) !important; font-weight: 600; }
.vfKennSchlecht { color: var(--vf-error) !important; font-weight: 600; }

/* Die Fehlerzahl oeffnet die Meldung - das muss der Zeiger sagen, sonst
   probiert es niemand (Klickprobe 14.09.2026). Die Klasse haengt am Wert nur,
   solange es wirklich etwas zu oeffnen gibt: ein Zeiger ueber "keine" waere
   dieselbe Luege andersherum.

   Zwei Klassen tief, weil eine einfache verloere - und die Gegnerin heisst
   `.sapMText { cursor: text }` (0,1,0). Das ist NACHGESCHLAGEN und nicht
   vermutet: im ausgelieferten Theme (sap_horizon, sap/m/themes/.../library.css)
   setzt `.sapUiSelectable` nur `user-select`, den Schreibbalken bringt die
   Grundregel von `sap.m.Text` mit. Sie kommt erst zur Laufzeit ins Dokument
   und gewinnt deshalb bei gleicher Spezifitaet (CLAUDE.md §4); mit dem
   Vorfahren sind es (0,2,0). Die Kinder stehen ausdruecklich dabei, falls der
   Text einmal in einem inneren Knoten landet. */
.vfStudioKennZeile .vfStudioKennKlickbar,
.vfStudioKennZeile .vfStudioKennKlickbar * {
  cursor: pointer;
}
.vfStudioKennZeile .vfStudioKennKlickbar:hover {
  text-decoration: underline;
}

/* Werkzeuge im Kopf einer Editorspalte (Kopieren, Einruecken). Icons statt
   Woerter: in der Zeile stehen schon Zeilenzahl und Groesse, zwei Woerter
   daneben lesen sich wie eine Navigation. Die Woerter stehen im Tooltip.

   Kleiner als ein normaler Knopf, damit die Zeile ihre Hoehe behaelt - der
   Kopf ist eine Auskunftszeile und keine Werkzeugleiste.

   ## Warum die Selektoren so tief sind

   Nachgeschlagen im ausgelieferten Theme, nicht geraten
   (sap/m/themes/sap_horizon/library.css):

     .sapUiSizeCompact .sapMBtnInner      (0,2,0)  height, min-width
     .sapMBtnIcon.sapUiIcon               (0,2,0)  font-size, line-height, width
     .sapUiSizeCompact .sapMBtnIcon.sapUiIcon (0,3,0)  dieselben, kleiner

   `sapUiSizeCompact` steht bei vFlow am <body>, diese Regeln greifen also
   alle. Ein `.vfStudioWerkzeug .sapMBtnInner` waere mit (0,2,0) GLEICH stark
   - und UI5s Stylesheet kommt erst zur Laufzeit ins Dokument und gewinnt
   dann (CLAUDE.md §4). Mit der eigenen Klasse am Knopf davor sind es (0,3,0)
   bzw. (0,4,0), und es braucht kein !important. */
.vfStudioWerkzeug.sapMBtn {
  min-width: 0;
  height: 24px;
  margin-left: var(--vf-space-2);
}
.vfStudioWerkzeug.sapMBtn .sapMBtnInner {
  height: 24px;
  min-width: 24px;
  padding: 0 var(--vf-space-1);
}
.vfStudioWerkzeug.sapMBtn .sapMBtnIcon.sapUiIcon {
  font-size: 14px;
  line-height: 22px;
  width: auto;
  min-width: 16px;
  max-height: 22px;
  color: var(--vf-text-muted);
}
.vfStudioWerkzeug.sapMBtn:hover .sapMBtnIcon.sapUiIcon {
  color: var(--vf-primary);
}

.vfStudioAbschnitt {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--vf-text-muted);
}
.vfStudioAbschnittHinweis {
  font-size: 12px;
  color: var(--vf-text-muted);
  margin-left: var(--vf-space-2);
}
.vfStudioAbschnittKopf {
  margin-bottom: var(--vf-space-2);
}
.vfStudioLinkZeile,
.vfStudioLinkListe {
  gap: var(--vf-space-3);
  margin-top: var(--vf-space-2);
}
.vfStudioLinkListe { flex-direction: column; }
.vfStudioLinkLoeschen .sapMLnkText { color: var(--vf-error) !important; }
.vfStudioSampleListe {
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-card, 8px);
  overflow: hidden;
  background: var(--vf-surface);
}

/* Test-Header: zwei Felder je Zeile, die leere letzte gestrichelt - sie ist
   ein Angebot und kein Eintrag. */
.vfStudioHeaderZeilen { gap: var(--vf-space-1); }
.vfStudioHeaderZeile {
  gap: var(--vf-space-1);
  align-items: center;
}
.vfStudioHeaderZeile .sapMInputBaseInner { font-family: var(--vf-font-mono); }
.vfStudioHeaderLeer .sapMInputBaseContentWrapper {
  border-style: dashed !important;
}

/* Pipeline-Stepper: fuenf gleich breite Kacheln in einer Reihe. Eigenbau,
   weil UI5 dafuer kein Control mitbringt (Handoff, Option a). Die Kacheln
   sind verbunden - nur die Aussenecken sind rund, innere Linien entfallen
   zwischen zwei gewaehlten. */
.vfStudioStufenKopf {
  padding: var(--vf-space-4) var(--vf-space-6) var(--vf-space-3);
  border-bottom: 1px solid var(--vf-border);
  gap: var(--vf-space-2);
}
/* Der Meldungsstreifen steht direkt unter dem Stufenkopf und muss mit ihm
   fluchten. Er hing bis zum 14.09.2026 ohne jeden Seitenabstand an der Kante,
   waehrend die Stufen-Kacheln darueber `--vf-space-6` Abstand haben - im
   Bild ist das die Zeile, die aus dem Raster faellt. Derselbe Wert also, und
   er steht nur hier: der Kopf bringt ihn als PADDING mit (er hat einen Rahmen
   unten, der ueber die volle Breite laufen soll), der Streifen als MARGIN. */
.vfStudioHaupt .vfStudioMeldung {
  margin: 0 var(--vf-space-6) var(--vf-space-3);
}
.vfStudioStepper {
  display: grid !important;
  grid-template-columns: repeat(5, 1fr);
  margin-top: var(--vf-space-2);
}
/* JEDE Kachelregel traegt `.vfStudioStepper` vor sich - nicht aus Ordnungsliebe,
   sondern weil die einfachen Klassen den Kampf verlieren. Am 12.09.2026 im
   Browser gemessen: `.vfStepperKachel { background: var(--vf-surface) }` (0,1,0)
   verliert gegen `.sapMFlexBoxBGTransparent` (0,1,0), und `.vfStepperKachel *
   { cursor: pointer }` gegen `.sapUiSelectable` - beide UI5-Regeln kommen erst
   zur Laufzeit ins Dokument und gewinnen damit bei gleicher Spezifitaet
   (CLAUDE.md §4). Die Folge war unsichtbar in der Datei und sichtbar nur am
   Schirm: die Kacheln waren durchsichtig statt weiss, die gewaehlte hatte keine
   Fuellung, und ueber der Beschriftung stand der Schreibbalken statt des
   Zeigers. Mit dem Vorfahren sind es (0,2,0) - kein !important noetig. */
.vfStudioStepper .vfStepperKachel {
  /* Ohne user-select markiert ein schneller Doppelklick auf zwei Kacheln
     die halbe Seite als Text - im Browser gesehen. */
  user-select: none;
  padding: var(--vf-space-2) var(--vf-space-3);
  gap: 2px;
  border: 1px solid var(--vf-border);
  border-left-width: 0;
  background: var(--vf-surface);
  cursor: pointer;
}
/* Der Zeiger muss auch UEBER DEN TEXTEN gelten. Auf der Kachel allein reicht
   er nicht: die drei Text-Controls darin bringen ihren eigenen Cursor mit,
   und genau ueber der Beschriftung - also dort, wo man hinzeigt - stand der
   Schreibbalken (Stefan, 12.09.2026: "der Cursor sollte auf der ganzen Box
   sichtbar sein"). */
.vfStudioStepper .vfStepperKachel * {
  cursor: pointer;
}
/* Alle fuenf Kacheln sind waehlbar - auch die beiden Enden: "von Eingang
   (roh)" und "bis Ausgang" sind die Kanten, die man am haeufigsten meint
   (Stefan, 12.09.2026). Deshalb keine Ausnahme mehr fuer die Enden. */
.vfStudioStepper > .vfStepperKachel:first-child {
  border-left-width: 1px;
  border-radius: var(--vf-radius-card, 8px) 0 0 var(--vf-radius-card, 8px);
}
.vfStudioStepper > .vfStepperKachel:last-child {
  border-radius: 0 var(--vf-radius-card, 8px) var(--vf-radius-card, 8px) 0;
}
.vfStudioStepper .vfStepperKachelAktiv {
  background: var(--vf-primary-subtle);
  border-color: var(--vf-primary);
}
/* Der Hover muss auf der GANZEN Kachel liegen und deutlich sein - der
   Zeiger allein sagt "klickbar", die Flaeche sagt "diese hier". Als
   Unterstrich statt Rahmenfarbe, weil die Innenraender zwischen gewaehlten
   Kacheln entfallen und ein wandernder Rahmen dort springen wuerde. Steht
   NACH der Aktiv-Regel, damit eine gewaehlte Kachel beim Zeigen nicht die
   Fuellung verliert. */
.vfStudioStepper .vfStepperKachel:hover {
  background: var(--vf-bg);
  box-shadow: inset 0 -2px 0 var(--vf-primary);
}
.vfStudioStepper .vfStepperKachelAktiv:hover { background: var(--vf-primary-subtle); }
/* Zwischen zwei gewaehlten Kacheln keine Innenlinie: der Bereich soll als
   EIN Block lesbar sein, nicht als drei Kaestchen nebeneinander. Die frueher
   hier stehende Regel (`.Aktiv + .Aktiv { border-left-width: 0 }`) war ein
   No-Op - die Kacheln haben ohnehin keinen linken Rand, die Trennlinie ist
   der RECHTE Rand der linken Kachel. Im Browser nachgemessen und Pixel fuer
   Pixel gegengeprueft (12.09.2026). Faerben statt entfernen, damit die
   Spaltenbreite sich beim Waehlen nicht um 1 px verschiebt. */
.vfStudioStepper .vfStepperKachelAktiv:has(+ .vfStepperKachelAktiv) {
  border-right-color: var(--vf-primary-subtle);
}
/* Auch hier der Vorfahre statt !important: die Textfarben von sap.m.Text
   kommen aus dem Theme und wuerden bei (0,1,0) gewinnen. */
.vfStudioStepper .vfStepperRolle {
  font-size: 11px;
  font-weight: 700;
  color: var(--vf-neutral-400, #b5bdc6);
}
.vfStudioStepper .vfStepperRolleAktiv { color: var(--vf-primary); }
.vfStudioStepper .vfStepperName { font-size: 13px; font-weight: 700; color: var(--vf-text); }
.vfStudioStepper .vfStepperUnter { font-size: 12px; color: var(--vf-text-muted); }

/* Code-Panes: Kopfzeile mit Titel, Mass und "Kopieren"; darunter der Editor
   ueber die Resthoehe. */
.vfStudioPanes {
  flex: 1 1 auto;
  min-height: 0;
  align-items: stretch;
}
.vfStudioPane {
  flex: 1 1 50%;
  min-width: 0;
  min-height: 0;
  border-left: 1px solid var(--vf-border);
}
.vfStudioPane:first-child { border-left: 0; }
.vfStudioPaneKopf {
  padding: var(--vf-space-2) var(--vf-space-4);
  border-bottom: 1px solid var(--vf-border);
}
.vfStudioPaneTitel { font-size: 13px; font-weight: 600; color: var(--vf-text); }
.vfStudioPaneMeta { font-size: 12px; color: var(--vf-text-muted); }
.vfStudioUngespeichert {
  font-size: 12px;
  color: var(--vf-warning);
  margin-left: var(--vf-space-2);
}
/* Die Fehlerzahl ist anklickbar - das muss man ihr ansehen. */
.vfKennSchlecht { cursor: pointer; text-decoration: underline; }
.vfStudioCodeHaupt { padding: var(--vf-space-3) 0; }

/* Die Hoehenkette bis zum Editor. UI5 gibt dem Tab-Inhalt von sich aus keine
   Hoehe; ein CodeEditor mit height:100% in einem Elternteil ohne bestimmte
   Hoehe rechnet mit 0 und zeichnet nichts. Jedes Glied dieser Kette ist
   deshalb noetig - im Browser nachgestellt, nicht geraten. */
/* Zwischen Dialog-Abschnitt und Inhalt sitzt ein .sapMDialogScroll mit
   `display: inline-block` - das waechst nur mit seinem Inhalt und ist damit
   das Glied, an dem die Hoehe abriss (im Browser gemessen: 431px statt 646).
   Es steht in keiner Dokumentation; man findet es, indem man die Kette
   durchgeht. */
.vfStudioDialog .sapMDialogScroll {
  display: block;
  height: 100%;
}
.vfStudioDialog .sapMDialogScrollCont { height: 100%; padding: 0; }
/* Der Reiterkopf gehoert NICHT zum Inhalt. Ihn mitzurechnen (allen drei
   Ebenen schlicht height:100% zu geben) schob die Seitenleiste um genau
   seine Hoehe unter den Dialogrand - der Kennzahlen-Block wurde angeschnitten
   (im Browser gemessen: 60px zu tief). Also der Tab-Bar eine Spalte, und der
   Inhalt nimmt, was nach dem Kopf uebrig ist. */
.vfStudioDialog .sapMITB {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.vfStudioDialog .sapMITBContainerContent {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
}
.vfStudioDialog .sapMITBContent {
  height: 100%;
  /* Ohne diesen Innenabstand fluchten Seitenleiste und Panes mit dem
     Dialogrand - so will es der Entwurf (Panes randlos). */
  padding: 0;
}
.vfStudioDialog .sapMITBContent > .sapMFlexBox { height: 100%; }
/* Der Editor selbst ist das Flex-Kind (renderType "Bare" im Controller) -
   UI5s .sapMFlexItem-Huelle bekaeme sonst die Hoehe und der Editor 0. Die
   UI5-Klasse heisst .sapCEd, nicht .sapUiCodeEditor. */
.vfStudioPane > .sapCEd,
.vfStudioCodeHaupt > .sapCEd {
  flex: 1 1 auto;
  min-height: 0;
  height: auto !important;
}
.vfStudioFormatBox { gap: var(--vf-space-1); }
.vfStudioFormatBox .sapMSlt { width: 100%; }

/* Pfadleiste im Server-Verzeichnis-Browser (Value-Help der Verzeichnis-Felder). */
.vfDirBrowseBar {
  gap: var(--vf-space-2);
  padding: var(--vf-space-3);
  border-bottom: 1px solid var(--vf-border);
}
/* Breadcrumb (Stefan, 2026-07-13): jedes Segment ein Link außer dem
   letzten (aktuelles Verzeichnis, reiner Text) - nur die Text-Kinder
   (Trenner "/" + letztes Segment) bekommen die gedämpfte Farbe, Links
   behalten ihre normale Link-Farbe. */
.vfDirBrowsePath {
  flex-wrap: wrap;
}
.vfDirBrowsePath > .sapMText {
  color: var(--vf-text-secondary);
}

/* ---- Rechts-Drawer (model/drawer.js) ------------------------------------ */
.vfDrawerScrim {
  position: fixed;
  inset: 0;
  background: rgba(23, 26, 34, 0.32);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  /* z-index bewusst NIEDRIG (unter UI5s Popup-Bereich, der bei ~10 startet):
     so erscheinen Select-Dropdowns/DatePicker/MessageBox IM bzw. ÜBER dem
     Drawer statt dahinter. Über dem App-Inhalt (z-index auto) liegt der Drawer
     trotzdem. Nebeneffekt: eine modale MessageBox blockt den Drawer jetzt
     korrekt (ihr Blocklayer liegt darüber). */
  z-index: 8;
}
#vfDrawerHost.vfDrawerOpen .vfDrawerScrim {
  opacity: 1;
  pointer-events: auto;
}
.vfDrawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: 440px;
  max-width: 92vw;
  box-sizing: border-box;
  padding: var(--vf-space-7);
  overflow-y: auto;
  /* !important: .sapMFlexBoxBGTransparent-Falle (VBox ohne backgroundDesign). */
  background: var(--vf-surface) !important;
  box-shadow: var(--vf-shadow-lg);
  transform: translateX(100%);
  transition: transform 0.25s ease;
  z-index: 9;
}
#vfDrawerHost.vfDrawerOpen .vfDrawer {
  transform: translateX(0);
}
.vfDrawerHeader {
  margin-bottom: var(--vf-space-6);
  /* Platz für den absolut positionierten Close-Button (unten) reservieren,
     sonst läuft ein langer Titel/Untertitel unter ihm durch. */
  padding-right: var(--vf-space-10);
  /* UI5 setzt auf jede sap.m.HBox/VBox generell position:relative (eigene
     interne Zwecke) - das würde den Close-Button (s.u.) relativ zu DIESER
     Zeile statt zum ganzen Drawer positionieren. !important nötig, s. dort. */
  position: static !important;
}
/* UI5 wrappt außerdem jedes Flexbox-Kind einzeln in einen eigenen
   position:relative-Div (.sapMFlexItemAlignAuto) - der direkte Wrapper um
   den Close-Button muss ebenso neutralisiert werden, sonst positioniert sich
   der Button relativ zu diesem winzigen Wrapper statt zum Drawer. Scoped auf
   .vfDrawerHeader, um keine anderen Flexbox-Wrapper in der App zu treffen. */
.vfDrawerHeader > div:has(> .vfDrawerClose) {
  position: static !important;
}
.vfDrawerClose {
  /* Oben rechts bündig zur Drawer-Ecke statt in der Header-Zeile zentriert
     (Stefan, 2026-07-27) - .vfDrawer ist position:fixed und damit (nach den
     beiden Overrides oben) der nächste Containing Block. !important nötig:
     UI5s .sapMBtnBase setzt selbst position:relative, gleiche Spezifität,
     aber später im Quellcode injiziert (project_vflow_ui5_theming_quirks). */
  position: absolute !important;
  top: var(--vf-space-3) !important;
  right: var(--vf-space-3) !important;
  margin: 0 !important;
}
.vfDrawerFooter {
  gap: var(--vf-space-2);
  margin-top: var(--vf-space-7);
}

/* Rollen-Auswahl (Users New/Edit): Zeilen als abgesetzte Cards mit etwas
   Abstand statt aneinanderklebender Listenzeilen. */
.vfRoleList .sapMLIB {
  margin-bottom: var(--vf-space-2);
  border-radius: var(--vf-radius-sm);
}
.vfRoleList .sapMLIB:last-child {
  margin-bottom: 0;
}

/* Flow-Freigabe (Technical Users): bei vielen Flows die Checkbox-Liste in einen
   eigenen, scrollbaren Bereich fassen, damit Credentials/Settings darunter
   erreichbar bleiben statt endlos nach unten geschoben zu werden. */
.vfFlowAccessList {
  max-height: 15rem;
  overflow-y: auto;
}

/* Inbound-Zugangsdaten (Systems > Zugriff): einmalig sichtbares Secret + Liste. */
.vfSecretBox {
  gap: var(--vf-space-2);
  padding: var(--vf-space-4);
  border: 1px solid var(--vf-brand-200);
  border-radius: var(--vf-radius-md);
  /* !important: .sapMFlexBoxBGTransparent-Falle. */
  background: var(--vf-brand-50) !important;
  margin-bottom: var(--vf-space-4);
}
.vfSecretTitle {
  font-weight: var(--vf-fw-semibold);
}
.vfSecretValue {
  word-break: break-all;
  font-size: var(--vf-fs-sm) !important;
  color: var(--vf-text) !important;
}
.vfCredRow {
  padding: var(--vf-space-2) 0;
}
.vfCredTitle {
  font-weight: var(--vf-fw-medium);
}
/* Gefahr-Aktion (z. B. Technical User löschen) - roter Transparent-Button. */
.vfDeleteButton .sapMBtnContent,
.vfDeleteButton .sapUiIcon {
  color: var(--vf-error) !important;
}

/* Kalter Start (App.controller.js#_showColdStartCover): blendet die
   ToolPage-Shell (Sidebar mit allen Menüpunkten) beim allerersten,
   noch nie erfolgreich eingeloggten Aufruf aus - sonst wirkt die
   Login-Karte, als läge schon eine aktive Session dahinter. z-index
   niedrig genug, um unter UI5s Popup-Bereich (~10, siehe .vfDrawer) zu
   bleiben, aber über dem normalen Seiteninhalt (z-index auto). */
.vfColdStartCover {
  position: fixed;
  inset: 0;
  background: var(--vf-bg);
  z-index: 2;
}

/* Testlizenz abgelaufen (App.controller.js#_showLicenseExpiredCover,
   docs/architecture/licensing.md Abschnitt 3): gleiche Technik/z-index wie
   .vfColdStartCover, ersetzt aber die normale Navigation nach dem Login
   durch einen erklärenden Hinweis statt sie nur zu verstecken. */
.vfLicenseExpiredCover {
  position: fixed;
  inset: 0;
  background: var(--vf-bg);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
}
.vfLicenseExpiredCard {
  max-width: 420px;
  padding: var(--vf-space-8);
  background: var(--vf-surface);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-md);
  text-align: center;
}
.vfLicenseExpiredIcon {
  width: 48px;
  height: 48px;
  margin: 0 auto 16px;
  border-radius: 50%;
  background: var(--vf-warning-bg);
}
.vfLicenseExpiredIcon::before {
  content: "!";
  display: block;
  line-height: 48px;
  font-family: var(--vf-font-sans);
  font-weight: var(--vf-fw-semibold);
  font-size: 22px;
  color: var(--vf-warning);
}
.vfLicenseExpiredCard h1 {
  margin: 0 0 8px;
  font-family: var(--vf-font-sans);
  font-size: 18px;
  font-weight: var(--vf-fw-semibold);
  color: var(--vf-text);
}
.vfLicenseExpiredCard p {
  margin: 0 0 20px;
  font-family: var(--vf-font-sans);
  font-size: 14px;
  color: var(--vf-text-secondary);
}
.vfLicenseExpiredLogout {
  font-family: var(--vf-font-sans);
  font-size: 14px;
  font-weight: var(--vf-fw-medium);
  padding: 8px 20px;
  border-radius: var(--vf-radius-sm);
  border: 1px solid var(--vf-border-strong);
  background: var(--vf-surface);
  color: var(--vf-text);
  cursor: pointer;
}
.vfLicenseExpiredLogout:hover {
  background: var(--vf-bg);
}

/* Karenzzeit-Sperre bei nie lizenzierter Instanz (App.controller.js#
   _showLicenseLockedCover, Stefan 2026-08-04, licensing.md Abschnitt 3
   Nachtrag) - gleiche Karte wie .vfLicenseExpiredCard, zusätzlich ein
   Eingabefeld + Aktivieren-Button, da dieser Fall (anders als eine
   abgelaufene Testlizenz) per Selbstbedienung behebbar ist. */
.vfLicenseLockedForm {
  display: flex;
  flex-direction: column;
  gap: var(--vf-space-2);
  margin-bottom: var(--vf-space-4);
}
.vfLicenseLockedInput {
  font-family: var(--vf-font-mono);
  font-size: 13px;
  width: 100%;
  min-height: 72px;
  padding: 8px 10px;
  border-radius: var(--vf-radius-sm);
  border: 1px solid var(--vf-border-strong);
  background: var(--vf-bg);
  color: var(--vf-text);
  resize: vertical;
  box-sizing: border-box;
}
.vfLicenseLockedInput:focus {
  outline: none;
  border-color: var(--vf-primary);
  box-shadow: var(--vf-shadow-focus);
}
.vfLicenseLockedError {
  font-family: var(--vf-font-sans);
  font-size: 13px;
  color: var(--vf-error);
  text-align: left;
  min-height: 18px;
}
.vfLicenseLockedActivate {
  font-family: var(--vf-font-sans);
  font-size: 14px;
  font-weight: var(--vf-fw-medium);
  padding: 8px 20px;
  border-radius: var(--vf-radius-sm);
  border: none;
  background: var(--vf-primary);
  color: #fff;
  cursor: pointer;
}
.vfLicenseLockedActivate:hover {
  opacity: 0.92;
}
.vfLicenseLockedActions {
  display: flex;
  gap: var(--vf-space-2);
  justify-content: center;
}

/* ---- Login-Karte (App.controller.js#_showLogin) ------------------------- */
.vfLoginDialog .sapMDialogScrollCont,
.vfLoginDialog .sapMDialogScroll,
.vfLoginDialog .sapMDialogSection {
  padding: 0 !important;
}
.vfLoginCard {
  box-sizing: border-box;
  width: 100%;
  padding: var(--vf-space-8) var(--vf-space-7) var(--vf-space-6);
  gap: var(--vf-space-5);
}
.vfLoginBrand {
  align-items: center;
  gap: var(--vf-space-1);
  margin-bottom: var(--vf-space-2);
}
.vfLoginLogo {
  width: 56px;
  height: 56px;
  align-items: center;
  justify-content: center;
  border-radius: var(--vf-radius-lg);
  /* !important: sap.m.VBox bekommt sonst UI5s .sapMFlexBoxBGTransparent
     (background:transparent), nach dem App-CSS injiziert - das Marken-Quadrat
     bliebe unsichtbar (dokumentierte Falle in project-vflow-ui5-theming-quirks). */
  background: var(--vf-primary) !important;
  margin-bottom: var(--vf-space-3);
}
.vfLoginLogoIcon {
  color: #fff !important;
  font-size: 26px !important;
}
.vfLoginWordmark {
  text-align: center;
  font-size: var(--vf-fs-h1) !important;
  font-weight: var(--vf-fw-semibold) !important;
  letter-spacing: 0.02em;
  color: var(--vf-text) !important;
}
.vfLoginSubtitle {
  text-align: center;
  color: var(--vf-text-secondary) !important;
}
.vfLoginFields {
  gap: var(--vf-space-2);
}
.vfLoginFieldLabel {
  margin-top: var(--vf-space-4);
  font-weight: var(--vf-fw-semibold);
}
.vfLoginFields > .vfLoginFieldLabel:first-child {
  margin-top: 0;
}
.vfLoginTagline {
  margin-top: var(--vf-space-2);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  /* !important: gleiche .sapMText-Laufzeit-Übersteuerung wie an anderen Stellen. */
  font-size: var(--vf-fs-caption) !important;
  font-weight: var(--vf-fw-semibold) !important;
  color: var(--vf-primary) !important;
}

/* Breadcrumb-Trenner im Flow-Editor-Kopf ("Flows / {Flow-Name}"). */
.vfBreadcrumbSeparator {
  color: var(--vf-text-muted);
  padding: 0 var(--vf-space-2);
}

/* Kopfbereich des Flow Editors: Innenabstand statt Außenabstand auf der
   Seite selbst, damit der Splitter darunter randlos bis zur Sidebar-
   Trennlinie geht (kein Bruch im Trennbalken). */
.vfEditorHeader {
  padding: var(--vf-space-6) var(--vf-space-6) var(--vf-space-5);
  /* !important: UI5 setzt auf jede VBox ohne explizites "background"-Design
     die eigene Klasse .sapMFlexBoxBGTransparent (background-color:
     transparent), geladen nach vflow.css - gleiche Falle wie bei den
     Emphasized-Button-Farben, siehe project_vflow_ui5_theming_quirks. */
  background: var(--vf-surface) !important;
  border-bottom: 1px solid var(--vf-border);
  /* Frozen header (Stefan-Review 2026-07-15): bleibt beim Scrollen der
     sap.m.Page sichtbar, damit "Speichern" ohne Hochscrollen erreichbar
     bleibt. Greift nur, wenn der Kopfbereich selbst so hoch wird, dass die
     Page überhaupt scrollt - der Splitter darunter scrollt ohnehin intern.
     !important: UI5s Basis-CSS setzt auf .sapMFlexBox "position: relative"
     und lädt nach vflow.css - gleiche Falle wie beim Hintergrund oben. */
  position: sticky !important;
  top: 0 !important;
  z-index: 2;
}

/* Trennlinie zwischen dem Kopf (Breadcrumb/Titel/Version/Verarbeitung) und
   der Bearbeitungssperre/dem Canvas im Flow-Editor. */
.vfHeaderDivider {
  height: 1px;
  /* !important: UI5 setzt auf jede VBox ohne explizites "background"-Design
     die eigene Klasse .sapMFlexBoxBGTransparent (background-color:
     transparent), geladen nach vflow.css - gleiche Falle wie bei
     .vfEditorHeader oben, siehe project_vflow_ui5_theming_quirks. */
  background: var(--vf-border) !important;
  margin: var(--vf-space-4) 0;
}

/* ---- Flow-Editor: Canvas + Bottom Property Panel per ziehbarem Trennbalken
   (sap.ui.layout.Splitter, orientation="Vertical") statt rechtem Drawer -
   wie in SAP Cloud Integration ("man kann es hoch und runter ziehen").
   flow-editor.md Abschnitt 5. Randlos (kein Border/Radius) - der
   Trennbalken soll ohne Unterbruch bis zur Sidebar durchgehen. ---- */
.vfEditorSplitter {
  border-top: 1px solid var(--vf-border);
  overflow: hidden;
  /* Statt der festen 620px aus der View: nimm, was das Fenster hergibt
     (Befund F1, 27.08.2026).

     Der Trennbalken teilt 60/40 zwischen Zeichenflaeche und
     Eigenschaften-Bereich. Bei fest 620px sind das 372px fuer die Kette - und
     ein sync- oder bridge-Flow braucht 385px, weil unter der Hinspur noch die
     RUECKSPUR liegt. Abgeschnitten wurde also ausgerechnet der Teil, an dem
     man arbeitet, wenn man das Response-Mapping anklickt.

     Zwei Aenderungen: die Untergrenze steigt von 620 auf 680 - 60 % davon
     sind rund 400 px und damit mehr als die 385, die eine Kette MIT Rueckspur
     braucht -, und darueber waechst die Flaeche mit dem Fenster. `max()`
     statt einer neuen festen Zahl, damit ein grosser Schirm auch mehr
     bekommt. Der Abzug deckt Kopfzeile, Titelzeile und Seitenrand ab.
     Ziehen bleibt moeglich; das hier ist nur der Ausgangspunkt. */
  height: max(680px, calc(100vh - 240px)) !important;
}

.vfBottomPanel {
  background: var(--vf-surface);
  height: 100%;
  overflow-y: auto;
}

.vfBottomPanel .sapMITB {
  background: transparent;
}

.vfBottomPanelPlaceholder {
  width: 100%;
  height: 100%;
  padding: var(--vf-space-7) var(--vf-space-5) var(--vf-space-5) var(--vf-space-7);
  align-items: flex-start;
  color: var(--vf-text-muted);
  font-size: var(--vf-fs-sm);
}

.vfBottomPanelPlaceholderIcon {
  font-size: 1.1rem;
  color: var(--vf-text-muted);
  margin-right: var(--vf-space-3);
}

/* Der Splitter-Trennbalken soll wie ein echter Drag-Handle aussehen, nicht
   wie eine zufällige graue Linie. */
.vfEditorSplitter > .sapUiLoSplitterBar {
  background: var(--vf-surface-sunk);
  border-top: 1px solid var(--vf-border);
  border-bottom: 1px solid var(--vf-border);
}

/* ==========================================================================
   Design-Refresh (Packages/PackageDetail/FlowEditor), angelehnt an ein von
   Stefan geteiltes Mockup - kein 1:1-Clone (UI5 begrenzt das), aber gleiche
   Richtung: Icon-Avatare, Metadata-Sidecards, Tabellen-Toolbars mit Counts,
   Pipeline-Karten mit Kicker-Label. Nur Elemente mit echten Daten dahinter -
   rein dekorative Mockup-Elemente ohne Backend-Gegenstück (Env-Badge,
   "Runtime healthy", User-Avatar) sind bewusst nicht übernommen.
   ========================================================================== */

/* ---- Entity-Icon-Avatar (Package-/Flow-Header) --------------------------- */
.vfEntityAvatar {
  width: 40px;
  height: 40px;
  border-radius: var(--vf-radius-md);
  /* !important: jede HBox ohne explizites backgroundDesign bekommt UI5s
     eigene .sapMFlexBoxBGTransparent-Klasse (background-color: transparent),
     nach vflow.css injiziert - gleiche Falle wie bei .vfEditorHeader, siehe
     project_vflow_ui5_theming_quirks. */
  background: var(--vf-primary) !important;
  color: var(--vf-neutral-0);
  align-items: center;
  justify-content: center;
  flex: none;
}

.vfEntityAvatar .sapUiIcon {
  color: var(--vf-neutral-0) !important;
}

/* ---- User-Avatar (Initialen statt Icon, z. B. Users-Tabelle) ------------- */
.vfUserAvatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--vf-primary) !important;
  color: var(--vf-neutral-0);
  align-items: center;
  justify-content: center;
  flex: none;
}

.vfUserAvatar .sapMText {
  color: var(--vf-neutral-0) !important;
  font-weight: var(--vf-fw-medium);
  font-size: var(--vf-fs-caption);
}

.vfUserAvatar .sapUiIcon {
  color: var(--vf-neutral-0) !important;
}

/* ---- Role-/Tag-Pill (Rolle, Credential-Typ etc., Users-/Credentials-Tabelle)
   Bewusst KEIN sap.m.ObjectStatus-Zustand (Success/Error/...) - diese sind
   laut Design-System nur für echten funktionalen Zustand reserviert (Monitoring
   etc.), eine Rolle/ein Credential-Typ ist kein Zustand. Eigenständige,
   neutral-brand-getönte Pille statt Zweckentfremdung der Status-Farben - gleiche
   ::before-Dot-Technik wie .sapMObjStatus oben, auf einem einzelnen Text-Control
   statt einer HBox+Kind-Element-Konstruktion (vermeidet die Flex-Item-Kollaps-
   Fallen, die bei mehrknotigen absolut positionierten Overlays aufgetreten sind,
   siehe project_vflow_ui5_theming_quirks). Name ist historisch (zuerst für Users
   gebaut), wird aber bewusst für jede nicht-funktionale Kategorisierungs-Pille
   wiederverwendet statt eine zweite, identische Klasse anzulegen. */
.vfRolePill {
  display: inline-flex;
  align-items: center;
  gap: var(--vf-space-2);
  background: var(--vf-primary-subtle);
  color: var(--vf-primary);
  border-radius: var(--vf-radius-pill);
  padding: 1px var(--vf-space-4) 1px var(--vf-space-3);
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-medium);
}

.vfRolePill::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--vf-primary);
  flex: none;
}

/* ---- Key-/ID-Badge (statt reinem mono-Text) ------------------------------ */
.vfKeyPill {
  font-family: var(--vf-font-mono) !important;
  font-size: var(--vf-fs-caption);
  color: var(--vf-text-secondary);
  background: var(--vf-surface-sunk);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-xs);
  padding: 1px var(--vf-space-3);
}

/* ---- Generische Card (Details-Card + Metadata-Sidecard teilen sich das) -- */
.vfCard {
  /* !important: UI5 setzt auf jede VBox/HBox eine eigene
     .sapMFlexBoxBGTransparent-Klasse (background-color: transparent), die
     nach vflow.css injiziert wird und sonst gewinnt - gleiche Falle wie bei
     .vfEditorHeader/.vfEntityAvatar. */
  background: var(--vf-surface) !important;
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-sm);
  padding: var(--vf-space-5);
  gap: var(--vf-space-3);
}

/* ---- Metadata-Sidecard (Package-Detail Overview, rechte Spalte) ---------- */
.vfMetadataCard {
  /* 340 statt 280 (Stefan, 2026-08-19): bei 280px brach eine Package-ID wie
     "valcofox_Solutions_AG" mitten im Wort um, obwohl rechts daneben Platz
     frei war. Die Breite ist bewusst fest und nicht `flex:1` - die Karte ist
     ein Beiwagen, kein zweiter Hauptbereich, und wuerde sonst auf einem
     breiten Schirm die halbe Zeile fuellen. */
  width: 360px;
  flex: none;
}

.vfMetadataCardTitle {
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-medium);
  color: var(--vf-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: var(--vf-space-2);
}

.vfMetadataRow {
  width: 100%;
  /* !important: UI5 setzt auf jede HBox eine eigene .sapMFlexBoxJustify*-/
     .sapMFlexBoxAlignItems*-Klasse (hier "Start"/"Stretch", je nach
     Default), die nach vflow.css injiziert wird und sonst gewinnt - gleiche
     Falle wie bei .vfEntityAvatar/.vfEditorHeader oben. */
  justify-content: space-between !important;
  align-items: center !important;
  padding: var(--vf-space-1) 0;
}

.vfMetadataRowLabel {
  color: var(--vf-text-secondary);
  font-size: var(--vf-fs-sm);
  /* Abstand zum Wert, falls dieser (langer mono-Pfad im Runtime-Drawer) dicht
     heranrückt. Das "auf einer Zeile halten" macht das Label-Control selbst via
     wrapping:false (Operation._metaRow) - CSS white-space würde von UI5s
     eigener .sapMText-Regel überschrieben (gleicher !important-Footgun). */
  margin-right: var(--vf-space-4);
}

.vfMetadataRowValue {
  font-family: var(--vf-font-mono) !important;
  font-size: var(--vf-fs-sm);
  color: var(--vf-text);
}

/* Ein langer Endpunkt-Pfad hat keine Leerzeichen und damit keine
   Bruchstelle - "/inbound/soap/OIS_BossardPurchaseOrderConfirmation" lief
   aus dem Runtime-Drawer heraus (Stefan, 22.09.2026).
   Zwei Dinge braucht es dafuer, und eines allein genuegt nicht:
   1. min-width:0 auf den Flex-Kindern. UI5 wickelt jedes HBox-Kind in ein
      .sapMFlexItem, und ein Flex-Item schrumpft von sich aus NICHT unter
      seine Inhaltsbreite (min-width:auto) - der Text zwingt die Zeile breit,
      bevor er ueberhaupt umbrechen koennte.
   2. overflow-wrap:anywhere auf dem Text, damit er mitten im Pfad umbricht.
   0,2,0 statt !important: .sapMText traegt eigene Regeln mit 0,1,0 und wird
   nach vflow.css injiziert - bei gleicher Spezifitaet gewinnt UI5
   (CLAUDE.md Abschnitt 4). Die Beschriftung bleibt einzeilig und schrumpft
   nicht mit. */
.vfMetadataRow .sapMFlexItem {
  min-width: 0;
}

.vfMetadataRow > .sapMFlexItem:first-child {
  flex: 0 0 auto;
}

.vfMetadataRow .vfMetadataRowValue {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ---- Runtime-Cockpit Detail-Drawer: Metadaten-Gruppen als abgesetzte Boxen
   (IDENTITY/ADDRESS/ACCESS/LIFECYCLE) - Rahmen statt Schatten (CLAUDE.md §5),
   Gruppentitel mit Hairline darunter. ------------------------------------- */
.vfDrawerSection {
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  padding: var(--vf-space-3) var(--vf-space-4) var(--vf-space-2);
  margin-bottom: var(--vf-space-3);
  background: var(--vf-surface);
}

.vfDrawerSectionTitle {
  /* Volle Boxbreite (Titel ohne wrapping:false, s. Operation._section), damit
     die Trennlinie durchläuft statt auf Wortbreite zu enden. */
  display: block !important;
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-semibold) !important;
  color: var(--vf-text-muted) !important;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-bottom: var(--vf-space-2);
  margin-bottom: var(--vf-space-1);
  border-bottom: 1px solid var(--vf-border);
}

/* ---- Runtime-Cockpit Detail-Drawer: Aktionsleiste am Ende des Inhalts
   (Pause/Resume, Undeploy, Im Editor ansehen) - abgesetzt durch eine dünne
   Trennlinie über den Buttons. --------------------------------------------- */
.vfDrawerActions {
  gap: var(--vf-space-2);
  margin-top: var(--vf-space-4);
  padding-top: var(--vf-space-4);
  border-top: 1px solid var(--vf-border);
}

/* ---- Tip-Callout (dezenter Hinweis, kein Fehler/Warnung - eigene, ruhige
   Farbe statt Status-Semantik, da CLAUDE.md Status-Farben nur für echten
   Laufzeit-/Lifecycle-Zustand reserviert). --------------------------------- */
.vfTipCallout {
  background: var(--vf-brand-50);
  border: 1px solid var(--vf-brand-200);
  border-radius: var(--vf-radius-md);
  padding: var(--vf-space-4) var(--vf-space-5);
  gap: var(--vf-space-1);
}

.vfTipCalloutTitle {
  font-weight: var(--vf-fw-medium);
  color: var(--vf-primary-active);
  font-size: var(--vf-fs-sm);
}

.vfTipCalloutText {
  color: var(--vf-text-secondary);
  font-size: var(--vf-fs-sm);
}

/* ---- Tabellen-Toolbar-Header ("Flows 6 total" + Filter + Aktion) --------- */
.vfTableToolbarTitle {
  font-weight: var(--vf-fw-semibold);
  font-size: var(--vf-fs-h3);
  color: var(--vf-text);
}

.vfTableToolbarCount {
  color: var(--vf-text-muted);
  font-size: var(--vf-fs-sm);
  font-weight: var(--vf-fw-regular);
  margin-left: var(--vf-space-2);
}

/* ---- Versions-Overflow-Badge ("v3 +2") ----------------------------------- */
.vfOverflowBadge {
  color: var(--vf-text-muted);
  font-size: var(--vf-fs-caption);
  margin-left: var(--vf-space-2);
}

/* ---- Flow-Editor Pipeline-Karten (Kicker-Label + zweizeiliger Button) ----
   Die ganze Karte soll klickbar sein und überall einen Pointer zeigen
   (Stefan: "auf der ganzen Box"), nicht nur der Button-Teil unterhalb des
   Kicker-Labels. Der Button trägt weiterhin den eigentlichen Klick-Handler
   (kein neues Control nötig) - er wird per position:absolute auf die volle
   Kartenfläche gelegt, das Kicker-Label liegt als rein dekorative,
   klick-durchlässige (pointer-events:none) Ebene darüber. Feste Kartenhöhe
   (statt auto), damit ein absolut positionierter Button eine wohldefinierte
   100%-Bezugsgröße hat. */
/* Flow-Kachel im SAP-Integration-Suite-Stil: Icon-Badge + Kicker oben, fetter
   Titel + gedämpfter Mono-Untertitel unten. Die Karte (sap.m.VBox) rendert mit
   renderType="Bare" (XML), sodass Kicker/Titel/Untertitel direkte Flex-Kinder
   sind - dadurch entfallen die früheren .sapMFlexItem-/absolute-Hacks: die
   Inhalte liegen im normalen Fluss, nur der Klick-Button ist ein transparentes
   Overlay über der ganzen Karte. */
.vfPipelineCard {
  position: relative;
  display: flex;
  flex-direction: column;
  width: var(--vf-pipeline-card-w);
  /* fixe Höhe für gleich hohe Kacheln in der Reihe; Titel/Untertitel werden
     per margin-top:auto an den unteren Rand geschoben, sodass sie bündig
     stehen, egal ob das Kicker-Label ein- oder zweizeilig umbricht.
     Als Token, weil .vfPipelineArrow dieselbe Höhe braucht, um die Linie auf
     Kartenmitte zu legen - die beiden dürfen nicht auseinanderlaufen. */
  height: var(--vf-pipeline-card-h);
  box-sizing: border-box;
  flex: none;
  padding: var(--vf-space-3);
  border: 1px solid var(--vf-border-strong);
  border-radius: var(--vf-radius-lg);
  background: var(--vf-surface);
}

.vfPipelineCardKicker {
  align-items: center;
  gap: var(--vf-space-2);
}

/* Icon im soften, violett getönten Rounded-Square (wie in der Vorlage). */
.vfCardIconBadge {
  box-sizing: border-box;
  width: 24px !important;
  height: 24px !important;
  line-height: 24px !important;
  margin: 0 !important;
  border-radius: var(--vf-radius-sm);
  background: var(--vf-brand-100);
  color: var(--vf-primary) !important;
  font-size: 13px !important;
  text-align: center;
  flex: none;
}

.vfPipelineCardKickerText {
  font-size: 10px;
  font-weight: var(--vf-fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--vf-text-muted) !important;
  line-height: 1.2;
}

/* Titel: fett, an den unteren Kartenrand geschoben (margin-top:auto), eine
   Zeile mit Ellipsis. */
.vfPipelineCardTitle {
  margin-top: auto;
  padding-top: var(--vf-space-2);
  display: block;
  max-width: 100%;
  /* Direktes Flex-Kind von .vfPipelineCard (renderType="Bare") - ohne
     min-width:0 bleibt Flexbox' Default min-width:auto aktiv, das die
     Ellipsis-Regeln unten wirkungslos macht (der Text bleibt auf seiner
     vollen intrinsischen Breite und läuft über die Karte hinaus, statt zu
     kürzen - Stefan-Review 2026-07-27, lange File-Pfade liefen über die
     Karte). */
  min-width: 0;
  font-size: var(--vf-fs-body) !important;
  font-weight: var(--vf-fw-semibold) !important;
  color: var(--vf-text) !important;
  /* !important: UI5s .sapMText setzt selbst white-space:pre-line (spätere
     Quellreihenfolge, gleiche Spezifität - dieselbe Falle wie an anderer
     Stelle in project_vflow_ui5_theming_quirks dokumentiert), das die
     Ein-Zeile-Ellipsis sonst wirkungslos macht (Text umbricht/wächst über
     die Karte, statt zu kürzen). */
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}

.vfPipelineCardSubtitle {
  display: block;
  max-width: 100%;
  /* Gleicher Flex-Item-min-width-Trap wie .vfPipelineCardTitle oben. */
  min-width: 0;
  font-size: var(--vf-fs-caption) !important;
  color: var(--vf-text-muted) !important;
  /* !important nötig, s. Kommentar bei .vfPipelineCardTitle oben. */
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}

/* Transparentes Klick-Overlay über der ganzen Karte (trägt den Press-Handler).
   !important auf Größe/Position: UI5s .sapMBtn bringt eigene feste Maße mit. */
.vfPipelineCard .vfPipelineCardButton {
  position: absolute !important;
  top: 0 !important;
  left: 0 !important;
  width: 100% !important;
  height: 100% !important;
  min-width: 0 !important;
}
.vfPipelineCard .vfPipelineCardButton .sapMBtnInner {
  border: none !important;
  background: transparent !important;
  box-shadow: none !important;
  width: 100% !important;
  height: 100% !important;
  cursor: pointer;
}

/* Das Klick-Overlay zeichnet KEINEN eigenen Fokusrahmen - sonst lag der
   Button-Fokusring (leicht eingerückt) über dem Kartenrahmen und es sah aus
   wie zwei überlappende Rahmen. Die Auswahl zeigt stattdessen die Karte selbst
   (:focus-within unten) als einen sauberen Rahmen. UI5 zeichnet den Fokusring
   als ::before UND ::after am .sapMBtnInner (je nach Build/Zustand) - beide
   unterdrücken, sonst bleibt bei :focus-visible ein zweiter 2px-Rahmen sichtbar
   (Stefan-Review 2026-07-10: nach Hard-Reload war ::before noch aktiv). */
.vfPipelineCard .vfPipelineCardButton,
.vfPipelineCard .vfPipelineCardButton:focus,
.vfPipelineCard .vfPipelineCardButton:focus-visible {
  outline: none !important;
}
.vfPipelineCard .vfPipelineCardButton .sapMBtnInner::before,
.vfPipelineCard .vfPipelineCardButton .sapMBtnInner::after {
  content: none !important;
  display: none !important;
  border: none !important;
}

/* Hover und Auswahl: EIN violetter Rahmen. Bei Auswahl zusätzlich ein weicher,
   heller Halo + zarte Flächentönung - der frühere harte 3px-Fokusring
   (--vf-shadow-focus, 30% Deckkraft direkt am Rahmen) las sich durch die
   Rundung wie ein zweiter Rahmen (Stefan-Review 2026-07-10). Jetzt ein
   verwaschener Glow (mit Blur, kein harter Rand). */
.vfPipelineCard:hover,
.vfPipelineCard:focus-within {
  border-color: var(--vf-primary);
  cursor: pointer;
}
.vfPipelineCard:focus-within {
  background: var(--vf-brand-50);
  box-shadow: 0 2px 10px rgba(91, 69, 224, 0.18);
}

/* ---- Legende oben rechts im Canvas ("● message flow · 2 Zweige") -------- */
.vfPipelineLegend {
  color: var(--vf-text-muted);
  font-size: var(--vf-fs-caption);
  gap: var(--vf-space-2);
  align-items: center;
}

.vfPipelineLegendDot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--vf-primary);
  flex: none;
}

/* ---- Bedingungs-Pill pro Zweig (ersetzt die eigene Condition-Box in der
   Zweig-Reihe - "Zweig 1 · Bedingung (Standard)"). Wie bei .vfPipelineBox
   oben: der Button rendert seinen eigentlichen Rahmen/Hintergrund auf einem
   inneren .sapMBtnInner-Element, nicht auf der Klasse selbst. ------------- */
.vfBranchConditionPill .sapMBtnInner {
  background: var(--vf-brand-50) !important;
  color: var(--vf-primary-active) !important;
  border: 1px solid var(--vf-brand-200) !important;
  border-radius: var(--vf-radius-pill) !important;
  padding: 1px var(--vf-space-4) !important;
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-medium);
  height: auto !important;
}

.vfBranchConditionPill:hover .sapMBtnInner {
  border-color: var(--vf-primary) !important;
}

/* Drop-Zone im "New Document"-Modal: gestrichelte Fläche zum Ziehen/Auswählen
   einer Datei. .vfDropZoneActive hebt beim Drüberziehen hervor. */
.vfDropZone {
  border: 2px dashed var(--vf-border-strong);
  border-radius: var(--vf-radius-md);
  padding: var(--vf-space-6, 24px) var(--vf-space-4, 16px);
  background: var(--vf-bg);
}
.vfDropZoneActive {
  border-color: var(--vf-primary);
  background: var(--vf-primary-subtle);
}
.vfDropZone .vfDropZoneIcon {
  color: var(--vf-text-muted);
}

/* ---- Benutzer-Footer unten in der Side-Navigation (Name + Rolle + Abmelden).
   Body-level position:fixed, links an die Sidenav-Spalte ausgerichtet - stört
   so das UI5-Flex-Layout der Aside nicht. z-index unter den UI5-Popups (~10),
   aber über dem Inhalt. Breite fest verdrahtet (256px, sap.tnt.ToolPage-
   Standardbreite in dieser Density/Theme) statt live an der Sidenav gemessen
   (Stefan-Review 2026-07-15, onToggleSideNav) - eine Live-Messung direkt nach
   dem Klick lag noch mitten in der Breiten-Animation der Sidenav und blieb
   bei schnellen Klicks manchmal auf der alten Breite hängen. transition
   animiert stattdessen selbst mit, synchron zur Klasse .vfUserFooterCollapsed
   (App.controller.js#_alignUserFooter, reines Klassen-Toggle, kein Messen). */
/* Die Navigation muss ueber dem Footer enden und von dort an SCROLLEN.
   Befund vom 2026-08-26 (Stefan: "wenn alles aufgeklappt ist, komme ich an die
   unteren Punkte nicht dran"): die Liste `ul.sapTntNL` traegt zwar
   `overflow-y: auto`, war aber genau so hoch wie ihr Inhalt - also gab es
   nichts zu scrollen. Sie ragte einfach unter den fixierten Footer und wurde
   dort verdeckt. Gemessen: Liste bis 758 px, Footer ab 720 px, letzter
   Eintrag "Ueber vFlow" damit unerreichbar.

   Der Deckel auf die Hoehe macht beides auf einmal: er haelt den Footer frei
   UND setzt das vorhandene `overflow-y: auto` erst in Kraft. Deshalb hier eine
   Zeile statt eines eigenen Scroll-Containers - das Scrollen konnte UI5
   schon, es fehlte nur die Begrenzung. */
.sapTntToolPageAside ul.sapTntNL {
  max-height: calc(100% - var(--vf-shell-userfooter));
}

.vfUserFooter {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 256px;
  /* Feste Hoehe, weil die Navigation oben genau diesen Wert freihaelt. Ohne
     die Kopplung wuechse der Footer bei groesserer Schrift ueber den
     reservierten Platz hinaus und verdeckte wieder Eintraege. */
  min-height: var(--vf-shell-userfooter);
  transition: width 0.2s ease;
  z-index: 5;
  box-sizing: border-box;
  padding: var(--vf-space-3) var(--vf-space-4);
  border-top: 1px solid var(--vf-border);
  /* !important: .sapMFlexBoxBGTransparent-Falle auf HBox. */
  background: var(--vf-surface) !important;
}
.vfUserFooterId {
  gap: var(--vf-space-3);
  cursor: pointer;
  min-width: 0;
  /* Stefan-Review 2026-07-17: vorher nur Avatar+Text klickbar, der Rest der
     Zeile bis zum Abmelden-Icon war tote Fläche (justify-content:SpaceBetween
     am Elternelement lässt sonst eine Lücke, die zu keinem der beiden Items
     gehört). flex:1 zieht die klickbare Fläche bis direkt vor das Icon. */
  flex: 1 1 auto;
  border-radius: var(--vf-radius-sm);
  padding: var(--vf-space-1) var(--vf-space-2);
  margin: calc(var(--vf-space-1) * -1) calc(var(--vf-space-2) * -1);
  transition: background 0.1s ease;
}
.vfUserFooterId:hover {
  background: var(--vf-brand-50);
}
.vfUserFooterMeta {
  min-width: 0;
}
.vfUserFooterAvatar {
  display: inline-block;
  flex: none;
  width: 32px;
  height: 32px;
  line-height: 32px;
  text-align: center;
  border-radius: var(--vf-radius-sm);
  background: var(--vf-primary) !important;
  color: #fff !important;
  font-weight: var(--vf-fw-semibold) !important;
}
.vfUserFooterName {
  font-weight: var(--vf-fw-semibold) !important;
  color: var(--vf-text) !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vfUserFooterRole {
  font-size: var(--vf-fs-caption) !important;
  color: var(--vf-text-muted) !important;
}

/* Eingeklappte Sidebar (onToggleSideNav, Stefan-Wunsch 2026-07-15): bei
   ~65px Breite ist kein Platz für Name/Rolle nebeneinander mit Avatar +
   Abmelden-Icon - Name/Rolle ausblenden, Avatar + Abmelden übereinander
   stapeln statt nebeneinander. !important: die HBox-Properties
   (justifyContent/alignItems) rendern als sapMFlexJustify…-/-Align…-Klassen,
   die UI5-Bibliotheks-CSS lädt nach vflow.css (gleiche Falle wie an anderen
   Stellen, siehe project_vflow_ui5_theming_quirks). */
.vfUserFooter.vfUserFooterCollapsed {
  width: 65px;
  flex-direction: column !important;
  justify-content: center !important;
  align-items: center !important;
  gap: var(--vf-space-2);
  padding: var(--vf-space-3) var(--vf-space-2);
}
.vfUserFooter.vfUserFooterCollapsed .vfUserFooterMeta {
  display: none;
}
.vfUserFooter.vfUserFooterCollapsed .vfUserFooterId {
  justify-content: center !important;
  /* Collapsed ist eine Spalte (Avatar über Logout-Icon, Meta ausgeblendet) -
     hier gibt es keine tote Fläche zu füllen; flex:1 aus dem expanded State
     würde stattdessen die Zeile über die volle Höhe strecken. */
  flex: none;
}

/* Profil-Seite: großer Marken-Avatar mit Initiale. */
/* Zentrierung per Flexbox statt line-height: UI5 setzt auf .sapMText ein
   eigenes line-height: normal, das gegen die Zeilenhoehe hier gewinnt - das
   Kuerzel klebte an der oberen linken Ecke des Kastens. Mit einem Buchstaben
   fiel das kaum auf, mit den zwei Buchstaben der neuen Initialen (Vor- und
   Nachname) sofort. Gleiches Mittel fuer den Avatar in der Seitenleiste,
   derselbe Bau. */
.vfProfileAvatar,
.vfUserFooterAvatar {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
}
.vfProfileAvatar {
  display: inline-block;
  width: 48px;
  height: 48px;
  line-height: 48px;
  text-align: center;
  border-radius: var(--vf-radius-md);
  background: var(--vf-primary) !important;
  color: #fff !important;
  font-size: 18px !important;
  font-weight: var(--vf-fw-semibold) !important;
}

/* ---- Test-Send: zweispaltiges Layout (Request links / Ergebnis rechts),
   je eine .vfCard - gleiche Karten-Bausteine wie Package-Detail/Runtime-
   Drawer (CLAUDE.md §8: bestehende Muster wiederverwenden). ---------------- */
.vfTestSendLayout {
  gap: var(--vf-space-5);
  /* !important: UI5 setzt auf jede HBox eine eigene
     .sapMFlexBoxAlignItemsStretch-Klasse, die nach vflow.css injiziert wird
     und sonst gewinnt - gleiche Falle wie bei .vfMetadataRow/.vfCard oben. */
  align-items: flex-start !important;
}
.vfTestSendRequestCard {
  width: 55%;
}
.vfTestSendResultCard {
  width: 45%;
}
/* Rechte Spalte: Ergebnis und darunter - nur bei einer Antwort - die
   Antwort-Karte (02.10.2026). */
.vfTestSendRightColumn {
  width: 45%;
  gap: var(--vf-space-5);
}
.vfTestSendAntwortStatus {
  margin-left: var(--vf-space-3);
  font-size: var(--vf-fs-sm);
  color: var(--vf-text-muted);
}

/* Ergebnis-Karte im Leerzustand: zentriertes Icon + Hinweistext, bis die
   erste Testnachricht gesendet wurde. */
.vfTestSendResultIdle {
  align-items: center;
  text-align: center;
  gap: var(--vf-space-2);
  padding: var(--vf-space-6) var(--vf-space-4);
}
.vfTestSendResultIdleIcon {
  font-size: 32px !important;
  color: var(--vf-text-muted) !important;
}
.vfTestSendResultIdleTitle {
  font-weight: var(--vf-fw-medium);
  color: var(--vf-text-secondary);
}
.vfTestSendResultIdleHint {
  font-size: var(--vf-fs-sm);
  color: var(--vf-text-muted);
}

/* sap.m.Dialog-Content-Innenabstand (Stefan-Review 2026-07-27, Baum-Editor):
   UI5s eigene "sapUiContentPadding"-Klasse existiert in diesem Theme-Build
   nicht (computed padding 0px trotz Klasse) - eigene Klasse statt dessen,
   gleicher Wert wie .vfDrawer. */
.vfDialogContentPadding {
  padding: var(--vf-space-7);
}

/* ---- Help-Seite: sap.ui.core.HTML mit vorgefertigtem DE/EN-Content
   (Help.controller.js läadt help/content-<lang>.html per fetch) - eigenes
   Layout statt UI5-Controls, weil der Inhalt (TOC + lange Screenshot-
   Sektionen) als reines HTML deutlich wartbarer ist. Zwei-Spalten-Layout
   wie das Design-System-Dokument (docs/design/vFlow-Design-System.dc.html):
   sticky TOC links, scrollender Inhalt rechts. */
.vfHelpCard {
  max-width: var(--vf-content-max);
  margin: 0 auto;
}
.vfHelpLayout {
  display: flex;
  align-items: flex-start;
  gap: var(--vf-space-8);
}
.vfHelpToc {
  position: sticky;
  top: var(--vf-space-3);
  flex: 0 0 200px;
  width: 200px;
  display: flex;
  flex-direction: column;
  gap: var(--vf-space-1);
  border-right: 1px solid var(--vf-border);
  padding-right: var(--vf-space-5);
  align-self: flex-start;
}
.vfHelpTocGroup {
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-medium);
  color: var(--vf-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: var(--vf-space-5);
}
.vfHelpTocGroup:first-child {
  margin-top: 0;
}
/* Marke am Kapiteltitel eines Zusatzmoduls (help/index.html filtert die
   Kapitel nach Lizenz - wer das Kapitel sieht, hat das Modul; die Marke sagt
   ihm, warum ein Kollege ohne Lizenz es nicht findet). Neutral in Markenfarbe
   statt in einer Statusfarbe: es ist kein Zustand, sondern eine Herkunft. */
.vfHelpAddonTag {
  display: inline-block;
  vertical-align: middle;
  margin-left: var(--vf-space-3);
  padding: 2px var(--vf-space-2);
  border-radius: var(--vf-radius-sm);
  background: var(--vf-primary-subtle);
  color: var(--vf-primary);
  font-family: var(--vf-font-sans);
  font-size: var(--vf-fs-caption);
  font-weight: var(--vf-fw-medium);
  text-transform: none;
  letter-spacing: 0;
}
.vfHelpToc a {
  color: var(--vf-text-secondary);
  text-decoration: none;
  font-size: var(--vf-fs-sm);
  padding: var(--vf-space-1) 0;
}
.vfHelpToc a:hover {
  color: var(--vf-primary);
}
.vfHelpBody {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--vf-space-9);
}
.vfHelpBody h1 {
  font-size: var(--vf-fs-display);
  line-height: var(--vf-lh-display);
  font-weight: var(--vf-fw-semibold);
  margin: 0 0 var(--vf-space-2);
}
.vfHelpBody h2 {
  font-size: var(--vf-fs-h2);
  line-height: var(--vf-lh-h2);
  font-weight: var(--vf-fw-semibold);
  margin: 0 0 var(--vf-space-3);
  scroll-margin-top: var(--vf-space-5);
  padding-top: var(--vf-space-2);
  border-top: 1px solid var(--vf-border);
}
.vfHelpSection:first-of-type h2 {
  border-top: none;
  padding-top: 0;
}
.vfHelpBody h3 {
  font-size: var(--vf-fs-h3);
  line-height: var(--vf-lh-h3);
  font-weight: var(--vf-fw-semibold);
  margin: var(--vf-space-6) 0 var(--vf-space-2);
}
.vfHelpBody p {
  margin: 0 0 var(--vf-space-3);
  color: var(--vf-text);
  line-height: var(--vf-lh-body);
}
.vfHelpBody ul,
.vfHelpBody ol {
  margin: 0 0 var(--vf-space-3);
  padding-left: var(--vf-space-6);
  color: var(--vf-text);
  line-height: var(--vf-lh-body);
}
.vfHelpBody li {
  margin-bottom: var(--vf-space-2);
}
.vfHelpBody code {
  font-family: var(--vf-font-mono);
  font-size: var(--vf-fs-code);
  background: var(--vf-surface-sunk);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-xs);
  padding: 1px var(--vf-space-2);
}
.vfHelpLead {
  font-size: var(--vf-fs-h3);
  line-height: var(--vf-lh-h3);
  color: var(--vf-text-secondary);
}
/* Hilfebilder sind 1440 px breit. In voller Groesse im Textfluss zerreissen
   sie den Lesefluss, und der Blick springt bei jedem Bild ans Seitenende.
   Deshalb im Text auf 720 px gedeckelt - lesbar genug, um zu erkennen WOVON
   die Rede ist - und per Klick in Originalgroesse (Stefan, 2026-08-28).

   min() statt einer festen Breite: auf einem schmalen Fenster gewinnt weiter
   die 100 %, das Bild laeuft also nie ueber den Rand. */
.vfHelpShot {
  display: block;
  max-width: min(100%, 720px);
  height: auto;
  margin: var(--vf-space-4) 0;
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-sm);
  cursor: zoom-in;
}

.vfHelpShot:focus-visible {
  outline: none;
  box-shadow: var(--vf-shadow-focus);
}

/* Bilder NEBEN dem Text (Stefan, 29.09.2026: "kleiner, gut in den Text
   integriert, beim Klick in einer Lightbox"). Auf breitem Schirm ist das Bild
   ein Vorschaubild rechts, der Text fliesst daneben - 720 px als eigener
   Block zerrissen den Lesefluss, und lesbar war die Beschriftung darin auch
   bei 720 px nicht; lesbar wird sie erst in der Vergroesserung.

   Welches Bild neben welchem Text steht, entscheidet help/index.html
   (bilderEinbetten): vor den Absatz, der es einfuehrt.

   Was neben einem Bild keinen Sinn hat, weicht aus statt darunter zu rutschen:
   Hinweiskaesten und Codebloecke werden eigene Blockkontexte (flow-root) und
   damit schmaler neben dem Bild - Tabellen tun das von sich aus. Ein Kapitel und jede
   Zwischenueberschrift h3 beginnen unter dem letzten Bild des vorherigen
   Abschnitts - sonst stuende "Was gezeichnet wird" neben dem Bild von oben. */
@media (min-width: 1000px) {
  /* Die Leiste setzt help/index.html#bilderEinbetten: eine Folge von Bildern,
     vor den Absatz gezogen, der sie einfuehrt. */
  .vfHelpBilder {
    float: right;
    clear: right;
    width: min(40%, 360px);
    margin: var(--vf-space-1) 0 var(--vf-space-4) var(--vf-space-6);
  }
  .vfHelpBilderMehrere {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--vf-space-2);
    width: min(44%, 400px);
  }
  .vfHelpBilder .vfHelpShot {
    width: 100%;
    max-width: 100%;
    margin: 0;
  }
  .vfHelpBilder .vfHelpShot + .vfHelpShot {
    margin-top: var(--vf-space-2);
  }
  .vfHelpBilderMehrere .vfHelpShot + .vfHelpShot {
    margin-top: 0;
  }
  .vfHelpSection {
    display: flow-root;
  }
  .vfHelpBody h3 {
    clear: both;
  }
  .vfHelpNote,
  .vfHelpWarn,
  .vfHelpBody pre {
    display: flow-root;
  }
}

/* Die Vergroesserung. Bewusst ohne Bibliothek: ein <div> mit einem Bild darin,
   Schliessen per Klick, Esc oder dem Knopf. Mehr braucht es nicht, und die
   Hilfe soll eine statische Seite ohne Abhaengigkeiten bleiben. */
.vfHelpLightbox {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--vf-space-6);
  background: rgba(15, 17, 26, 0.82);
  cursor: zoom-out;
}

.vfHelpLightbox img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  border-radius: var(--vf-radius-md);
  box-shadow: var(--vf-shadow-lg);
  background: var(--vf-surface);
}

/* Der Schliessen-Knopf ist die sichtbare Zusage, dass man wieder herauskommt -
   der Klick auf den Hintergrund tut dasselbe, aber das sieht man ihm nicht an. */
.vfHelpLightboxClose {
  position: absolute;
  top: var(--vf-space-4);
  right: var(--vf-space-4);
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--vf-radius-sm);
  background: var(--vf-surface);
  color: var(--vf-text);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

.vfHelpLightboxClose:focus-visible {
  outline: none;
  box-shadow: var(--vf-shadow-focus);
}

/* Beim Drucken hat eine Vergroesserung keinen Sinn - und ein gedeckeltes Bild
   auch nicht: auf Papier ist die volle Breite das Nuetzlichste. */
@media print {
  .vfHelpShot {
    max-width: 100%;
    cursor: auto;
  }
  .vfHelpLightbox {
    display: none;
  }
}
.vfHelpCaption {
  display: block;
  margin: calc(var(--vf-space-4) * -1) 0 var(--vf-space-4);
  font-size: var(--vf-fs-caption);
  color: var(--vf-text-muted);
}
.vfHelpTable {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 var(--vf-space-5);
  font-size: var(--vf-fs-sm);
}
.vfHelpTable th,
.vfHelpTable td {
  text-align: left;
  padding: var(--vf-space-3) var(--vf-space-4);
  border-bottom: 1px solid var(--vf-border);
  vertical-align: top;
}
.vfHelpTable th {
  color: var(--vf-text-muted);
  font-weight: var(--vf-fw-medium);
  text-transform: uppercase;
  font-size: var(--vf-fs-caption);
  letter-spacing: 0.04em;
}
.vfHelpTable td code {
  font-family: var(--vf-font-mono);
  font-size: var(--vf-fs-code);
}
/* Codebeispiel in der Hilfe (Stylesheet-Ausschnitte im Flow-Editor-Kapitel).
   Mono wie ueberall, wo vFlow Technisches zeigt (CLAUDE.md Abschnitt 3), und
   mit eigenem Scrollbalken: eine lange Zeile darf die Seite nicht in die
   Breite ziehen. */
.vfHelpCode {
  font-family: var(--vf-font-mono);
  font-size: var(--vf-fs-code);
  background: var(--vf-surface);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  padding: var(--vf-space-3) var(--vf-space-4);
  overflow-x: auto;
  margin: var(--vf-space-4) 0;
}
.vfHelpNote {
  background: var(--vf-info-bg);
  border: 1px solid var(--vf-info-border);
  border-radius: var(--vf-radius-md);
  padding: var(--vf-space-4) var(--vf-space-5);
  font-size: var(--vf-fs-sm);
  color: var(--vf-text);
}
.vfHelpNote strong {
  color: var(--vf-info);
}
/* Ein mehrteiliger Hinweis (Liste, dann Absatz) soll unten nicht mehr Luft
   haben als oben - der Abstand des letzten Absatzes addiert sich sonst zur
   Polsterung des Kastens. */
.vfHelpNote > p:last-child,
.vfHelpNote > ul:last-child {
  margin-bottom: 0;
}
/* Wie .vfHelpNote, nur in den Warn-Tokens: fuer die wenigen Stellen, an denen
   ein Update BESTEHENDES Verhalten aendert. Das ist kein Hinweis mehr, den man
   auch ueberlesen kann - wer ihn ueberliest, merkt es an einer Schnittstelle,
   die nach dem Update anders arbeitet als vorher. Statusfarbe fuer einen
   echten Zustand, nicht als Schmuck (CLAUDE.md §2). */
.vfHelpWarn {
  background: var(--vf-warning-bg);
  border: 1px solid var(--vf-warning-border);
  border-radius: var(--vf-radius-md);
  padding: var(--vf-space-4) var(--vf-space-5);
  font-size: var(--vf-fs-sm);
  color: var(--vf-text);
}
.vfHelpWarn strong {
  color: var(--vf-warning);
}
.vfHelpWarn > p:last-child,
.vfHelpWarn > ul:last-child {
  margin-bottom: 0;
}
.vfHelpTutorial {
  border-top: 3px solid var(--vf-primary);
  padding-top: var(--vf-space-5);
}
.vfHelpStep {
  margin-bottom: var(--vf-space-7);
}

/* Hinweisseite "nur am Desktop" (mobile-scope.md Abschnitt 3). Bewusst ein
   grosses, ruhiges Symbol in Neutralfarbe und NICHT in einer Statusfarbe:
   hier ist nichts fehlgeschlagen, die Seite ist nur woanders zu Hause
   (CLAUDE.md §2 - Statusfarben bleiben echtem Zustand vorbehalten). */
.vfDesktopOnlyIcon {
  font-size: 3rem;
  color: var(--vf-text-muted);
  margin-top: var(--vf-space-6);
}

/* Hilfe auf dem Telefon (mobile-scope.md Abschnitt 5). Die Hilfe ist eine
   eigenständige Seite mit eigenem Viewport-Meta und war damit die halbe
   Miete - was sie auf 390 px trotzdem unbrauchbar machte, ist das
   Zwei-Spalten-Layout: ein Inhaltsverzeichnis mit FESTEN 200 px neben dem
   Text lässt davon keine 150 px übrig.

   Deshalb hier gestapelt statt nebeneinander, und das Verzeichnis verliert
   sein position:sticky - ein klebender Block, der die halbe Höhe eines
   Telefondisplays einnimmt, wäre schlimmer als gar keiner. Es steht dann
   einmal oben, wie ein Inhaltsverzeichnis in einem Buch. */
@media (max-width: 599px) {
  .vfHelpLayout {
    flex-direction: column;
    gap: var(--vf-space-5);
  }
  .vfHelpToc {
    position: static;
    flex: none;
    width: auto;
    border-right: none;
    border-bottom: 1px solid var(--vf-border);
    padding-right: 0;
    padding-bottom: var(--vf-space-4);
  }
  .vfHelpBody {
    gap: var(--vf-space-7);
  }
  /* Die Tabellen sind zwei- und dreispaltig und laufen bei voller Polsterung
     aus dem Rand. Enger setzen statt waagerecht scrollen zu lassen: es sind
     durchweg Begriff/Bedeutung-Paare, die umbrechen dürfen. */
  .vfHelpTable th,
  .vfHelpTable td {
    padding: var(--vf-space-2);
  }
  /* Ein einzelnes langes <code> (das längste ist 45 Zeichen, z. B.
     "<Methode> /inbound/rest/<Adresse>") würde die Tabelle sonst aufspreizen
     und die ganze Seite waagerecht scrollbar machen. */
  .vfHelpTable code {
    overflow-wrap: anywhere;
  }
}

/* Gestufte Verbindungsdiagnose (Stefan, 2026-08-07, connection-test.ts):
   je Zeile eine Stufe - Name aufgeloest / Port erreichbar / Anmeldung /
   Verzeichnis. Ersetzt nicht die MessageStrip darueber, sondern beantwortet
   die Anschlussfrage beim Scheitern: woran genau lag es? */
.vfConnTestSteps {
  margin-top: var(--vf-space-2);
  padding: var(--vf-space-2) var(--vf-space-3);
  background: var(--vf-bg);
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
}
.vfConnTestRow {
  padding: 2px 0;
  gap: var(--vf-space-2);
}
.vfConnTestIcon {
  font-size: 14px;
  width: 1rem;
}
.vfConnTestOk    { color: var(--vf-success) !important; }
.vfConnTestFailed { color: var(--vf-error) !important; }
.vfConnTestSkipped { color: var(--vf-text-muted) !important; }
/* Feste Breite, damit die Detailspalte in allen Zeilen an derselben Kante
   beginnt - sonst franst die Liste je nach Bezeichnungslaenge aus. */
.vfConnTestLabel {
  min-width: 11rem;
  font-size: var(--vf-fs-caption) !important;
}
/* Technische Werte (Adressen, Ports, Pfade, Serverfehler) in Mono - dieselbe
   Trennung wie ueberall sonst im Produkt. */
.vfConnTestDetail {
  font-family: var(--vf-font-mono);
  font-size: var(--vf-fs-caption) !important;
  color: var(--vf-text-muted) !important;
}

/* Kacheln der Ueber-vFlow-Seite (About.view.xml).

   Die Karte muss ihre Gitterzelle ausfuellen, sonst steht sie oben in einer
   Zelle, die durch gridAutoRows="1fr" hoeher ist als ihr Inhalt - und man
   saehe wieder ungleich hohe Kaesten, nur diesmal mit Luft darunter statt
   daneben. box-sizing, damit das Innenmass von .vfCard die 100 % nicht
   sprengt. */
.vfAboutCard {
  height: 100%;
  box-sizing: border-box;
}

/* Kacheln der Engine-Seite (Engine.view.xml).

   Wie .vfAboutCard: die Kachel muss ihre Gitterzelle ausfuellen, sonst steht
   sie oben in einer Zelle, die durch gridAutoRows="1fr" hoeher ist als ihr
   Inhalt - und man saehe wieder ungleich hohe Kaesten, nur mit Luft darunter
   statt daneben.

   Die Statuszeile am unteren Rand auszurichten waere schoener, braucht aber
   einen Selektor auf UI5s Innen-DOM - dafuer wird die Seite erst einmal
   angesehen. */
.vfEngineTile {
  height: 100%;
  box-sizing: border-box;
}

/* Kachelgitter der Ueber-vFlow-Seite (About.view.xml).

   Zwei Spalten, fest - nicht auto-fit. Mit auto-fit passten auf einem breiten
   Bildschirm vier Kacheln nebeneinander, und aus dem gewuenschten 2x2 wurde
   ein 4x1 mit viel zu schmalen Spalten (Stefan, 2026-08-12).

   !important, weil sap.ui.layout.cssgrid.CSSGrid seine Angaben als Inline-Stil
   setzt und ein Klassen-Selektor sonst verliert - dieselbe UI5-Eigenheit wie
   bei den Emphasized-Buttons.

   Unter 48rem eine Spalte: zwei Karten nebeneinander sind auf einem schmalen
   Fenster unlesbar. */
.vfAboutGrid {
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
}

/* ---- Marken-/Kontaktkachel (About.view.xml, Stefan 2026-08-30) -----------
   Eine Kachel, zwei Haelften: links die Marke, rechts von wem sie ist.

   Das Umbrechen steuert die HBox selbst (wrap="Wrap" in der View), NICHT
   eine Regel hier: sap.m.HBox setzt `flex-wrap: nowrap` ueber eine eigene
   Klasse und gewinnt gegen das App-CSS. Mit `flex-wrap: wrap` an dieser
   Stelle blieb der Umbruch aus, und die Haelften ragten bei 900 px ueber den
   Kachelrand hinaus - im Bild nachgesehen.
   ---------------------------------------------------------------------- */
.vfAboutBrandRow {
  width: 100%;
  gap: var(--vf-space-4);
}

/* Zwei Haelften, die sich den Platz teilen - aber NICHT beliebig weit
   schrumpfen duerfen.

   Mit `min-width: 0` (erster Anlauf) griff flex-wrap nie: die Haelften
   schrumpften unter ihre Basis, statt umzubrechen. Bei 900 px Fensterbreite
   ist das Raster noch zweispaltig, die Kachel also ~264 px breit, und beide
   Haelften landeten bei 126 px. Ergebnis im Bild: "Support" brach
   BUCHSTABENWEISE senkrecht um, die Mailadresse ragte aus der Kachel, der
   Claim lag ueber dem Logo.

   `min-width: 11rem` ist knapp unter der Basis und damit die Schwelle, ab
   der umgebrochen statt gequetscht wird - zwei Haelften passen erst ab
   ~22rem Kachelbreite nebeneinander, darunter stehen sie untereinander und
   haben jeweils die volle Breite. */
.vfAboutBrandSide,
.vfAboutContactSide {
  flex: 1 1 12rem;
  min-width: 11rem;
}

/* Und selbst in der vollen Breite bleibt "sap.services@valcoba.com" ein
   Wort ohne Trennstelle. Auf dem Telefon ist die Spalte schmaler als die
   Adresse - dann lieber mitten im Wort umbrechen als ueber den Rand
   hinauslaufen. */
.vfAboutContactSide,
.vfAboutContactLink {
  overflow-wrap: anywhere;
}

/* Die Marke bringt ihren eigenen Abstand nach unten mit (.vfLoginBrand),
   der in der einspaltigen Kachel richtig war - nebeneinander erzeugt er
   eine schiefe Mitte. */
.vfAboutBrandSide {
  margin-bottom: 0;
}

/* Rechtsbuendig, wie gewuenscht. !important, weil UI5 seine eigenen
   FlexBox-Klassen (.sapMFlexItemAlignEnd u. a.) nach dem App-CSS setzt -
   dieselbe Laufzeit-Uebersteuerung wie beim Marken-Quadrat. */
.vfAboutContactSide {
  align-items: flex-end !important;
  text-align: right;
}

/* Label und Verweis in einer Zeile ("Support sap.services@valcoba.com"),
   rechts ausgerichtet. Ohne das Zuruecksetzen von justify-content stuende
   das Paar links in einer sonst rechtsbuendigen Spalte. */
.vfAboutContactLink {
  justify-content: flex-end !important;
  gap: var(--vf-space-2);
}

@media (max-width: 48rem) {
  .vfAboutGrid {
    grid-template-columns: 1fr !important;
  }
}

/* ---------------------------------------------------------------------------
   Etikett der Installation (INSTALLATION_LABEL, siehe AppService#getHealth).
   Sichtbar nur, wenn die .env einen Wert setzt - eine Produktivinstallation
   traegt bewusst keine Kennzeichnung.

   BEWUSST KEINE Statusfarbe: gruen/rot sind in vFlow funktional belegt (die
   Statusbadges im Monitoring) und duerfen nicht als Dekoration auftauchen. Das
   Etikett nimmt deshalb den Brand-Ton in seiner leisen Stufe - auffaellig
   genug, um im Blick zu sein, ohne sich als Zustandsmeldung auszugeben.

   Mono, weil es ein technischer Wert ist wie Flow-IDs und Zeitstempel - siehe
   die Schriftregel in CLAUDE.md. */
.vfInstanceTag {
  font-family: var(--vf-font-mono) !important;
  font-size: var(--vf-fs-sm);
  font-weight: 500;
  line-height: 1;
  color: var(--vf-primary);
  background: var(--vf-primary-subtle);
  border: 1px solid var(--vf-primary);
  border-radius: var(--vf-radius-xs);
  padding: var(--vf-space-2) var(--vf-space-3);
  white-space: nowrap;
}

/* In der Kopfzeile steht das Etikett direkt neben dem Produktnamen. Die
   ToolHeader ist in vFlow HELL (weisser Grund) - eine helle Schrift waere dort
   unsichtbar. Genau das ist beim ersten Versuch passiert: Das Element war im
   DOM, trug den richtigen Text und stand an der richtigen Stelle, war aber
   weiss auf weiss. Also dieselbe Fuellung wie ueberall, nur vertikal
   ausgerichtet. */
.sapMTB .vfInstanceTag {
  align-self: center;
  flex: 0 0 auto;
}

/* Auf der Anmeldemaske zwischen Wortmarke und Begruessung - dort ist der Grund
   hell, also bleibt die Fuellung von oben; nur der Abstand kommt dazu. */
.vfLoginInstanceTag {
  display: inline-block;
  margin: var(--vf-space-3) 0 var(--vf-space-1) 0;
}

/* Nachrichtendetail: Etikett links, Wert rechts - und das Etikett darf nicht
   zerbrechen. Die Zeilen der Uebersicht sind HBoxen mit SpaceBetween; bei
   kurzen Werten (Zeitstempel, Zahlen) geht das von selbst auf. Ein langer
   Freitext - Abbruchgrund oder Fehlermeldung - drueckt das Etikett aber
   zusammen, bis es ZEICHENWEISE umbricht ("Abbru/chgru/nd", gesehen beim
   Aufnehmen der Hilfebilder am 2026-08-18).
   Die eigentliche Sperre sitzt in der View (FlexItemData shrinkFactor="0" am
   Etikett): HBox legt seine Kinder in eigene Huellen, eine CSS-Klasse am Text
   darin kann das Schrumpfen nicht verhindern. Hier bleiben nur Abstand und
   Ausrichtung. */
/* Uebersicht im Nachrichten-Detail (Monitoring.view.xml, 24.09.2026):
   volle Breite, Etikett in fester Spalte, Wert gleich daneben. Die Zeilen
   sind HBox mit renderType="Bare", damit die Texte selbst die Flex-Kinder
   sind (CLAUDE.md §4: sonst nimmt der .sapMFlexItem-Wrapper die Breite). */
/* Die weisse Karte darum stellt die ObjectPage-Sektion schon - hier nur
   Abstaende, sonst saesse eine Karte in der Karte. */
.vfDetailUebersicht {
  gap: var(--vf-space-3);
}
.vfDetailZeile {
  gap: var(--vf-space-5);
  align-items: baseline;
}
.vfDetailZeile > .vfDetailEtikett {
  flex: 0 0 10rem;
  color: var(--vf-text-muted);
}
.vfDetailZeile > .vfDetailWert {
  flex: 1 1 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.vfDetailLabel {
  margin-right: var(--vf-space-5);
}
.vfDetailValue {
  text-align: right;
}

/* Nicht transportierbare Zeile in der Transport-Auswahl (Transport.controller.js).
   Ein Flow ohne veroeffentlichte Version kann nicht mitfahren - er bleibt aber
   SICHTBAR statt gefiltert zu werden: wer seinen Flow sucht und nicht findet,
   haelt die Liste fuer kaputt; wer ihn gedaempft und mit "kein Publish" sieht,
   kennt sofort den naechsten Schritt.
   Nur das Auswahlfeld wird gesperrt, die Zeile bleibt lesbar - deshalb
   gedaempfte Schrift statt der ueblichen halben Deckkraft ueber allem. */
.vfZeileGesperrt .sapMText,
.vfZeileGesperrt .sapMObjStatusText {
  color: var(--vf-text-muted) !important;
}

.vfZeileGesperrt .sapMLIBSelectM,
.vfZeileGesperrt .sapMCb {
  pointer-events: none;
  opacity: 0.35;
}

/* Popin-Beschriftung: kein Leerzeichen vor dem Doppelpunkt (Befund R11,
   28.08.2026).

   In der schmalen Ansicht der Monitoring-Zusammenfassung stand
   "Total : 69530", zwei Zeilen darunter aber "Sender: File01" - zwei
   Schreibweisen im selben Kasten.

   Ursache ist kein Text, sondern ein Layoutdetail: die SORTIERBAREN Spalten
   tragen einen <Button type="Transparent"> als Kopf (Monitoring.view.xml,
   summaryHeader*), die nicht sortierbaren ein <Text>. Im Popin erbt die
   Beschriftung damit den Innenabstand des Buttons - im Browser gemessen
   7 px links und rechts, dazu min-width 32 px. Der Kopf war deshalb 59,2 px
   breit statt 43,2, und der Zwischenraum landete vor dem Doppelpunkt.

   !important ist hier noetig: UI5s eigene Button-Regeln haben die hoehere
   Spezifitaet, ohne den Zusatz aendert sich nichts (nachgemessen).

   Merksatz: ein Layoutdetail wird so zu einem Rechtschreibfehler. */
.sapMListTblSubCntHdr .sapMBtn {
  margin: 0 !important;
}

.sapMListTblSubCntHdr .sapMBtnInner {
  padding: 0 !important;
  min-width: 0 !important;
  height: auto !important;
  border: none !important;
  background: transparent !important;
}

/* Ein Flex-Element, das unter seinen Inhalt schrumpfen darf (Befund R6,
   28.08.2026).

   Flexbox setzt min-width auf "auto": ein Element schrumpft von sich aus NICHT
   unter die Breite seines Inhalts, sondern waechst aus seinem Behaelter heraus.
   In der Runtime-Sicht lief dadurch ein langer Flow-Name links ueber das
   Schloss-Symbol hinaus und rechts bis an die Status-Pille - und das
   wrapping="false" an der Flow-ID darunter konnte gar nicht kuerzen, weil es
   dafuer eine Breitenschranke braucht.

   Merksatz: wrapping="false" kuerzt nichts, solange die Box mitwaechst. */
.vfSchrumpfbar {
  min-width: 0;
  overflow: hidden;
}

/* ---- Versionsverlauf (FlowEditor.view.xml) ------------------------------
   Sieben Spalten - Version, Status, zweimal Wer/Wann, Kommentar, Aktionen -
   in einem Dialog von 1100 px. Mit der dichten Standard-Zeilenhoehe liefen
   Zeitstempel und Status-Pille ineinander (Stefan beim Testen, 2026-08-30:
   "die Historie-Liste ist auch etwas gedrängt").

   Nur hier: Monitoring und Dashboard bleiben bewusst dicht (CLAUDE.md
   Abschnitt 6, 36-40 px) - dort zaehlt, wie viele Zeilen auf den Schirm
   passen. Ein Versionsverlauf hat selten mehr als eine Handvoll.

   ## Warum genau DIESER Selektor

   Zwei Umwege, beide im Browser nachgemessen und beide wirkungslos:

   1. `.vfVersionHistoryTable .sapMListTblCell` (ohne den Kindkombinator) -
      auch mit `!important`. Zwei Klassen reichen gegen UI5s eigene
      Zellregel nicht.
   2. `sapUiSizeCozy` am Dialog, also UI5s eigener Dichte-Schalter. Der
      greift NICHT, wenn der Body auf `sapUiSizeCompact` steht: beide
      Regeln stehen gleichrangig in der library.css von sdk.openui5.org,
      und die Naehe im DOM entscheidet dort nichts.

   Was wirkt, ist die zusaetzliche Zeilenklasse - drei Klassen schlagen UI5s
   zwei. Der Kindkombinator sieht nach Zierrat aus und ist der Grund, warum
   die Regel ueberhaupt ankommt; wer ihn "vereinfacht", nimmt ihr die
   Wirkung (genau das ist beim Aufraeumen einmal passiert). ------------- */
.vfVersionHistoryTable .sapMListTblRow > .sapMListTblCell,
.vfVersionHistoryTable .sapMListTblHeader > .sapMListTblHeaderCell {
  padding-top: var(--vf-space-3) !important;
  padding-bottom: var(--vf-space-3) !important;
  /* Luft ZWISCHEN den Spalten - die Zeitstempel stehen in Mono und tragen
     ihre Breite bis an den Rand der Zelle. */
  padding-right: var(--vf-space-4) !important;
}

/* System Landscape, Kanten-Dialog: die Namensspalte waechst in den freien
   Platz und kuerzt einen zu langen Flow-Namen mit Auslassungspunkten, statt
   die Zeile zu verbreitern. Das Schrumpfen selbst regelt `minWidth` an der
   FlexItemData im Controller - ueber CSS ginge es nicht, weil UI5 sein Theme
   nach dieser Datei laedt. */
.vfLandschaftFlowName {
  overflow: hidden;
  text-overflow: ellipsis;
  /* Abstand als padding, nicht als margin: bei `overflow: hidden` liegen die
     Auslassungspunkte am Innenrand, ein Aussenabstand wuerde dahinter sitzen
     und der gekuerzte Name klebte an der Zahlenspalte. */
  padding-right: var(--vf-space-3);
}

/* System Landscape, Legende als Filter (29.09.2026): ein ausgeblendeter Typ
   bleibt in der Legende stehen - sonst koennte man ihn nicht wieder
   einblenden -, aber blass und durchgestrichen. */
.vfLandschaftLegende[data-aus="ja"] {
  opacity: 0.45;
}
.vfLandschaftLegende[data-aus="ja"] .sapMLnk {
  text-decoration: line-through;
}

/* Waehrend ein System gezogen wird: Greifhand ueberall im Bild, und kein
   Markieren von Beschriftungen. !important, weil die Knoten ihren Zeiger als
   Inline-Stil tragen (der muss ins exportierte SVG, eine Klasse gilt dort
   nicht). */
.vfLandschaftZiehen,
.vfLandschaftZiehen * {
  cursor: grabbing !important;
  user-select: none;
}

/* ---------------------------------------------------------------------------
   Feldzuordnung: zwei Baeume mit Linien dazwischen
   (docs/architecture/message-mapping.md Abschnitt 10, Frage 4)

   Die Linienflaeche ist eine eigene Spalte zwischen den Baeumen, nicht ein
   Overlay ueber ihnen: so kann kein Strich einen Klick abfangen, und die
   Baeume scrollen unabhaengig, ohne dass die Linien mitwandern muessen.
   Sie sind Anzeige, nicht Bedienung.
--------------------------------------------------------------------------- */
.vfZuordnungFlaeche {
  align-items: stretch;
  height: 52vh;
  border: 1px solid var(--vf-border);
  border-radius: var(--vf-radius-md);
  background: var(--vf-surface);
}

/* Die drei Spalten. Sie funktionieren nur, weil die HBox mit
   renderType="Bare" rendert - sonst legt UI5 um jedes Kind eine eigene
   sapMFlexItem-Huelle, und diese Regeln greifen eine Ebene zu tief. */
/* box-sizing ausdruecklich: die Spalten tragen Polsterung, und ohne das
   kaeme sie zur berechneten Breite hinzu - die beiden Seiten waeren dann
   nicht mehr gleich breit, obwohl beide flex:1 haben. */
.vfZuordnungSeite {
  flex: 1 1 0;
  min-width: 0;
  box-sizing: border-box;
}

.vfZuordnungSeiteKopf {
  flex: 0 0 auto;
  align-self: flex-start;
  margin: var(--vf-space-2) var(--vf-space-2) 0;
}

.vfZuordnungBaum {
  box-sizing: border-box;
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  overflow: auto;
  padding: var(--vf-space-3);
}

.vfZuordnungLinien {
  flex: 0 0 5rem;
  position: relative;
  border-left: 1px solid var(--vf-border);
  border-right: 1px solid var(--vf-border);
}

.vfZuordnungLinien > div {
  position: absolute;
  inset: 0;
}

.vfZuordnungLinien svg {
  display: block;
  width: 100%;
  height: 100%;
  /* Klicks gehen durch: gebedient wird auf den Zeilen. */
  pointer-events: none;
}

.vfZuordnungLinie {
  fill: none;
  stroke: var(--vf-primary);
  stroke-width: 1.5;
  opacity: 0.75;
}

/* Eine Wiederholung ist etwas anderes als ein Feld - gestrichelt, damit man
   die beiden Arten von Verbindung im Bild unterscheiden kann. */
.vfZuordnungLinieGruppe {
  stroke-dasharray: 4 3;
}

.vfZuordnungZeile {
  cursor: pointer;
  border-radius: var(--vf-radius-sm);
  padding: 2px var(--vf-space-3);
  min-height: 24px;
}

.vfZuordnungZeile:hover {
  background: var(--vf-neutral-100);
}

.vfZuordnungGewaehlt {
  background: var(--vf-brand-50, var(--vf-neutral-100));
  box-shadow: inset 2px 0 0 var(--vf-primary);
}

.vfZuordnungName {
  font-family: var(--vf-font-mono);
  font-size: 13px;
}

.vfZuordnungAttr {
  color: var(--vf-text-muted);
  font-style: italic;
}

.vfZuordnungZusatz {
  font-family: var(--vf-font-mono);
  font-size: 12px;
  color: var(--vf-text-muted);
  margin-left: var(--vf-space-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.vfZuordnungDetail {
  margin-top: var(--vf-space-4);
  max-height: 22vh;
  overflow: auto;
}

.vfZuordnungTiefe0 { padding-left: var(--vf-space-3); }
.vfZuordnungTiefe1 { padding-left: calc(var(--vf-space-3) + 16px); }
.vfZuordnungTiefe2 { padding-left: calc(var(--vf-space-3) + 32px); }
.vfZuordnungTiefe3 { padding-left: calc(var(--vf-space-3) + 48px); }
.vfZuordnungTiefe4 { padding-left: calc(var(--vf-space-3) + 64px); }
.vfZuordnungTiefe5 { padding-left: calc(var(--vf-space-3) + 80px); }
.vfZuordnungTiefe6 { padding-left: calc(var(--vf-space-3) + 96px); }
.vfZuordnungTiefe7 { padding-left: calc(var(--vf-space-3) + 112px); }
.vfZuordnungTiefe8 { padding-left: calc(var(--vf-space-3) + 128px); }

/* Die Obergrenze der Dialogbreite gehoert hierher und nicht in contentWidth:
   UI5 prueft dort gegen den Typ CSSSize, und der kennt kein min(). */
.vfZuordnungDialog {
  max-width: 1280px;
}

/* ⓘ neben dem Feld-Label (Design-Handoff Eigenschaften-Panel, 11.09.2026).
   Der Knopf soll die Label-Zeile NICHT hoeher machen und nicht wie eine
   Aktion aussehen - er ist ein Angebot, kein Befehl. Deshalb ohne
   Hintergrund, in der Farbe der sekundaeren Schrift, und erst beim
   Darueberfahren in der Aktionsfarbe. */
.vfFormLabelMitHilfe {
  gap: var(--vf-space-1, 4px);
}
/* !important bei der Hoehe: die Regeln standen hier seit jeher mit 1.25rem,
   gewirkt haben sie nie - UI5s Knopfhoehe kommt zur Laufzeit nach dem
   App-CSS und gewann. Im Panel nachgemessen (21.09.2026): 32px statt der
   gemeinten 20px. Genau diese 12px zuviel haben die Formularzeilen
   auseinandergezogen. */
.vfHilfeKnopf.sapMBtn {
  min-width: 0;
  height: var(--vf-label-line) !important;
  margin: 0;
  /* !important wie bei der Hoehe: UI5 gibt dem Knopf `padding: 3px 0`, und
     die drei Pixel schoben das Icon im 20px-Kasten nach UNTEN - das ⓘ stand
     damit 3px tiefer als die Mitte des Labels daneben (im Panel gemessen,
     21.09.2026: Textmitte 696, Ikonmitte 699). Mit `padding: 0` fallen beide
     Mitten zusammen.
     Nicht angefasst, obwohl in diesem Block ebenfalls wirkungslos:
     `min-width: 0` am .sapMBtnInner (UI5 haelt 32px) und die Icon-Groesse
     (16px statt 0.875rem). Beides gemessen und ABSICHTLICH so gelassen - die
     32px sind die Klickflaeche und zugleich der Abstand des ⓘ zum Text;
     erzwungen man die 0, klebt das Icon mit 2px am Label. */
  padding: 0 !important;
}
.vfHilfeKnopf .sapMBtnInner {
  min-width: 0;
  height: var(--vf-label-line) !important;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
}
.vfHilfeKnopf .sapMBtnIcon {
  color: var(--vf-text-secondary, #556b82);
  min-width: 0;
}
/* Zeilenhoehe und Groesse mit hoeherer Spezifitaet (0,4,0): mit
   `.vfHilfeKnopf .sapMBtnIcon` (0,2,0) standen beide seit jeher hier und
   wirkten nie - UI5s Knopf-Icon-Regel gewann, im Browser auf DEV gemessen
   (24.09.2026): line-height 24px und 16px statt 20px und 14px. Die Glyphe lag
   damit in einer 24px-Zeile im 20px-Kasten und stand rund 2px tiefer als die
   Mitte des Labels daneben (Stefan sah es an „Dateiname-Muster ⓘ").
   Mit dieser Regel fallen die Mitten zusammen, nachgemessen. Kein
   !important: die Spezifitaet reicht, und kein Control drueckt eine
   Icon-Zeilenhoehe aus. */
.vfHilfeKnopf.sapMBtn .sapMBtnInner .sapMBtnIcon {
  font-size: 0.875rem;
  line-height: var(--vf-label-line);
}
.vfHilfeKnopf:hover .sapMBtnIcon {
  color: var(--vf-primary, #5b45e0);
}

/* Panel-Kopf des Eigenschaften-Fensters (Design-Handoff, 11.09.2026).
   Icon-Kachel links, Titel + Untertitel in der Mitte, Pflichtfeld-Stand
   rechts. Die Kachel traegt die Markenfarbe - der Handoff nennt dafuer
   Violett, und das ist zugleich die Farbe des Knotens im Diagramm: dasselbe
   Element, dieselbe Farbe. */
.vfPanelKopf {
  gap: var(--vf-space-3, 12px);
  margin-bottom: var(--vf-space-3, 12px);
}
/* Mit .sapMFlexBox als zweitem Glied: jede HBox ohne backgroundDesign traegt
   UI5s `.sapMFlexBoxBGTransparent { background-color: transparent }`, und
   die gewann - die Kachel war im Browser durchsichtig (DEV, 14.09.2026),
   derselbe Fall wie bei .vfEntityAvatar weiter oben. */
.vfPanelKopfIkone.sapMFlexBox {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border-radius: var(--vf-radius-md, 8px);
  background: var(--vf-primary-subtle, #ede9fc);
}
.vfPanelKopfIkone .sapUiIcon {
  color: var(--vf-primary, #5b45e0);
  font-size: 1rem;
}
.vfPanelKopfText {
  flex: 1 1 auto;
  min-width: 0;
}
.vfPanelTitel {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--vf-text, #1d2d3e);
}
.vfPanelUntertitel {
  font-size: 0.75rem;
  color: var(--vf-text-tertiary, #556b82);
}
/* Der Pflichtfeld-Stand ist eine Auskunft, keine Warnung: solange nichts
   fehlt, bleibt er unauffaellig. Erst wenn etwas offen ist, traegt er die
   Pflichtfarbe - dieselbe wie der Stern am Label. */
.vfPanelStatus,
.vfPanelStatusOffen {
  flex: 0 0 auto;
  font-size: 0.75rem;
  padding-left: var(--vf-space-3, 12px);
}
.vfPanelStatus {
  color: var(--vf-text-tertiary, #556b82);
}
.vfPanelStatusOffen {
  color: var(--vf-required, #b6248a);
  font-weight: 600;
}

/* Punkt am Reiter, solange dort ein Pflichtfeld offen ist (Design-Handoff).
   Bewusst klein und ohne Zahl: er sagt "hier fehlt noch etwas", die Menge
   steht im Panel-Kopf. Zwei Zahlen an zwei Orten waeren eine zu viel. */
/* Der Marker kommt als data-Attribut und nicht als Stilklasse: ein
   IconTabFilter erbt von Item, nicht von Control, und hat kein
   addStyleClass (siehe FlowEditor.controller.js#_showElementPanel). */
/* Der Punkt haengt am INNEREN Textknoten (.sapMITHTextContent) und nicht am
   aeusseren .sapMITBText. Der ist naemlich `display: flex` - im Browser
   gemessen, nicht vermutet -, und ein ::after darin wird zum FLEX-KIND: es
   stellt sich neben statt hinter den Text und rutschte beim gewaehlten
   Reiter ueber den ersten Buchstaben (Stefan und ich sahen es gleichzeitig,
   11.09.2026). Der innere Span ist ein normaler Block, dort folgt der Punkt
   dem Text wie jedes andere Zeichen - in beiden Zustaenden. */
[data-vfpflicht="offen"] .sapMITHTextContent::after {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 6px;
  vertical-align: middle;
  border-radius: 50%;
  background: var(--vf-required, #b6248a);
}

/* ==========================================================================
   Eigenschaften-Panel, zweiter Handoff (Stefan, 14.09.2026)
   ==========================================================================
   Die Masse stammen aus dem Handoff (README, Abschnitt Panel-Aufbau), die
   Farben aus den vFlow-Token - der Mockup nennt Fiori-Blau, vFlow ist
   violett, und das ist eine Entscheidung, keine Nachlaessigkeit. Was hier
   NICHT uebernommen wird: die Eingabehoehe 36px. Das Design-System steht
   auf 32px (--vf-control-h), und ein Panel mit anderen Feldhoehen als der
   Rest der App waere der auffaelligere Fehler. */

/* Innenabstand: 14px unter dem Splitter, 24px seitlich, 24px unten.
   Vorher `sapUiSmallMargin` (16px rundum) - und dazu noch einmal 16px an
   jedem Reiterinhalt, sodass die Felder 32px vom Rand standen, die Reiter
   aber 16px. */
.vfBottomPanel > .vfPanelInhalt {
  /* space-7 ist 24px; space-6 sind 20 - beim ersten Wurf verwechselt und im
     Browser als "14px 20px 20px" gemessen. */
  padding: 14px var(--vf-space-7, 24px) var(--vf-space-7, 24px);
}

/* Reiterleiste direkt am linken Panelrand, Text 14/600, 3px-Linie.
   Spezifitaet: UI5 setzt Kopf-Innenabstaende ueber eigene Klassen
   (.sapMITH mit sapUiResponsiveContentPadding), deshalb ueberall der
   Vorfahre .vfBottomPanel und !important nur dort, wo UI5 dieselbe
   Eigenschaft mit derselben Tiefe setzt (gemessen am 27.08. an
   .vfTabsAligned, siehe oben). */
.vfBottomPanel .sapMITB > .sapMITH {
  padding-left: 0 !important;
  padding-right: 0 !important;
  border-bottom: 1px solid var(--vf-border, #d5dadf);
  background: transparent;
}
.vfBottomPanel .sapMITBFilter .sapMITBText {
  font-size: 14px;
  font-weight: 600;
}
.vfBottomPanel .sapMITBFilter.sapMITBSelected::after {
  border-bottom-width: 3px !important;
}
/* Reiterinhalt ohne den UI5-Innenabstand: das Raster unten bringt seinen
   eigenen Abstand mit, und die Felder sollen mit den Reitern fluchten. */
.vfBottomPanel .sapMITB > .sapMITBContainerContent > .sapMITBContent {
  padding: 18px 0 0;
  background: transparent;
}

/* Gruppen-Header innerhalb eines Reiters: Trennlinie, 8px, dann der
   Kicker (Handoff, Feld-Raster). Als erstes Element eines Reiters keine
   Linie - dort ist die Reiterleiste die Linie. */
.vfPanelRaster > .vfFormSection {
  border-top: 1px solid var(--vf-border, #e1e5ea);
  padding-top: var(--vf-space-2, 8px);
  margin: var(--vf-space-2, 8px) 0 0;
}
.vfPanelRaster > .vfFormSection:first-child {
  border-top: none;
  padding-top: 0;
}

/* Einleitungssatz am Reiteranfang: ein Satz, 13/400, dann "Mehr". */
.vfPanelEinleitung {
  gap: var(--vf-space-2, 8px);
  align-items: baseline;
  margin-bottom: var(--vf-space-2, 8px);
}
.vfPanelEinleitung .sapMText {
  font-size: 13px !important;
  line-height: 1.5;
  color: var(--vf-text-secondary, #33425a) !important;
}

/* Checkbox-Zeile: kein eigenes Label, Kaestchen und Text in einer Zeile.
   Der obere Versatz laesst das Kaestchen mit der EINGABE der Nachbarspalte
   fluchten statt mit deren Label (Handoff: 22px = Label 16px + 6px). */
.vfPanelRaster > .vfFormRowCheck {
  padding-top: 22px;
}
.vfFormRowCheck .vfFormLabelMitHilfe {
  gap: 0;
}

/* Zahl mit Einheit: 120px, rechtsbuendig, die Einheit als Text daneben.
   Die senkrechte Mitte kommt NICHT von hier: `align-items: center` stand
   hier und verlor gegen UI5s `.sapMFlexBoxAlignItemsStretch` (gleiche
   Spezifitaet, spaeter geladen) - „Sekunden" klebte oben an der Eingabe
   (gemessen 24.09.2026). Das HBox-Control setzt jetzt alignItems="Center"
   selbst (FlowEditor.controller.js#_addFormRow). */
.vfFormZahl {
  gap: var(--vf-space-2, 8px);
}
.vfFormZahl .sapMInputBaseInner {
  text-align: right;
}
.vfFormEinheit {
  font-size: 13px !important;
  color: var(--vf-text-tertiary, #556b82) !important;
  white-space: nowrap;
}

/* Nur-lesen-Wert (System-ID, Adresse, Endpunkt): kein Rahmen, gestrichelte
   Unterlinie, sekundaere Textfarbe - eine Auskunft, kein Feld. */
.vfNurLesen {
  display: inline-block;
  padding: 6px 0;
  border-bottom: 1px dashed var(--vf-border-strong, #89919a);
  color: var(--vf-text-secondary, #33425a) !important;
}

/* Aktionsleiste in einem Reiter (Mapping-Script, Verbindung testen):
   linksbuendig, eine Primaeraktion, Status rechts daneben in Mono. */
.vfAktionsleiste {
  gap: var(--vf-space-3, 10px);
  align-items: center;
  flex-wrap: wrap;
}
.vfAktionsleiste .vfAktionsStatus {
  font-size: 12px !important;
  color: var(--vf-text-tertiary, #556b82) !important;
  font-family: var(--vf-font-mono);
  margin-left: var(--vf-space-2, 8px);
}

/* Zweig-Tabelle im Routing-Panel (Handoff 09): Kopfzeile 11/700 Versalien
   auf der eingesunkenen Flaeche, Zeilen ruhig, Trennlinie hell. Drei
   Klassen tief, weil UI5 seine Kopfzellen mit zwei setzt (.sapMListTbl
   .sapMListTblHeaderCell) - gleiche Tiefe verloere (CLAUDE.md §4). */
.vfPanelRaster .vfZweigTabelle .sapMListTblHeaderCell {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--vf-text-tertiary, #556b82);
  background: var(--vf-surface-sunk, #f5f6f7);
}
.vfPanelRaster .vfZweigTabelle .sapMListTblCell {
  border-bottom: 1px solid var(--vf-border-subtle, #eef1f4);
  padding-top: 12px;
  padding-bottom: 12px;
}
.vfPanelRaster .vfZweigTabelle.sapMList {
  border: 1px solid var(--vf-border, #e1e5ea);
  border-radius: var(--vf-radius-md, 8px);
  overflow: hidden;
}
.vfZweigName {
  font-weight: 600;
}

/* ---- Dateizugriff (docs/architecture/dateizugriff.md) --------------------
   Verbindungsformular als Raster mit Label UEBER dem Feld (CLAUDE.md §4).
   Die Felder sind VBox mit renderType="Bare" - sonst stuende zwischen dem
   Raster und dem Feld ein .sapMFlexItem, und das Raster wuerde die Wrapper
   anordnen statt der Felder. Host und Startverzeichnis sind breiter, weil
   Hostnamen und Pfade laenger sind als ein Port. */
/* Mit .sapMFlexBox als zweitem Glied wie bei .vfPanelRaster: sonst gewinnt
   UI5s display:flex bei gleicher Staerke (im Browser gemessen, CLAUDE.md §4). */
.vfDzVerbindung.sapMFlexBox {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--vf-space-5) var(--vf-space-7);
  padding: var(--vf-space-5) var(--vf-space-7);
}
.vfDzFeld {
  display: flex;
  flex-direction: column;
  gap: var(--vf-space-2);
  min-width: 0;
}
.vfDzFeldBreit {
  grid-column: span 2;
}
.vfDzAktionen {
  gap: var(--vf-space-5);
  padding: 0 var(--vf-space-7) var(--vf-space-5);
}
.vfDzPfad {
  flex-wrap: wrap;
  min-width: 0;
}
.vfDzIcon {
  color: var(--vf-text-muted);
}
.vfDzFuss {
  padding: var(--vf-space-4) var(--vf-space-5);
  border-top: 1px solid var(--vf-border);
}

/* Bedingung testen (zweig-bedingungen.md Abschnitt 7): Abstand zwischen den
   Stuecken des Dialogs, damit Bedingung, Nachricht und Ergebnis als drei
   Schritte lesbar sind statt als ein Block. Flex mit gap statt Margins an den
   Kindern - CLAUDE.md Abschnitt 4. */
.vfBedingungTest {
  display: flex;
  flex-direction: column;
  gap: var(--vf-space-3);
  padding: var(--vf-space-2) 0;
}

/* Keystore mit zwei Reitern (vertrauensspeicher.md): die Reiterleiste sitzt
   am Rand des Arbeitsbereichs, nicht in einer eigenen Karte - sonst steht
   eine Karte in einer Karte, sobald der Inhalt selbst eine ist. */
.vfKeystoreTabs > .sapMITH {
  padding-left: 0;
  padding-right: 0;
}
.vfKeystoreTabs .sapMITBContentSection {
  padding: 0;
}

/* "Vom Server holen" (vertrauensspeicher.md 8.2): der Fingerabdruck ist der
   EINZIGE Schritt, der einen Mittelsmann ausschliesst - also steht er lesbar
   da und nicht als Kleingedrucktes. Umbruch mitten im Wert, weil ein SHA-256
   95 Zeichen hat und sonst den Dialog sprengt. */
.vfCaFingerprint {
  font-size: var(--vf-fs-sm);
  color: var(--vf-text);
  overflow-wrap: anywhere;
  margin-top: var(--vf-space-2);
}

/* Das Glied, das vFlow vorschlaegt - abgesetzt, damit die Empfehlung nicht
   in einer Liste gleich aussehender Karten untergeht. */
.vfCaVorschlag {
  border-color: var(--vf-primary);
}

/* ---- vFlow Pulse (P7) ---------------------------------------------------- */
/* Eingabe + Knopf bzw. Knopfreihe: Abstand per gap statt Margins (CLAUDE.md §4). */
.vfPulseZeile,
.vfPulseKnoepfe {
  gap: var(--vf-space-2);
}
