/* ====================================================================
   IVV Inventur-Scan - mobile-first Grundlayout.
   Basis-Styles fuer schmale Viewports zuerst, ab 900px zusaetzliche
   Desktop-Regeln (dauerhafte Sidebar statt Burger/Bottombar).
   ==================================================================== */

:root {
	--color-brand: #1D4ED8;
	--color-brand-dark: #1E3A8A;
	--color-ok: #16A34A;
	--color-err: #DC2626;
	--color-warn: #D97706;
	--color-neutral: #1F2937;
	--color-bg: #F3F4F6;
	--color-card: #FFFFFF;
	--color-border: #E5E7EB;
	--color-text: #111827;
	--color-text-muted: #6B7280;
	--radius: 10px;
	--safe-bottom: env(safe-area-inset-bottom, 0px);
	--safe-top: env(safe-area-inset-top, 0px);
	--bottombar-height: 52px; /* nur Icons, siehe .bottombar - auf Desktop ungenutzt (bottombar ausgeblendet) */
}

/* ====================================================================
   hidden muss IMMER gewinnen.

   Das hidden-Attribut wirkt nur ueber ein display:none aus dem
   Browser-Standard - und jede eigene display-Regel auf einer Klasse
   schlaegt das. Ein Element mit hidden bleibt dann sichtbar, obwohl der
   Code sauber el.hidden = true setzt. Der Fehler ist im JavaScript nicht
   zu sehen und entsprechend muehsam zu finden.

   Am 15.09.2026 gleich dreimal aufgetreten: die Auswahl-Leiste stand im
   Reiter "Fehlend", wo es nichts auszuwaehlen gibt; der Knopf "Mehr laden"
   in der Geraetedatenbank war immer da; und die Fehlerzeile im
   Hinweis-Streifen ebenso. Frueher wurde das je Klasse einzeln geflickt
   (siehe .ivv-puffer-banner) - diese eine Regel erledigt die ganze
   Gattung. tests/css-vars.test.js prueft, dass sie stehen bleibt.
   ==================================================================== */
[hidden] { display: none !important; }


* { box-sizing: border-box; }

/* Kein Doppeltipp-Zoom. "manipulation" erlaubt Tippen und Scrollen,
   schaltet aber den Doppeltipp zum Zoomen ab - das entfernt nebenbei
   die 300ms-Verzoegerung, die manche Browser vor einem Klick abwarten,
   um auf einen zweiten Tipp zu pruefen. Auf einem Scanner, mit dem man
   Zeile fuer Zeile abarbeitet, ist das spuerbar. */
html { touch-action: manipulation; -webkit-text-size-adjust: 100%; }

html, body {
	margin: 0;
	padding: 0;
	height: 100%;
	background: var(--color-bg);
	color: var(--color-text);
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	-webkit-tap-highlight-color: transparent;
}

a { color: var(--color-brand); text-decoration: none; }

/* App-Shell nutzt bewusst KEIN 100vh/100dvh + overflow:hidden mehr - diese
   Kombination aus fixer Hoehe + intern gecapptem Scroll-Container ist auf
   aelteren Android-WebViews (z.B. TC26-Werksstand) beobachtet nicht
   zuverlaessig scrollbar (vermutlich Flexbox-min-height-0-Bug). Stattdessen
   scrollt ganz klassisch das Dokument/body - das funktioniert praktisch
   ueberall, auch auf sehr alten WebViews. Topbar/Bottombar bleiben per
   position:sticky/fixed sichtbar, siehe unten. */
.app-shell {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

/* --- Topbar --- */
.topbar {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: calc(10px + var(--safe-top)) 14px 10px;
	background: var(--color-neutral);
	color: #fff;
	position: sticky;
	top: 0;
	z-index: 25;
}
.topbar .burger-btn {
	background: none;
	border: none;
	color: #fff;
	font-size: 22px;
	padding: 4px 6px;
	cursor: pointer;
	display: inline-flex;
}
.topbar .app-title {
	font-weight: 600;
	font-size: 1.05em;
	flex: 1;
}
.topbar .app-title small {
	display: block;
	font-weight: 400;
	font-size: 0.7em;
	color: #cbd5e1;
}

/* --- Content --- */
.content {
	flex: 1 1 auto;
	overflow-x: hidden;
	/* Platz fuer die fixe Bottombar reservieren (die liegt ausserhalb des
	   Dokumentflusses, siehe .bottombar), sonst verdeckt sie den letzten
	   Bildschirminhalt. --bottombar-height wird unten definiert. */
	padding: 14px 14px calc(14px + var(--bottombar-height) + var(--safe-bottom));
}

/* --- Sidebar (Drawer, mobile) --- */
.sidebar-overlay {
	position: fixed;
	inset: 0;
	background: rgba(0,0,0,0.45);
	z-index: 40;
}
.sidebar {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	width: 260px;
	max-width: 82vw;
	background: var(--color-neutral);
	color: #fff;
	z-index: 50;
	display: flex;
	flex-direction: column;
	padding: calc(14px + var(--safe-top)) 0 calc(14px + var(--safe-bottom));
	transform: translateX(-100%);
	transition: transform 0.2s ease;
}
.sidebar.open { transform: translateX(0); }
.sidebar-header {
	padding: 0 16px 14px;
	font-weight: 700;
	font-size: 1.1em;
	border-bottom: 1px solid rgba(255,255,255,0.12);
	margin-bottom: 8px;
}
.sidebar-header small { display: block; font-weight: 400; color: #94a3b8; font-size: 0.75em; }
.sidebar nav { display: flex; flex-direction: column; flex: 1; overflow-y: auto; }
.sidebar a, .sidebar button.sidebar-link {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 12px 16px;
	color: #e5e7eb;
	font-size: 0.98em;
	background: none;
	border: none;
	text-align: left;
	width: 100%;
	cursor: pointer;
}
.sidebar a i, .sidebar button.sidebar-link i { width: 20px; text-align: center; opacity: 0.85; }
.sidebar a.active, .sidebar button.sidebar-link.active { background: rgba(255,255,255,0.1); color: #fff; }
.sidebar a:hover, .sidebar button.sidebar-link:hover { background: rgba(255,255,255,0.06); }
.sidebar .sidebar-footer { border-top: 1px solid rgba(255,255,255,0.12); padding-top: 8px; margin-top: 8px; }

/* --- Bottombar (mobile): position:fixed statt sticky-in-flex, damit sie
   auch dann zuverlaessig sichtbar bleibt, wenn (wie auf manchen aelteren
   Android-WebViews beobachtet) die umgebende Flexbox-Hoehenberechnung
   nicht mitspielt - fixed ist relativ zum Viewport und unabhaengig davon.
   Nur Icons (kein Text), siehe partials/footer.php. --- */
.bottombar {
	display: flex;
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 30;
	/* Hoehe MUSS den Safe-Area-Bereich mit einrechnen. Wegen
	   "* { box-sizing: border-box }" weiter oben zieht ein
	   padding-bottom sonst von der angegebenen Hoehe ab: Auf einem
	   iPhone sind das rund 34px Home-Indicator, von 52px blieben also
	   nur ~18px fuer die Icons uebrig - die Leiste wirkt abgeschnitten.
	   Auf Android ist der Inset 0, dort fiel es nicht auf. */
	height: calc(var(--bottombar-height) + var(--safe-bottom));
	background: var(--color-neutral);
	border-top: 1px solid rgba(255,255,255,0.08);
	padding-bottom: var(--safe-bottom);
}
.bottombar a {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	color: #94a3b8;
}
.bottombar a i { font-size: 20px; }
.bottombar a.active { color: #fff; }

/* --- Karten / Buttons / Formulare --- */
.card {
	background: var(--color-card);
	border: 1px solid var(--color-border);
	border-radius: var(--radius);
	padding: 14px;
	margin-bottom: 12px;
}
.card h2, .card h3 { margin-top: 0; }

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	border: none;
	border-radius: var(--radius);
	background: var(--color-brand);
	color: #fff;
	font-size: 1em;
	padding: 11px 18px;
	cursor: pointer;
}
.btn:hover { background: var(--color-brand-dark); }
.btn.btn-secondary { background: #E5E7EB; color: var(--color-text); }
.btn.btn-danger { background: var(--color-err); }
.btn.btn-ok { background: var(--color-ok); }
.btn.btn-block { width: 100%; }
.btn:disabled { opacity: 0.6; cursor: not-allowed; }
.btn-sm { padding: 6px 10px; font-size: 0.85em; }

.form-group { margin-bottom: 14px; }
.form-group label { display: block; font-weight: 600; margin-bottom: 5px; font-size: 0.92em; }
.form-group input[type=text],
.form-group input[type=password],
.form-group input[type=email],
.form-group input[type=number],
.form-group input[type=date],
.form-group select,
.form-group textarea {
	width: 100%;
	padding: 11px 12px;
	border: 1px solid var(--color-border);
	border-radius: 8px;
	/* Mindestens 16px: iOS zoomt beim Antippen eines Eingabefeldes
	   automatisch hinein, wenn die Schrift kleiner ist - und zoomt
	   danach nicht von selbst zurueck. Das laesst sich nicht abschalten,
	   nur vermeiden. */
	font-size: 16px;
	background: #fff;
}
/* Gilt auch fuer die Felder ausserhalb von .form-group (Suchfelder,
   Mailempfaenger), aus demselben Grund. */
input[type=text], input[type=password], input[type=email],
input[type=number], input[type=search], select, textarea { font-size: 16px; }
.form-row { display: flex; gap: 10px; flex-wrap: wrap; }
.form-row .form-group { flex: 1; min-width: 140px; }

/* --- Banner / Inline-Hinweise (kein Toast-System, alles inline) --- */
.banner {
	border-radius: var(--radius);
	padding: 11px 14px;
	margin-bottom: 14px;
	font-size: 0.95em;
}
.banner.ok { background: #DCFCE7; color: #166534; border: 1px solid #86EFAC; }
.banner.err { background: #FEE2E2; color: #991B1B; border: 1px solid #FCA5A5; }
.banner.info { background: #DBEAFE; color: #1E40AF; border: 1px solid #93C5FD; }
.banner.warn { background: #FEF3C7; color: #92400E; border: 1px solid #FDE68A; }

/* --- Tabelle --- */
.table-wrap { overflow-x: auto; }
table.ivv-table { width: 100%; border-collapse: collapse; font-size: 0.92em; }
table.ivv-table th, table.ivv-table td { padding: 8px 10px; border-bottom: 1px solid var(--color-border); text-align: left; white-space: nowrap; }
table.ivv-table th { color: var(--color-text-muted); font-weight: 600; font-size: 0.85em; text-transform: uppercase; }
/* Zusaetzlich gefundenes, nicht auf der Lager-Liste stehendes Geraet im
   Tab "Erfasst" (siehe renderErfasstTable() in session-detail.php) */
table.ivv-table tr.ivv-row-zusatz td { background: #FEF2F2; }

/* Aktionsspalte bleibt beim seitlichen Scrollen stehen.
   Auf einem Handscanner sind die Tabellen breiter als der Bildschirm,
   und der Loeschen-Knopf steht ganz rechts - man musste also erst nach
   rechts wischen, um ihn ueberhaupt zu sehen. Mit sticky klebt die
   letzte Spalte am rechten Rand und ist immer erreichbar.
   Greift nur, wenn die letzte Zelle als Aktionsspalte markiert ist
   (class="ivv-col-aktion"), damit normale Datenspalten nicht
   versehentlich festkleben. */
table.ivv-table th.ivv-col-aktion,
table.ivv-table td.ivv-col-aktion {
	position: sticky;
	right: 0;
	background: var(--color-card);
	/* Kante nach links, damit man sieht, dass darunter weitergescrollt
	   wird und die Spalte nicht einfach angewachsen ist. */
	box-shadow: -6px 0 6px -4px rgba(0,0,0,0.12);
	text-align: right;
}
table.ivv-table tr.ivv-row-zusatz td.ivv-col-aktion { background: #FEF2F2; }

/* Zeile, die gerade geloescht werden soll (Rueckfrage laeuft) oder fuer das
   Sammel-Loeschen ausgewaehlt ist. Deutlich kraeftiger als die zarte
   Zusatzfund-Markierung darueber - hier geht es darum, VOR dem Loeschen zu
   sehen, welche Zeile gemeint ist. Die klebende Aktionsspalte braucht
   dieselbe Regel nochmal, sonst bleibt sie beim seitlichen Scrollen weiss. */
table.ivv-table tr.ivv-row-loeschen td,
table.ivv-table tr.ivv-row-loeschen td.ivv-col-aktion {
	background: #FEE2E2;
	box-shadow: inset 0 0 0 9999px rgba(220,38,38,0.06);
}
.ivv-liste-zeile.ivv-row-loeschen { background: #FEE2E2; }

/* Auswahlkaestchen in der Aktionsspalte. Groesser als der Browser-Standard -
   auf dem Handscanner trifft man 13px mit dem Finger nicht. */
.ivv-auswahl {
	width: 20px;
	height: 20px;
	vertical-align: middle;
	cursor: pointer;
	accent-color: var(--color-brand);
}

/* Leiste ueber der Tabelle, sobald etwas ausgewaehlt ist. */
.ivv-auswahl-leiste {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	margin-bottom: 8px;
	padding: 8px 10px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius);
	background: var(--color-bg);
}
/* Fehlend-Tab (session-detail.php): Zeile oeffnet per Klick das
   Ergebnisfenster. */
table.ivv-table tr.ivv-row-klickbar { cursor: pointer; }
table.ivv-table tr.ivv-row-klickbar:active td { background: var(--color-bg); }

/* ------------------------------------------------------------------
   Listenzeilen statt Tabelle.

   Fuer Uebersichten, die auf einem schmalen Display gelesen werden
   sollen: Statt Spalten, die seitlich hinauslaufen, bekommt jeder
   Eintrag einen Block - Hauptangabe oben, Nebenangaben klein darunter,
   Aktionen rechts und immer sichtbar. Kein seitliches Scrollen.
   ------------------------------------------------------------------ */
.ivv-liste { display: flex; flex-direction: column; }
.ivv-liste-zeile {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 10px 0;
	border-bottom: 1px solid var(--color-border);
}
.ivv-liste-zeile:last-child { border-bottom: 0; }
.ivv-liste-haupt { flex: 1 1 auto; min-width: 0; }
/* min-width:0 ist noetig, damit lange Werte umbrechen statt den Block
   aufzublaehen und die Aktionen hinauszuschieben. */
.ivv-liste-titel { font-weight: 600; word-break: break-word; }
.ivv-liste-oeffnen { display: block; color: inherit; text-decoration: none; }
.ivv-liste-oeffnen:active { background: var(--color-bg); }
.ivv-liste-name-eingabe {
	padding: 5px 8px;
	border: 1px solid var(--color-border);
	border-radius: 6px;
	font-size: 0.95em;
	font-weight: 600;
	max-width: 220px;
}
.ivv-liste-neben { font-size: 0.82em; color: var(--color-text-muted); margin-top: 2px; word-break: break-word; line-height: 1.35; }
/* Scanliste: Anzeigename (ServiceNow) als erste Nebenzeile, etwas kraeftiger als der Rest. */
.ivv-liste-anzeigename { color: var(--color-text); }
.ivv-liste-aktion { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; }
.ivv-liste-zahl { font-variant-numeric: tabular-nums; white-space: nowrap; }
.ivv-liste-haupt-klickbar { cursor: pointer; }
/* --- Kompakte Listendarstellung mit frei gewaehlten Spalten (A9) --- */
/* Ein Feld je "Beschriftung Wert"-Paar. inline-block, damit ein langer
   Wert nicht mitten im Feldnamen umbricht - dann stuende die
   Beschriftung am Ende der einen und der Wert am Anfang der naechsten
   Zeile, was auf 360 Pixeln kaum noch zu lesen ist. */
.ivv-liste-feld { display: inline-block; }
.ivv-liste-label { opacity: 0.7; }
/* Die Bemerkung bekommt eine eigene, volle Zeile: Sie ist ein
   Eingabefeld und muss mit Handschuhen zu treffen sein, egal an welcher
   Position in der Spaltenauswahl sie steht. */
.ivv-liste-bemerkung { margin-top: 6px; }
.ivv-liste-bemerkung .ivv-inline-edit { width: 100%; }

/* --- Trefferzahl ueber der Liste (0.27.0) --- */
.ivv-liste-anzahl {
	font-size: 0.85em;
	color: var(--color-text-muted);
	padding-bottom: 6px;
	font-variant-numeric: tabular-nums;
}

/* --- Zahlen je Spalte im Zuordnungsschritt (0.25.0) --- */
.mapping-stat { margin-top: 4px; font-size: 0.8em; color: var(--color-text-muted); line-height: 1.4; }
.mapping-stat-zahlen { display: block; font-variant-numeric: tabular-nums; }
.mapping-stat-beispiel { display: block; font-style: italic; word-break: break-word; }
.mapping-stat-warnung { margin-top: 6px; font-style: normal; }

/* --- Sortieren und Spaltenbreiten (0.22.0) --- */
.ivv-th-sort { position: relative; cursor: pointer; user-select: none; -webkit-user-select: none; }
.ivv-th-sort:hover { background: var(--color-bg); }
.ivv-th-aktiv { font-weight: 700; }
.ivv-th-text { display: inline-block; padding-right: 10px; }
/* Der Griff liegt am rechten Rand der Ueberschrift. 10px breit statt
   der uebliche 4px-Strich: Mit dem Finger oder mit Handschuhen waere
   ein Haarstrich nicht zu treffen. touch-action:none, sonst scrollt
   Android beim Ziehen die Seite statt die Spalte zu verbreitern. */
.ivv-th-griff {
	position: absolute;
	top: 0;
	right: 0;
	width: 10px;
	height: 100%;
	cursor: col-resize;
	touch-action: none;
}
.ivv-th-griff:hover { background: var(--color-brand); opacity: 0.35; }

/* Eingestellte Breiten wirken nur mit fester Tabellenaufteilung - sonst
   rechnet der Browser nach Inhalt und ignoriert die Vorgabe. Deshalb
   auch das Abschneiden: Wer eine Spalte schmal zieht, will sie schmal
   haben und nicht dreizeilig umgebrochen. Ohne eingestellte Breite
   bleibt alles wie bisher. */
.ivv-table-breiten { table-layout: fixed; }
.ivv-table-breiten td, .ivv-table-breiten th { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ivv-table-breiten td .ivv-inline-edit { width: 100%; min-width: 0; }

/* Sortierleiste der kompakten Darstellung (auf dem Handscanner gibt es
   keine Ueberschrift zum Anklicken). */
.ivv-sortleiste {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-wrap: wrap;
	padding: 6px 0 10px;
	font-size: 0.85em;
	color: var(--color-text-muted);
}
.ivv-sortleiste select {
	padding: 6px 8px;
	border: 1px solid var(--color-border);
	border-radius: 8px;
	background: #fff;
	max-width: 190px;
}

/* --- Spalten-Dialog --- */
.ivv-spalten-box { max-width: 480px; }
.ivv-spalten-kopf { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.ivv-spalten-hinweis { margin: 6px 0 10px; font-size: 0.85em; }
.ivv-spalten-liste { max-height: 55vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.ivv-spalten-gruppe {
	font-size: 0.8em;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--color-text-muted);
	margin: 12px 0 4px;
}
.ivv-spalten-zeile {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	padding: 6px 0;
	border-bottom: 1px solid var(--color-border);
}
.ivv-spalten-zeile:last-child { border-bottom: 0; }
/* Grosse Kaestchen - dieselbe Begruendung wie beim Sammel-Loeschen:
   auf dem TC26 wird mit Handschuhen getippt. */
.ivv-spalten-zeile input[type="checkbox"] { width: 20px; height: 20px; vertical-align: middle; }
.ivv-spalten-zeile label { cursor: pointer; flex: 1 1 auto; min-width: 0; }
.ivv-spalten-pfeile { flex: 0 0 auto; white-space: nowrap; }
.ivv-spalten-fuss {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	flex-wrap: wrap;
	margin-top: 14px;
	padding-top: 12px;
	border-top: 1px solid var(--color-border);
}
.ivv-spalten-fuss-rechts { white-space: nowrap; }
.ivv-liste-haupt-klickbar:active { background: var(--color-bg); }

/* --- Badges / Status --- */
.badge { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 0.78em; font-weight: 600; }
.badge.ok { background: #DCFCE7; color: #166534; }
.badge.err { background: #FEE2E2; color: #991B1B; }
.badge.neutral { background: #E5E7EB; color: var(--color-text-muted); }
.badge.warn { background: #FEF3C7; color: #92400E; }

/* --- Toggle Switch (Login-Methode) --- */
.toggle-switch { position: relative; display: inline-block; width: 46px; height: 26px; }
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider { position: absolute; inset: 0; background: #cbd5e1; border-radius: 999px; cursor: pointer; transition: 0.15s; }
.toggle-slider::before { content: ""; position: absolute; width: 20px; height: 20px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: 0.15s; }
.toggle-switch input:checked + .toggle-slider { background: var(--color-brand); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(20px); }

/* Offline-Puffer-Banner. Sitzt ueber der unteren Leiste, damit es die
   Bedienung nicht verdeckt, faellt aber durch die Warnfarbe auf. Kein
   Wegklicken: Solange Scans offen sind, soll das sichtbar bleiben. */
.ivv-puffer-banner {
	position: fixed;
	left: 8px;
	right: 8px;
	bottom: calc(8px + var(--bottombar-height) + var(--safe-bottom));
	z-index: 40;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 6px;
	padding: 9px 12px;
	border-radius: var(--radius);
	background: #FEF3C7;
	color: #92400E;
	border: 1px solid #FCD34D;
	box-shadow: 0 3px 12px rgba(0,0,0,0.18);
	font-size: 0.9em;
	font-weight: 600;
}
/* Offline-Fundament Phase 4 (schlanke Variante): der Banner ist jetzt eine
   Spalte aus Zeilen statt einer einzelnen Zeile - .ivv-puffer-zeile traegt
   das bisherige Zeilen-Layout, damit eine zweite Zeile fuer abgelehnte
   Scans einfach mitwaechst statt eine zweite, ueberlappende fixe Box zu
   brauchen (beide haetten sich sonst denselben bottom-Wert geteilt). */
.ivv-puffer-zeile { display: flex; align-items: center; gap: 10px; }
.ivv-puffer-zeile .ivv-puffer-text { flex: 1 1 auto; min-width: 0; }
.ivv-puffer-zeile .btn { flex: 0 0 auto; }
.ivv-puffer-zeile-fehler { color: #7F1D1D; }
.ivv-puffer-zeile-fehler .fa-triangle-exclamation { color: #DC2626; }
.ivv-puffer-fehler-liste {
	border-top: 1px solid rgba(0,0,0,0.15);
	margin-top: 2px;
	padding-top: 6px;
	max-height: 160px;
	overflow-y: auto;
	font-weight: 400;
	font-size: 0.92em;
}
.ivv-puffer-fehler-liste ul { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.ivv-puffer-fehler-liste li { line-height: 1.3; }
/* Ohne diese Zeile gewinnt "display: flex" oben gegen das hidden-Attribut,
   und die Box bleibt IMMER sichtbar, egal was app.js setzt - genau der
   Fehler, den Soenke am 03.09. gemeldet hat (leerer Streifen, der nie
   verschwindet). */
.ivv-puffer-banner[hidden] { display: none; }
@media (min-width: 900px) {
	/* Auf dem Desktop gibt es keine untere Leiste. */
	.ivv-puffer-banner { bottom: 12px; left: auto; right: 12px; max-width: 380px; }
}

/* --- Modal (einzige Modal-Komponente der App: Schnellscan) --- */
.modal-overlay {
	position: fixed;
	inset: 0;
	background: rgba(0,0,0,0.5);
	display: flex;
	align-items: center;
	justify-content: center;
	/* Sicherheitsnetz: Sollte die Box doch einmal hoeher werden als der
	   sichtbare Bereich, scrollt wenigstens die Flaeche darum - sonst
	   waere der obere Teil unerreichbar. */
	overflow-y: auto;
	z-index: 60;
	padding: 16px;
}
.modal-box {
	background: #fff;
	border-radius: var(--radius);
	max-width: 420px;
	width: 100%;
	/* 85vh rechnet mit dem GROSSEN Viewport, also ohne die Adressleiste
	   des Browsers. Ist sie eingeblendet, wird die Box hoeher als der
	   sichtbare Bereich - der obere Teil rutscht hinaus und laesst sich
	   nicht zurueckscrollen. dvh rechnet mit dem tatsaechlich sichtbaren
	   Bereich; die vh-Zeile davor bleibt als Rueckfallwert. */
	max-height: 85vh;
	max-height: 85dvh;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
	padding: 18px;
	position: relative;
}

/* Laengere Inhalte (Hilfe): Kopf bleibt stehen, nur der Text scrollt.
   Sonst verliert man beim Scrollen Titel und Schliessen-Knopf. */
.modal-box-lang { display: flex; flex-direction: column; overflow: hidden; padding: 0; }
.modal-box-lang .modal-kopf {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	padding: 14px 16px;
	border-bottom: 1px solid var(--color-border);
	flex: 0 0 auto;
}
.modal-box-lang .modal-inhalt {
	padding: 12px 16px 16px;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
	flex: 1 1 auto;
	min-height: 0; /* ohne das schrumpft der Bereich nicht und scrollt nie */
}
.modal-close-inline {
	background: none;
	border: none;
	font-size: 1.5em;
	line-height: 1;
	color: var(--color-text-muted);
	cursor: pointer;
	padding: 0 4px;
	flex: 0 0 auto;
}

/* PDF-Betrachter: nutzt fast die ganze Flaeche statt der schmalen
   Standard-Modalbreite - ein PDF muss lesbar sein, nicht nur angedeutet.
   dvh zuerst probiert (siehe .modal-box weiter oben), vh als Rueckfall. */
.modal-box-pdf {
	max-width: 900px;
	width: 96vw;
	height: 92vh;
	height: 92dvh;
	max-height: none;
}
.modal-box-pdf .modal-inhalt { padding: 0; display: flex; }
/* Seitenbereich des PDF-Betrachters: scrollt selbst, dunkler Hintergrund
   wie in gaengigen PDF-Viewern, damit die weissen Seiten abgesetzt sind.
   Die Canvas-Breite setzt app.js (pdfSeitenRendern) auf clientWidth-16,
   der 8px-Rand hier muss dazu passen. */
.pdf-seiten {
	flex: 1 1 auto;
	overflow: auto;
	-webkit-overflow-scrolling: touch;
	background: #525659;
	padding: 8px;
	box-sizing: border-box;
	min-height: 0;
}
.pdf-seiten canvas.pdf-seite {
	display: block;
	margin: 0 auto 8px auto;
	background: #fff;
	box-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.pdf-status {
	color: #eee;
	text-align: center;
	padding: 32px 16px;
	font-size: 0.95em;
}
.pdf-status-fehler { color: #ffb4a8; }
/* Ablaufbalken im Schnellscan-Ergebnisfenster.
   Sitzt am oberen Rand des Fensters und laeuft von rechts nach links
   ab: Der Streifen ist links verankert, seine Breite geht von 100% auf
   0%, also wandert die rechte Kante nach links.

   Bewusst im normalen Fluss mit negativen Aussenabstaenden statt
   position:absolute - die .modal-box scrollt (overflow-y:auto), ein
   absolut gesetzter Balken wuerde also mitscrollen statt oben zu
   kleben. Bei einem kurzen Ergebnis scrollt ohnehin nichts.

   Rot und 6px hoch, damit man ihn auf einem Handscanner-Display bei
   Lagerbeleuchtung tatsaechlich wahrnimmt. Ein 3px-Streifen in
   Markenblau war dafuer zu unauffaellig. */
.modal-progress {
	height: 6px;
	margin: -18px -18px 14px;
	border-radius: var(--radius) var(--radius) 0 0;
	background: rgba(0,0,0,0.10);
	overflow: hidden;
}
.modal-progress-fill {
	height: 100%;
	width: 100%;
	background: var(--color-err);
}
/* Angehalten: deutlich abgesetzt in Grau, damit erkennbar ist, dass die
   Zeit steht und der Balken nicht bloss haengt. */
.modal-progress.paused .modal-progress-fill {
	background: var(--color-text-muted);
	opacity: 0.45;
}

/* ------------------------------------------------------------------
   Einstellungen: kompakte Zeilen statt einer Karte je Punkt.

   Vorher hatte jede Einstellung eine eigene Karte mit Ueberschrift,
   Erklaerungstext, Bedienelement und eigenem Speichern-Knopf - auf
   einem Handscanner musste man dafuer mehrfach scrollen, um vier
   Schalter zu sehen. Jetzt: eine Karte je Themenblock, darin
   Beschriftung links, Bedienelement rechts. Die Erklaerung steht klein
   darunter und nur, wo sie wirklich noetig ist; den Rest erklaert die
   Hilfe oben in der Kopfzeile.
   ------------------------------------------------------------------ */
.set-zeile {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 11px 0;
	border-bottom: 1px solid var(--color-border);
}
.set-zeile:last-child { border-bottom: 0; }
.set-zeile-text { flex: 1 1 auto; min-width: 0; }
.set-zeile-label { font-weight: 600; font-size: 0.95em; }
.set-zeile-hinweis { font-size: 0.8em; color: var(--color-text-muted); margin-top: 1px; }
.set-zeile-wert { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; }
.set-zeile-wert input[type=number] { width: 74px; padding: 6px 8px; border: 1px solid var(--color-border); border-radius: 8px; text-align: right; }
.set-zeile-wert .set-einheit { font-size: 0.85em; color: var(--color-text-muted); }

/* Zwei Beschriftungen links und rechts vom Schalter waren auf schmalen
   Displays der groesste Platzfresser. Der Schalter allein genuegt. */
.set-karte h3 { margin-bottom: 4px; }
/* Klappbloecke: Ueberschrift und Geltungsbereich in EINER Zeile - der
   Hinweis "gilt nur fuer dich" brauchte vorher eine eigene Zeile. */
.set-karte summary { cursor: pointer; }
.set-summary-hinweis { color: var(--color-text-muted); font-weight: 400; font-size: 0.82em; }
.set-karte details[open] summary { margin-bottom: 6px; }

/* Aenderungsverlauf: etwas mehr Luft zwischen den Versionen, damit die
   Bloecke auf dem schmalen Display auseinanderfallen. */
.changelog h3 { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--color-border); }
.changelog h3:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.changelog h4 { margin: 14px 0 4px; font-size: 0.95em; }
.changelog ul { margin: 4px 0 10px; padding-left: 20px; }
.changelog li { margin-bottom: 4px; }
.changelog p { margin: 6px 0; }
.changelog code { background: rgba(0,0,0,0.06); padding: 1px 5px; border-radius: 4px; font-size: 0.9em; }
.changelog hr { border: 0; border-top: 1px solid var(--color-border); margin: 18px 0; }

/* Hilfe-Fenster: Bedienelemente als Begriff/Erklaerung. Untereinander
   statt zweispaltig - auf einem schmalen Display bleibt fuer eine
   zweite Spalte kein Platz. */
.hilfe-felder { margin: 0; }
.hilfe-felder dt { font-weight: 600; font-size: 0.9em; margin-top: 9px; }
.hilfe-felder dd { margin: 1px 0 0; font-size: 0.88em; color: var(--color-text-muted); }

/* Uhrzeit/Netz/Akku in der Kopfzeile - schmale Icon-Badges, Platz ist auf
   einem Handscanner knapp. Zwischen Titel (schiebt per flex:1) und dem
   Hilfe-Fragezeichen. */
.topbar-status {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 0.78em;
	color: rgba(255,255,255,0.85);
	font-variant-numeric: tabular-nums;
}
.topbar-status .ivv-status-badge { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
.topbar-status .ivv-status-badge:empty { display: none; } /* z.B. Akku ohne Battery-API - kein leerer Abstand */
.topbar-status .ivv-status-err { color: #FCA5A5; }

/* Fragezeichen in der Kopfzeile. Sitzt ganz rechts, der Titel schiebt
   es per margin-left:auto dorthin. */
.topbar-help {
	margin-left: auto;
	background: none;
	border: 0;
	color: rgba(255,255,255,0.75);
	font-size: 18px;
	line-height: 1;
	padding: 6px 4px;
	cursor: pointer;
}
.topbar-help:hover { color: #fff; }

.modal-close {
	position: absolute;
	top: 10px;
	right: 10px;
	background: none;
	border: none;
	font-size: 1.4em;
	color: var(--color-text-muted);
	cursor: pointer;
}

/* --- Scan-Feedback-Overlay (grosser Haken / X, selbst-schliessend) --- */
.scan-feedback-overlay {
	position: fixed;
	inset: 0;
	/* Ueber dem Kamerafenster (z-index 80): im Dauermodus (A6) geht die
	   Kamera nach 1,2 s wieder auf, waehrend die Rueckmeldung noch steht -
	   die muss sichtbar bleiben, sonst sieht man das Ergebnis nicht. */
	z-index: 90;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	gap: 14px;
	color: #fff;
	pointer-events: none;
}
.scan-feedback-overlay.ok { background: rgba(22,163,74,0.94); }
.scan-feedback-overlay.err { background: rgba(220,38,38,0.94); }
/* Doppelscan: weder gruen (waere "sauber erfasst") noch rot (waere
   "abgelehnt") - das Geraet ist in Ordnung, war nur schon dabei. */
.scan-feedback-overlay.dup { background: rgba(217,119,6,0.94); }
.scan-feedback-overlay i { font-size: 5em; }
.scan-feedback-overlay .sf-text { font-size: 1.2em; font-weight: 600; text-align: center; padding: 0 20px; }

/* --- Fortschrittsanzeige --- */
.progress-bar { background: #E5E7EB; border-radius: 999px; height: 10px; overflow: hidden; }
.progress-bar > div { background: var(--color-ok); height: 100%; transition: width 0.2s; }

/* --- Utility --- */
.text-muted { color: var(--color-text-muted); }
.text-center { text-align: center; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.flex { display: flex; }
.flex-between { display: flex; justify-content: space-between; align-items: center; }
.gap-8 { gap: 8px; }
.stat-row { display: flex; gap: 10px; flex-wrap: wrap; }
.stat-tile { flex: 1; min-width: 100px; background: var(--color-card); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 12px; text-align: center; }
.stat-tile .stat-num { font-size: 1.6em; font-weight: 700; }
.stat-tile .stat-label { font-size: 0.78em; color: var(--color-text-muted); text-transform: uppercase; }
/* Verlinkte Kacheln (Dashboard): sollen wie die normalen aussehen, aber
   erkennbar antippbar sein. */
a.stat-tile { display: block; color: inherit; text-decoration: none; transition: border-color 0.15s, transform 0.05s; }
a.stat-tile:hover { border-color: var(--color-brand); }
a.stat-tile:active { transform: scale(0.98); }

/* Listeneintraege, die zu einer Detailseite fuehren (Dashboard) - ohne
   sichtbaren Hinweis haelt man sie leicht fuer reinen Text. */
.list-link { display: block; color: inherit; text-decoration: none; padding: 10px 0; border-bottom: 1px solid var(--color-border); }
.list-link:active { background: var(--color-bg); }
.list-link .list-link-chevron { color: var(--color-text-muted); font-size: 0.8em; margin-left: 8px; }

/* --- Spalten-Mapping (Import) --- */
.mapping-layout { display: flex; flex-direction: column; gap: 18px; }
.mapping-preview .table-wrap { max-height: 320px; overflow-y: auto; }
.mapping-fields { display: flex; flex-direction: column; gap: 10px; }
.mapping-field label { font-size: 0.88em; }
.mapping-field select {
	width: 100%;
	padding: 9px 10px;
	border: 1px solid var(--color-border);
	border-radius: 8px;
	font-size: 0.95em;
	background: #fff;
}

.qr-panel { padding: 12px 4px; }

/* Dropzone bewusst flach: Sie ist nicht der Hauptzweck der Seite,
   sondern eine gelegentliche Aktion. Ziehen UND Antippen funktionieren
   unveraendert, die Flaeche bleibt mit ~64px Hoehe bequem zu treffen. */
.dropzone {
	border: 2px dashed var(--color-border);
	border-radius: var(--radius);
	padding: 14px;
	text-align: center;
	color: var(--color-text-muted);
	cursor: pointer;
	background: #fafafa;
	font-size: 0.92em;
}
.dropzone i { font-size: 1.2em; margin-right: 6px; }

/* --- "X" zum Leeren von Such- und Scanfeldern ---
   Die Layout-Angaben (Breite, flex) sitzen am Wrapper, das Feld selbst
   fuellt ihn aus. Der rechte Innenabstand haelt den Text vom Knopf weg.
   Der Knopf erscheint nur, wenn wirklich etwas drinsteht. */
.input-clear-wrap { position: relative; display: block; }
.input-clear-wrap > input { width: 100%; padding-right: 36px; }
.input-clear {
	position: absolute;
	right: 6px;
	top: 50%;
	transform: translateY(-50%);
	width: 26px;
	height: 26px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(0,0,0,0.06);
	color: var(--color-text-muted);
	font-size: 13px;
	line-height: 1;
	cursor: pointer;
	display: none;
}
.input-clear.visible { display: inline-flex; align-items: center; justify-content: center; }
.input-clear:hover { background: rgba(0,0,0,0.14); }
.dropzone.dragover { border-color: var(--color-brand); background: #EFF6FF; color: var(--color-brand); }

/* ==================================================================
   Desktop-Breakpoint: dauerhafte Sidebar statt Burger/Bottombar.
   ================================================================== */
@media (min-width: 900px) {
	.app-shell { flex-direction: row; }
	.topbar .burger-btn { display: none; }
	.sidebar {
		position: static;
		transform: none;
		width: 240px;
		flex: 0 0 240px;
	}
	.sidebar-overlay { display: none; }
	.main-col { display: flex; flex-direction: column; flex: 1; min-width: 0; }
	.bottombar { display: none; }
	.content { padding: 20px 24px; }
	.two-col { display: flex; gap: 18px; align-items: flex-start; }
	.two-col > * { flex: 1; min-width: 0; }
	.modal-box { max-width: 520px; }

	/* Desktop-Bedienung fuer Import-Mapping und Userverwaltung (werden
	   typischerweise am Schreibtisch erledigt, nicht am Scanner-Display,
	   siehe Nutzerfeedback) - Vorschau/Mapping nebeneinander statt
	   gestapelt, Karten nicht auf volle Breite strecken. */
	.mapping-layout { flex-direction: row; align-items: flex-start; }
	.mapping-preview { flex: 1.4; min-width: 0; }
	.mapping-select { flex: 1; min-width: 260px; }
	.card.card-narrow { max-width: 640px; }
}

/* Mailversand in der Listenansicht: Formatwahl (PDF/Excel/Beides) als
   Knopfleiste - das Radio selbst bleibt unsichtbar, der gewaehlte Knopf
   wird ueber :has() hervorgehoben. Browser ohne :has() zeigen einfach
   die Radios sichtbar an - funktioniert, sieht nur weniger huebsch aus. */
.mail-format-wahl { cursor: pointer; }
.mail-format-wahl:has(input:checked) { background: var(--color-brand); color: #fff; border-color: var(--color-brand); }
.mail-format-wahl:has(input) input { position: absolute; opacity: 0; width: 0; height: 0; }

/* Anklickbare Werte in Listen. Frueher <a href="#"> - das sah zwar richtig
   aus, machte den Wert auf Android aber unmarkierbar: Ein langes Antippen
   auf einem Link oeffnet dort das Link-Kontextmenue statt Text zu
   markieren. Als <span> laesst sich der Wert normal markieren und kopieren
   (Wunsch Soenke, 15.09.2026), der Klick haengt weiterhin am Element. */
/* Kopier-Knopf hinter Kennungen (Asset-Tag/Seriennummer). Bewusst
   zurueckhaltend: grau und klein, damit die Tabelle ruhig bleibt - aber mit
   genug Flaeche, um ihn auf dem Handscanner mit dem Finger zu treffen. */
.ivv-kopier {
	border: 0;
	background: none;
	padding: 2px 5px;
	margin-left: 2px;
	color: var(--color-text-muted);
	cursor: pointer;
	font-size: 0.9em;
	line-height: 1;
	vertical-align: baseline;
}
.ivv-kopier:hover { color: var(--color-brand); }
.ivv-kopier-ok { color: var(--color-ok); }
.ivv-kopier-fehler { color: var(--color-err); }

/* Zaehlerstand in der Inventurliste. Frueher ein .badge - das ist mit
   padding 2px/9px und 0.78em deutlich kleiner als der .btn-sm daneben
   (6px/10px, 0.85em) und sah neben "Neu zaehlen" verrutscht aus. Gleiche
   Masse wie ein Knopf, nur ohne Klick-Optik. */
.zaehler-stand {
	display: inline-block;
	padding: 6px 10px;
	font-size: 0.85em;
	font-weight: 700;
	line-height: 1.2;
	border: 1px solid var(--color-border);
	border-radius: var(--radius);
	background: var(--color-bg);
	color: var(--color-text);
}

.ivv-link {
	color: var(--color-brand);
	text-decoration: underline;
	cursor: pointer;
}
