/*
 * Warstwa wizualna wg iOS HIG (clarity, deference, depth) i zlotego podzialu.
 * Skala odstepow to ciag Fibonacciego 8/13/21/34/55 - stosunek sasiednich dazy do phi.
 * Zadnych wartosci posrednich: kazdy odstep w tym pliku pochodzi z tej piatki.
 * Typografia 13/17/28/34, gdzie 28 = 17 x 1,618.
 */

:root {
  --bg: #f2f2f7;
  --bg-elevated: #ffffff;
  --label: #1c1c1e;
  --label-secondary: #6c6c70;
  --separator: #d1d1d6;
  --accent: #1d6871;              /* turkus odczytany z icon-512.png */
  --accent-kontrast: #ffffff;
  --danger: #c00e0e;
  --ok: #1a7a3c;                  /* v.13.78: Kopf-Signalicon online, Kontrast ~4,8:1 auf --bg */
  --schatten: 0 1px 3px #0000000f;

  --s1: 8px;
  --s2: 13px;
  --s3: 21px;
  --s4: 34px;
  --s5: 55px;
  --radius: 13px;
}

/*
 * Ciemna paleta w DWOCH miejscach o tych samych wartosciach:
 *   - `@media` z wykluczeniem [data-theme="light"] - motyw systemowy, chyba ze uzytkownik
 *     jawnie wybral jasny (wtedy system NIE moze go nadpisac),
 *   - `:root[data-theme="dark"]` - jawny wybor "Dunkel", dziala takze przy jasnym systemie.
 * Wartosci sa identyczne; rozne sa wylacznie selektory.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #121316;
    --bg-elevated: #1c1c1e;
    --label: #d6d6d0;
    --label-secondary: #b8b8ae;
    --separator: #38383a;
    --accent: #5cc5d0;
    --accent-kontrast: #000000;
    --danger: #ff6961;
    --ok: #30d158;                /* v.13.78: Kontrast ~9,2:1 auf --bg dunkel */
    --schatten: none;
  }
}
:root[data-theme="dark"] {
  --bg: #121316;
  --bg-elevated: #1c1c1e;
  --label: #d6d6d0;
  --label-secondary: #b8b8ae;
  --separator: #38383a;
  --accent: #5cc5d0;
  --accent-kontrast: #000000;
  --danger: #ff6961;
  --ok: #30d158;
  --schatten: none;
}

* { box-sizing: border-box; }

/*
 * Atrybut `hidden` ma wygrywac ZAWSZE. Bez tej reguly przegrywa z kazda wlasna regula
 * niosaca `display` - i tak wlasnie dolny pasek trybu zaznaczania (.auswahl-leiste
 * ma display:flex) wisial na ekranie przez caly czas, mimo hidden=true. Monter widzial
 * pasek, uznawal ze tryb jest wlaczony, a tapniecie kafelka otwieralo podglad.
 * !important jest tu na miejscu: to nie lata na jeden przypadek, tylko przywrocenie
 * semantyki atrybutu z HTML-a.
 */
[hidden] { display: none !important; }

/*
 * `html` MUSI dostac to samo tlo co `body`. Inline w <head> ustawia #17181b, zeby nie bylo
 * bialego blysku przed style.css - ale reset dotad obejmowal wylacznie `body`, wiec `html`
 * zostawal ciemny na zawsze. W trybie jasnym widac to bylo jako czarna plama pod krotka
 * lista i przy odbiciu (rubber-band) w Safari na iOS.
 */
html { background: var(--bg); }

body {
  margin: 0;
  font: 17px/1.45 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  background: var(--bg);
  color: var(--label);
  -webkit-text-size-adjust: 100%;
}

/* ---------- pasek ---------- */

header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  min-height: 44px;
  padding: var(--s1) var(--s3);
  padding-top: calc(var(--s1) + env(safe-area-inset-top));
  padding-left: calc(var(--s3) + env(safe-area-inset-left));
  padding-right: calc(var(--s3) + env(safe-area-inset-right));
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(21px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease-out;
}
header.gescrollt { border-bottom-color: var(--separator); }

/* Tytul w pasku pojawia sie dopiero, gdy duzy tytul wyjedzie za gore. */
#crumb {
  font-size: 17px;
  font-weight: 600;
  opacity: 0;
  transition: opacity .25s ease-out;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* v.13.87: klasyczna pulapka flexboxa - bez min-width:0 flex-child z white-space:nowrap
     NIE moze scurczyc sie pod swoja naturalna (pelna) szerokosc tekstu, nawet niewidoczny
     (opacity:0 nie zeruje szerokosci layoutu) - .kopf-aktionen (z "..." na koncu) bylo
     wypychane za prawa krawedz ekranu na dlugich tytulach (np. screenBauRoh). */
  min-width: 0;
}
header.gescrollt #crumb { opacity: 1; }

/* v.9.34: powiekszone z 44px/21px - monterzy nie rozpoznawali ikony. Pole dotyku
   nadal min. 44x44 (wymog), ikona wizualnie ~32px. */
#aktion {
  flex: none;
  min-width: 48px;
  min-height: 48px;
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  box-shadow: none;                /* w pasku ma byc sama ikona, bez plyty przycisku */
  color: var(--accent);
  font-size: 32px;
  line-height: 1;
}

/* ---------- tresc ---------- */

main {
  max-width: 34rem;
  margin: 0 auto;
  padding: 0 var(--s3) calc(var(--s5) + env(safe-area-inset-bottom));
}

h1 {
  margin: var(--s2) 0 var(--s3);
  font-size: 34px;
  line-height: 1.15;
  letter-spacing: -.02em;
  font-weight: 700;
}

/* P2 (24.08): odsuniety od listy budow i wysrodkowany, nie przyklejony do kraweddzi. */
.neu-baustelle { display: block; width: fit-content; margin: var(--s4) auto 0; }

/* Strzalki poprzednie/nastepne pietro (v.9.34, FIX E) - min. 56px, na krancach wyszarzone. */
.sw-kopf { font-size: 17px; font-weight: 500; line-height: 1.3; }
.sw-kopf-zeile { width: 100%; min-height: 44px; font-size: 17px; font-weight: 500; line-height: 1.3; }
/* v.13.87: "‹ Zurück" + "Adresse · STG N" in EINER Zeile (vorher zwei getrennte Reihen +
   eigene Zurück-Zeile) - zurueck behaelt volle Breite (flex-shrink:0), die Adresse/Stiege
   schrumpft und bekommt Ellipsis (min-width:0 - dieselbe Flexbox-Falle wie bei #crumb). */
.sw-zeile1 { display: flex; align-items: center; gap: var(--s2); }
/* v.13.87: eigenes, engeres Padding NUR hier (globales button.leise.zurueck bleibt fuer
   die anderen zwei Vorkommen unveraendert) - Teil der Kompaktierung, min-height 44px bleibt. */
.sw-zeile1 .zurueck.leise { flex: none; padding: var(--s1) 0; }
/* .leise im Selektor noetig, um button.leise{font-weight:400} zu schlagen (Spezifitaet). */
.sw-adresse-stiege.leise {
  flex: 1 1 auto;
  min-width: 0;
  display: block;
  padding: 0;
  text-align: left;
  color: var(--label);
  background: none;
  box-shadow: none;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sw-titelzeile { display: flex; align-items: center; gap: var(--s1); }
.sw-titelzeile h1 { flex: 1; min-width: 0; text-align: center; cursor: pointer; }
/* v.12.98: Tap auf den Titel oeffnet die Stockwerk-Liste - Pfeil als Hinweis, nur per CSS (textContent bleibt). */
.sw-titelzeile h1::after { content: ' \25BE'; font-size: .8em; color: var(--accent); }
.sw-kopf h1 { margin: 0; font-size: 17px; font-weight: 700; line-height: 1.3; }
/* v.13.87: min-height 56->44px (Standard-Touch-Ziel) - Teil der Kompaktierung des
   Stockwerk-Kopfs (Tomasz: "5 Reihen, zu leer"), min-width bleibt fuer die breite Tap-Flaeche.
   Eigenes (kleineres) vertikales Padding - das globale button{padding:var(--s2) var(--s3)}
   machte den Knopf trotz min-height:44px real ~62px hoch (28px Schriftgroesse + 26px Padding). */
.sw-pfeil { flex: none; min-width: 56px; min-height: 44px; padding: 2px var(--s3); font-size: 28px; }
.sw-pfeil:disabled { opacity: .3; }

/* Naglowek sekcji w stylu grupowanej listy iOS. */
h2 {
  margin: var(--s3) 0 var(--s1);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--label-secondary);
}

/* v.15.72: naglowek grupy zdjec w zakladce Fotos = link do pietra. Wyglada jak h2 (ten sam
   krój i wersaliki), tylko w kolorze akcentu; 44px wysokosci dotyku jak reszta przyciskow. */
h2 > .foto-gruppe-link {
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: var(--accent);
  background: none;
  box-shadow: none;
  justify-content: flex-start;
}

/* ---------- listy grupowane ---------- */

ul {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--bg-elevated);
  border-radius: var(--radius);
  box-shadow: var(--schatten);
  overflow: hidden;
}

li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  min-height: 44px;
  padding: var(--s1) var(--s3);      /* bylo --s2 - gestsza lista, wiecej wierszy na ekranie */
  background: none;
  border: 0;
}
li strong { font-size: 15px; }

/* Tytul wysrodkowany - na razie tylko lista budow. */
h1.zentriert { text-align: center; }
.bauten-kopf { display: block; }
.bauten-kopf h1 { min-width: 0; overflow-wrap: anywhere; font-size: clamp(22px, 6.5vw, 34px); }
/* v.13.83: Suchfeld - Lupe per CSS (WebKit zeigt bei type=search keine eigene, nur den
   nativen x-Clear-Button, siehe Test), Eingabe bekommt links Platz dafuer. */
.bauten-suche-wrap { position: relative; margin: var(--s2) 0; }
.bauten-suche-wrap::before {
  content: '🔍';
  position: absolute; left: var(--s2); top: 50%; transform: translateY(-50%);
  font-size: 15px; opacity: .5; pointer-events: none;
}
.bauten-suche { padding-left: calc(var(--s2) + 15px + var(--s1)); }
.bauten-termine { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s2); width: 100%; margin: 0 0 var(--s2); padding: var(--s1) 0; color: var(--label); background: none; box-shadow: none; justify-content: flex-end; text-align: right; }
.bauten-termin { display: inline-flex; gap: var(--s1); }
.bauten-termin.vorbei { opacity: .55; }
.bauten-mehr { color: var(--accent); }
/* v.13.88 (D2c): Buchstaben-Ueberschrift (seit v.15.39 auf jeder Breite) - Optik
   wie h2 (Abschnittsueberschrift), obwohl technisch ein <li> (gueltige Listenstruktur, das
   Grid-Muster von .spalten oben braucht sie als <li>-Kind). */
.bauten-buchstabe {
  display: block;
  min-height: 0;
  padding: var(--s3) var(--s3) var(--s1);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--label-secondary);
  cursor: default;
}
li.bauten-buchstabe + li { box-shadow: none; }
/* v.15.39 (A): Gruppen-DOM auf jeder Breite - Buchstabe als klebende Abschnittsueberschrift
   ueber den Karten (wie Kontakte iOS), Karten volle Breite, Text links. Aussen-ul ohne
   overflow:hidden, sonst klebt sticky nicht. */
ul.bauten-gruppen { overflow: visible; background: transparent; box-shadow: none; }
ul.bauten-gruppen > li.leerzeile { background: var(--bg-elevated); border-radius: var(--radius); }
li.bauten-gruppe { display: block; padding: 0; min-height: 0; box-shadow: none; }
.bauten-gruppe > .bauten-buchstabe {
  position: sticky; top: var(--kopf-hoehe, 0px); z-index: 1;
  background: var(--bg);
}
.bauten-gruppe > ul { width: 100%; }
.bauten-gruppe > ul > li { justify-content: flex-start; text-align: left; }
/* Separator tylko MIEDZY wierszami i wciety od lewej - nie ramka wokol kazdego. */
li + li { box-shadow: inset 0 1px 0 var(--separator); }
li + li { background-clip: padding-box; }
ul.getrennt li + li { box-shadow: none; border-top: 1px solid var(--separator); margin-left: var(--s3); padding-left: 0; }

li .meta { color: var(--label-secondary); font-size: 13px; }

/* v.13.01: Zeile im Artikelkatalog - voller Name (kein Ellipsis: Tomasz beurteilt an ihm, ob der Artikel
   stimmt), rechts nur der Pfeil; die ganze Zeile ist der Knopf. */
li.katalog-zeile {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s2);
  padding-block: var(--s2);
  cursor: pointer;
}
.katalog-text { display: flex; flex-direction: column; min-width: 0; }
.katalog-name { overflow-wrap: anywhere; }
.katalog-pfeil { color: var(--label-secondary); font-size: 22px; line-height: 1; }
li.katalog-zeile.ausgeblendet .katalog-name { color: var(--label-secondary); }
.qty { display: inline-flex; align-items: center; justify-content: center;
  min-width: 56px; min-height: 44px; padding: 0; text-align: center;
  font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums;
  border: 1px solid var(--accent); border-radius: 6px; background: var(--bg-elevated);
  box-shadow: none; color: var(--label); }
/* Reczny wpis ilosci (v.9.32) - tapniecie w liczbe zamiast klikania +/- wielokrotnie. */
.qty-edit { min-width: 56px; min-height: 44px; padding: 0; text-align: center;
  font: inherit; font-weight: 600; font-variant-numeric: tabular-nums;
  border: 1px solid var(--accent); border-radius: 6px; background: var(--bg-elevated);
  box-shadow: none; color: var(--label); }
/* v.13.77: `.qty-edit` erbt sonst `input { width: 100% }` - im Materialzeile-Grid presst das
   den Artikelnamen auf 1-2 Zeichen pro Zeile. Breite = button.qty (Zeile oben). */
.qty-edit { width: 3.5rem; flex: 0 0 auto; }
.row { display: flex; gap: var(--s1); align-items: center; }

/* v.11.41: Baustellen verwalten - Zeile untereinander statt nebeneinander, Feld auf
   voller Breite, Daumen-Bedienung am Telefon (Zgloszenie Tomasza 13.09). */
.baustellen-verwalten-zeile { flex-direction: column; align-items: stretch; gap: var(--s1); }
.baustellen-verwalten-zeile label { margin: 0; }
.baustellen-verwalten-zeile .err:empty { display: none; }

/* ---------- przyciski ---------- */

button, .knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  min-height: 44px;
  padding: var(--s2) var(--s3);
  font: inherit;
  font-weight: 500;
  color: var(--accent);
  background: var(--bg-elevated);
  border: 0;
  border-radius: var(--radius);
  box-shadow: var(--schatten);
  cursor: pointer;
  transition: opacity .25s ease-out;
}
button:active, .knopf:active { opacity: .55; }

/* ---------- splash ---------- */

/*
 * Stoi w HTML-u, wiec widac go od pierwszej klatki, zanim app.js zdazy cokolwiek zrobic.
 * Chowa go klasa `weg` z app.js: minimum 600 ms (zeby nie mrugnal), maksimum 1500 ms
 * (zeby nie blokowal pracy, gdyby siec padla). Tylko przy STARCIE - miedzy ekranami nie.
 */
#splash {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  background: #17181b;
  transition: opacity .35s ease-out;
}
/*
 * splash-mark.png: icon-512 przyciety o 33 px z kazdej strony (biale rogi i srebrna ramka
 * z projektu ikony) i przeskalowany do 320 px. 52 kB zamiast 426 kB - na budowie znak zdazy
 * sie doczytac w oknie splashu takze przy 400 kB/s.
 * 38,2% szerokosci ekranu to mniejsza czesc zlotego podzialu.
 */
#splash img {
  width: 38.2vw;
  max-width: 220px;
  height: auto;
  aspect-ratio: 1;
  border-radius: 22%;
}
/* Splash stoi zawsze na ciemnym tle, wiec podpis bierze akcent trybu CIEMNEGO:
   #1d6871 na #17181b dawal 2,77:1, ponizej progu WCAG AA. #5cc5d0 daje 8,75:1. */
#splash .splash-fuss { font-size: 13px; color: #5cc5d0; }
/* Numer wersji ma byc do odczytania, ale nie konkurowac z nazwa - stad 70% krycia. */
#splash .splash-version { font-size: 12px; color: #5cc5d0; opacity: .7; }
#splash.weg { opacity: 0; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  #splash { transition: none; }
}

/* ---------- marka ---------- */

.marke { display: flex; flex-direction: column; align-items: center; gap: var(--s2);
         margin: var(--s4) 0 var(--s3); }
.marke img { width: 89px; height: 89px; border-radius: var(--s2); }
.marke .wortmarke { font-size: 28px; font-weight: 700; letter-spacing: -.02em; }

/* Znak Gmerek IT - inline SVG na currentColor, wiec sam trafia w tryb jasny i ciemny. */
.gmerek-zeichen { width: 34px; height: 34px; flex: none; color: var(--label-secondary); }
.gmerek-zeichen svg { width: 100%; height: 100%; display: block; }

.ueber-zeile { display: flex; align-items: center; gap: var(--s2); margin: var(--s2) 0; }
.ueber-text { font-size: 13px; color: var(--label-secondary); line-height: 1.5; }
/* Arkusz "Über BauLog" jest wizytowka, nie lista akcji - wszystko na osi. */
.blatt-aktionen.ueber { text-align: center; }
.blatt-aktionen.ueber .ueber-zeile { justify-content: center; }
/* Zdanie o Gmerek IT stoi POD Abbrechen jako stopka arkusza - mniejsze i ciszej niz reszta. */
.ueber-fuss {
  margin: var(--s2) 0 0;
  text-align: center;
  font-size: 12px;
  color: var(--label-secondary);
  line-height: 1.5;
}

/* ---------- olowek ---------- */

/* Kafelek po zlapaniu gestu - iOS Safari nie ma wibracji, wiec sygnal musi byc widoczny. */
.kachel.lang img { filter: brightness(.55); }

.markier {
  position: fixed; inset: 0; z-index: 30;
  display: flex; flex-direction: column;
  background: #000;
}
.markier-buehne {
  flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
/* touch-action: none, bo kazde drgniecie palca to kreska, nie przewijanie ekranu. */
.markier-flaeche {
  max-width: 100%; max-height: 100%;
  touch-action: none;
  cursor: crosshair;
}
.markier-leiste {
  display: flex; align-items: center; gap: var(--s1);
  padding: var(--s2) var(--s2) calc(var(--s2) + env(safe-area-inset-bottom));
  background: var(--bg-elevated);
}
.markier-leiste button { min-height: 44px; }
.markier-farben { display: flex; gap: var(--s1); margin-right: auto; }
.farb-chip {
  width: 34px; height: 34px; min-height: 34px; padding: 0;
  border-radius: 50%; border: 2px solid var(--separator);
  box-shadow: none;
}
.farb-chip.aktiv { border-color: var(--accent); transform: scale(1.15); }

/* ---------- panel Aktivität ---------- */

.filter { display: flex; flex-wrap: wrap; gap: var(--s1); margin: var(--s2) 0; }
.filter select { width: auto; flex: 1 1 100%; min-height: 44px; }
/* Od i do stoja w jednym rzedzie - zakres dat czyta sie jako para, nie dwa osobne pola. */
.filter input[type="date"] { width: auto; flex: 1 1 40%; min-height: 44px; }

/* Tabela ma sie PRZEWIJAC, nie sciskac - na telefonie kolumny inaczej sa nieczytelne. */
.tabelle-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: var(--s2) 0; }
table.verlauf { border-collapse: collapse; width: max-content; min-width: 100%; font-size: 13px; }
table.verlauf th, table.verlauf td {
  padding: var(--s1) var(--s2);
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--separator);
}
table.verlauf th { font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
                   color: var(--label-secondary); }
table.verlauf td.zeit { font-variant-numeric: tabular-nums; color: var(--label-secondary); }
table.verlauf td.meta { color: var(--label-secondary); }
table.verlauf td.detail { white-space: normal; max-width: 60%; }
table.verlauf tr:last-child td { border-bottom: 0; }
/* v.13.88 (D2b): ab 900px volle Breite statt max-content (Detail war rechts abgeschnitten,
   daneben leerer Platz) - table-layout:fixed verteilt die Breite nach den th-Vorgaben statt
   nach Inhalt, Detail bekommt den groessten Anteil und bricht um (white-space:normal schon
   oben gesetzt), Zeit bleibt einzeilig (nowrap ist die Basisregel oben). Unter 900px
   unveraendert (horizontal scrollbar wie bisher, DO NOT: Telefon-Ansicht bleibt gleich). */
@media (min-width: 900px) {
  .tabelle-scroll { overflow-x: visible; }
  table.verlauf { width: 100%; min-width: 0; table-layout: fixed; }
  table.verlauf th:nth-child(1) { width: 11%; }
  table.verlauf th:nth-child(2) { width: 13%; }
  table.verlauf th:nth-child(3) { width: 15%; }
  table.verlauf th:nth-child(4) { width: 15%; }
  table.verlauf th:nth-child(5) { width: 36%; }
  table.verlauf th:nth-child(6) { width: 10%; }
  table.verlauf td.detail { max-width: none; overflow-wrap: break-word; }
}

/* ---------- odpowiedz na dotyk ---------- */

/*
 * Wiersze list i pozycje arkuszy musza reagowac na palec. Samo `opacity` na tle bialym
 * jest ledwo widoczne, wiec wciskany element dostaje WLASNE tlo. Powrot 120 ms - tyle,
 * zeby bylo widac, i nie tyle, zeby przeszkadzalo przy szybkim klikaniu.
 */
:root { --gedrueckt: rgba(29, 104, 113, .14); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --gedrueckt: rgba(92, 197, 208, .20); }
}
:root[data-theme="dark"] { --gedrueckt: rgba(92, 197, 208, .20); }

li:active,
.blatt-knopf:active,
.stiege-chip:active,
.segment-knopf:active {
  background: var(--gedrueckt);
  transition: none;                  /* wcisniecie natychmiast, powrot dopiero po puszczeniu */
}
li, .blatt-knopf, .stiege-chip, .segment-knopf {
  transition: background .12s ease-out;
}

/* Usuwa 300 ms opoznienia tapniecia na iOS. Wierszy z gestem NIE dotyka - li.wischbar
   ma wlasne pan-y, a lightbox wlasne none; obie reguly stoja nizej i wygrywaja. */
li, button, .knopf, .blatt-knopf, .stiege-chip, .segment-knopf, .kachel {
  touch-action: manipulation;
}
/* Szary prostokat WebKit-a przy tapnieciu - wlasny stan wcisniecia jest czytelniejszy. */
* { -webkit-tap-highlight-color: transparent; }

button.primary, .knopf.primary {
  background: var(--accent);
  color: var(--accent-kontrast);
  font-weight: 600;
}
button.gross, .knopf.gross { width: 100%; margin-top: var(--s2); }

/* Akcja drugorzedna: sam tekst, bez plyty - nie konkuruje z aparatem. */
button.leise {
  background: none;
  box-shadow: none;
  font-weight: 400;
}
/* Powrot w lewym gornym rogu to najczesciej dotykany element w calej appce, a byl
   najmniejszy - 17px w rekawicy roboczej to za malo. 20px i pelne 44px wysokosci dotyku. */
button.leise.zurueck {
  font-size: 20px;
  padding: var(--s2) 0;
  min-height: 44px;
  justify-content: flex-start;
}
.abmelden { display: block; width: 100%; margin-top: var(--s5); color: var(--label-secondary);
            background: none; box-shadow: none; }

li .row button { min-width: 44px; min-height: 44px; padding: 0; font-size: 21px; }
/* .qty jest teraz <button>, ale ma wygladac jak pole (v.12.80) - osobna, bardziej
   szczegolowa regula zamiast zmiany ogolnej powyzej, ktora zostaje dla +/-. */
li .row button.qty { min-width: 56px; min-height: 44px; font-size: 17px; font-weight: 600; }
/* Artikelname als Button (v.12.68) - soll beruehrbar aussehen, aber nicht mit den
   Mengen-Buttons daneben konkurrieren. Einziges Signal: gepunktete Unterstreichung. */
.artikel-name { display: block; min-width: 0; min-height: 44px; padding: 0;
  background: none; box-shadow: none; border-radius: 0; color: var(--label);
  font-weight: inherit; text-align: left; justify-content: flex-start;
  text-decoration: underline dotted; white-space: normal; overflow-wrap: anywhere; }
/* v.13.02: Materialzeile - Name (bis 2 Zeilen, voll sichtbar) | Mengen-Steuerung. Nur diese Zeile, nicht
   `.wisch-inhalt` global. Ohne Recht 'material' gibt es keinen .wisch-inhalt: dann ist der li selbst das Raster. */
li.material-zeile > .wisch-inhalt, li.material-zeile:not(.wischbar) {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--s1); }
li.material-zeile .row button:not(.qty) { min-width: 44px; padding: 0; }
li.material-zeile .row button.qty { min-width: 3.5rem; padding: 0; }

/* ---------- formularze ---------- */

input, select, textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--s2);
  font: inherit;
  color: var(--label);
  background: var(--bg-elevated);
  border: 1px solid var(--separator);
  border-radius: var(--radius);
}
select { width: auto; }
/* v.12.72: resize:none, weil die Hoehe jetzt von textareaWaechst() (app.js) mit dem
   Text mitwaechst - ein manueller Resize-Griff wuerde das Feld unter den Text ziehen
   und die naechste Eingabe wuerde die Hoehe wieder ueberschreiben (Ruckeln). */
textarea { resize: none; line-height: 1.45; }
label { display: block; margin: var(--s2) 0; }
/* v.11.88: nazwa pola widoczna dla czytnika ekranu i dla menedzera hasel, niewidoczna na
   ekranie - placeholder znika po pierwszym znaku, a Keychain/Bitwarden czytaja tekst
   etykiety przy dopasowywaniu pol. Pozycja absolutna wyjmuje ja z ukladu, wiec zaden
   odstep na ekranie logowania sie nie zmienia. */
.feld-name {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.err { color: var(--danger); font-size: 13px; }
a { color: var(--accent); text-decoration: none; }

/* v.10.33: pasek "Offline - Stand HH:MM" nad trescia ekranu z cache - waski, bez przycisku,
   nie modal, nic nie blokuje (ZASADA NR 1). */
.offline-leiste {
  font-size: 12px;
  color: var(--label-secondary);
  background: var(--bg-elevated);
  border: 1px solid var(--separator);
  border-radius: var(--radius);
  padding: 4px var(--s2);
  margin-bottom: var(--s1);
  text-align: center;
}
/* v.10.63: Warnfarbe statt Groesse/Icon - Regel Nr. 1 bleibt, der Balken blockiert nichts. */
.offline-leiste.offline {
  color: var(--danger);
  border-color: var(--danger);
}
/* v.11.96: nur der Zustand "Netz wieder da, Daten noch aus dem Cache" ist antippbar -
   ein Tap laedt den Bildschirm neu. Sonst ist der Balken reine Anzeige. */
.offline-leiste.tippbar {
  cursor: pointer;
  color: var(--accent);
  border-color: var(--accent);
}

/* ---------- zdjecia ---------- */

/*
 * Podzial pionowy ekranu Stockwerk: pas zdjec zajmuje 38,2% wysokosci widoku,
 * lista materialu dostaje pozostale 61,8% - podzial phi, nie polowa na polowe.
 */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(89px, 1fr));
  gap: var(--s1);
  max-height: 38.2vh;
  overflow-y: auto;
  margin-top: var(--s1);
  padding: 1px;
}
.grid img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--s1);
  background: var(--separator);
  cursor: pointer;
  display: block;
  /* Bez tego dlugie przytrzymanie miniatury otwiera natywne menu iOS nad akcjami appki. */
  -webkit-touch-callout: none;
}

/* Kafelek nosi haczyk zaznaczenia - img nie ma pseudoelementow, wiec potrzebna otoczka. */
.kachel { position: relative; display: block; }
.kachel.gewaehlt img { opacity: .55; }
.kachel.gewaehlt::after {
  content: '✓';
  position: absolute; top: 4px; right: 4px;
  width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-kontrast);
  font-size: 14px; font-weight: 700;
}

/* ---------- pasek klatek ---------- */

/*
 * Stoi pod adresem budowy i nad segmentami. Przewija sie w poziomie, bo przy 36 klatkach
 * zadne zawijanie nie pomoze, a monter ma trafiac kciukiem bez celowania.
 */
.stiegen-leiste {
  display: flex;
  gap: var(--s1);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  margin: var(--s2) 0;
  padding-bottom: var(--s1);
  scrollbar-width: none;
}
.stiegen-leiste::-webkit-scrollbar { display: none; }

.stiege-chip {
  flex: none;
  min-height: 44px;
  padding: 0 var(--s2);   /* v.12.93: schmaler, 13 statt 21 px (phi-Skala) */
  font-size: .875rem;
  border-radius: 999px;
  border: 1px solid var(--separator);
  background: var(--bg-elevated);
  color: var(--label);
  box-shadow: none;
  white-space: nowrap;
  scroll-snap-align: center;
}
.stiege-chip.aktiv {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-kontrast);
  font-weight: 600;
}
.stiege-chip.neu, .stiege-chip.mehr { color: var(--accent); }
.stiege-chip.ausgeblendet { opacity: .45; }

.auswahl-starts { display: flex; justify-content: flex-end; margin-top: var(--s1); }
.auswahl-starts .auswahl-start { min-height: 44px; padding: 0; font-size: 17px; }
.auswahl-leiste {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; flex-wrap: wrap; gap: var(--s1); align-items: center;
  margin-top: var(--s1); padding: var(--s1) 0;
  background: var(--bg);
}
.auswahl-leiste button { min-height: 44px; flex: 1 1 8rem; padding: 0 var(--s1); }
.auswahl-leiste button:disabled { opacity: .4; }
.auswahl-leiste .warnung { color: var(--danger); }

.versteckt { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.aufnahme { flex-wrap: wrap; gap: var(--s1); margin: var(--s1) 0; }
/* v.13.81: Material-Reihe (+ Artikel/Dateien/Foto) bleibt beim Scrollen unter dem Header
   kleben - nur diese Reihe (mit-mitte = Material-Reiter, siehe uploadBlock artikelKnopf),
   Fotos/Notizen und Regie unveraendert. margin-top: 0, weil position:sticky den eigenen
   margin-top zum top-Offset addiert (sonst Luecke zum Header beim Kleben) - der Abstand zur
   Zakladkenleiste bleibt trotzdem gleich, weil .segment { margin-bottom: var(--s3) } (21px)
   allein schon groesser ist als das entfallene margin-top (8px) und den Abstand per
   Margin-Collapsing traegt. Hintergrund deckend (var(--bg)), damit die Liste beim Scrollen
   nicht unter den Knoepfen durchscheint. */
.aufnahme.mit-mitte {
  position: sticky;
  top: var(--kopf-hoehe, 0px);
  z-index: 9;
  margin-top: 0;
  background: var(--bg);
}
.aufnahme .knopf { flex: 1 1 13rem; }
.aufnahme.kompakt .dateien-link { flex: 0 0 auto; min-height: 44px; padding: 0 var(--s1); font-size: 17px; }
/* v.11.56: aparat po prawej; stala proporcja takze poza trybem kompaktowym. */
@media (min-width: 768px) {
  .aufnahme { display: grid; grid-template-columns: 1fr 1.618fr; max-width: 44rem; }
  .aufnahme.kompakt .dateien-link { justify-content: flex-start; }
  .aufnahme.mit-mitte { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* v.13.07 K1: na telefonie Dateien + Foto ZAWSZE w jednej linii (dotad 2 rzedy = ok. 20% ekranu przed lista):
   zloty podzial 1 : 1.618 (Foto szersze, bo czestsze; kolejnosc DOM bez zmian - aparat po prawej), 44 px, tekst
   15px/600, emoji 17px. minmax(0, ...) zeby tresc nie rozpychala kolumn i nie psula proporcji. Etykieta Dateien
   skrocona do "📎 Dateien" (pelna w aria-label), bo "Dateien hinzufügen" nie miesci sie w 1/2.618 szerokosci.
   Desktop (>= 768 px) zostaje przy regulach powyzej. Tylko klasy pod .aufnahme - globalne .knopf/.leise nietkniete. */
.aufnahme .kurz { display: none; }
.aufnahme .emoji { font-size: 17px; line-height: 1; }
@media (max-width: 767px) {
  .aufnahme { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.618fr); }
  .aufnahme .knopf, .aufnahme .dateien-link, .aufnahme.kompakt .dateien-link {
    width: auto; min-width: 0; height: 44px; min-height: 44px; margin: 0; padding: 0 var(--s1);
    font-size: 15px; font-weight: 600; white-space: nowrap; }
  .aufnahme .voll { display: none; }
  .aufnahme .kurz { display: inline-flex; align-items: center; gap: var(--s1); }
  /* v.13.80: Material-Reihe - + Artikel/Dateien/Foto in drei GLEICH breiten Spalten (goldener
     Schnitt aus v.13.79 hier bewusst weg, Tomaschs Veto). Andere Reiter (Fotos/Notizen)
     bleiben bei der 2-Spalten-Regel oben - eigene Klasse statt .aufnahme global zu aendern. */
  .aufnahme.mit-mitte { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* "Foto aufnehmen" -> "Foto": nur in der dreiteiligen Material-Reihe, wo die schmalere
     Spalte (1fr statt 1,618fr) fuer die volle Beschriftung nicht reicht (375 px). */
  .aufnahme.mit-mitte .foto-voll { display: none; }
  .aufnahme.mit-mitte .foto-kurz { display: inline-flex; align-items: center; gap: var(--s1); }
}
.aufnahme .foto-kurz { display: none; }
/* v.13.80: "Dateien" in der Material-Reihe = Sekundaerstil wie die inaktive Fotos/Notizen-
   Zakladka (dieselben Tokens wie .segment-knopf), damit es nicht mit + Artikel/Foto (primary,
   --accent) konkurriert - Dateien wird seltener gebraucht. */
.aufnahme.mit-mitte .dateien-link {
  background: var(--bg-elevated);
  color: var(--label);
  border: 1px solid var(--separator);
  box-shadow: none;
}
/* v.13.80: unter 360px reicht in der Material-Reihe kein Platz mehr fuer "Dateien" ALS TEXT
   neben +Artikel/Foto (aufnahme_zeile_test.mjs A4, Playwright iPhone SE 320px: 1px Overflow) -
   nur das Icon bleibt, Spaltenbreite und aria-label unveraendert. font-size:0 auf .kurz
   kollabiert nur den Textknoten - .emoji hat ihre eigene (absolute) font-size und bleibt sichtbar. */
@media (max-width: 359px) {
  .aufnahme.mit-mitte .dateien-link .kurz { font-size: 0; gap: 0; }
}
/* v.13.81 D4: Feld-Fokus (z. B. Menge im letzten Listeneintrag) darf nicht unter der
   klebenden Material-Reihe verschwinden - nur aktiv, wenn der Material-Reiter gerade
   gerendert ist (Klasse in screenStockwerkRoh), sonst wuerde scroll-padding-top auf jedem
   Screen mit Header wirken. */
body.material-sticky-aktiv {
  scroll-padding-top: calc(var(--kopf-hoehe, 0px) + var(--material-reihe-hoehe, 0px));
}
/* v.15.44 (B): seit 1.28.35 (E) bleibt nach "+ Artikel" das Mengenfeld fokussiert, die
   iOS-Tastatur also offen. iOS verschiebt dann den sichtbaren Ausschnitt (visualViewport.
   offsetTop > 0), sticky `top` zaehlt aber ab Layout-Viewport - Header und Material-Reihe
   kleben ueber dem sichtbaren Bereich. --vvt (JS, wie bei .blatt-hinter) ohne Tastatur = 0. */
body.material-sticky-aktiv header { top: var(--vvt, 0px); }
body.material-sticky-aktiv .aufnahme.mit-mitte { top: calc(var(--kopf-hoehe, 0px) + var(--vvt, 0px)); }

.uploads { margin-top: var(--s1); }
.uploads:empty { display: none; }
.uploads .dateiname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uploads .ok { color: var(--accent); }
.uploads .err { text-align: right; }

/* ---------- "Was ist neu" i Fibel (v.9.77) ---------- */
.was-neu { margin-top: var(--s4); padding: var(--s3); border-radius: var(--radius);
  background: var(--bg-elevated); }
.was-neu:empty { display: none; }
.was-neu-link { display: block; margin: var(--s4) auto 0; }
.was-neu-kopf { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }
.punkt { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); }
.neu-eintrag { padding: var(--s2) 0; }
.neu-eintrag + .neu-eintrag { border-top: 1px solid var(--trennlinie, rgba(128,128,128,.25)); }
.neu-kopf { display: flex; flex-direction: column; gap: 2px; }
.neu-punkte { margin: var(--s2) 0 0; padding-left: 1.1em; }
.neu-punkte li { margin-bottom: var(--s1); }
.neu-text { margin: var(--s2) 0 0; }
.neu-eintrag.zusammen { cursor: pointer; }

.fibel { margin-top: var(--s4); padding: var(--s3); border-radius: var(--radius);
  background: var(--bg-elevated); }
.fibel h2 { margin-top: 0; }
.fibel-feld { display: flex; flex-direction: column; gap: 4px; margin-bottom: var(--s3); }
.fibel-feld > span { font-size: 14px; color: var(--label-secondary); }
.fibel-feld select, .fibel-feld input { min-height: 48px; font-size: 17px; }
.fibel-einheit { display: flex; align-items: center; gap: var(--s2); }
.fibel-einheit input { flex: 1; min-width: 0; }
.fibel-ergebnis { display: flex; gap: var(--s4); margin-top: var(--s3); }
.fibel-ergebnis > div { display: flex; flex-direction: column; }
.fibel-gross { font-size: 28px; line-height: 1.2; }
.fibel-ampel { margin-top: var(--s2); padding: var(--s2) var(--s3); border-radius: var(--radius);
  text-align: center; font-weight: 600; }
.fibel-ampel:empty { display: none; }
.fibel-ampel.gut { background: #1c6b3a; color: #fff; }
.fibel-ampel.warn { background: #8a6100; color: #fff; }
.fibel-ampel.schlecht { background: var(--danger); color: #fff; }
.fibel-quelle, .fibel-warnung { margin-top: var(--s3); font-size: 13px;
  color: var(--label-secondary); }
.fibel-warnung { font-style: italic; }

/* v.9.76: strefa upuszczania plikow (desktop). Na dotyku dragover nie istnieje,
   wiec ta klasa nigdy tam nie wchodzi i uklad zostaje bez zmian. */
.zieht { outline: 2px dashed var(--accent); outline-offset: 4px; border-radius: var(--radius); }

/* Kolejka offline (v.9.33) - kafelki wartend/laedt hoch/fehlgeschlagen, przezywaja reload. */
.kolejka-offline { display: grid; grid-template-columns: repeat(auto-fill, minmax(89px, 1fr));
  gap: var(--s1); margin-top: var(--s1); }
.kolejka-offline:empty { display: none; }
.kolejka-kachel { position: relative; aspect-ratio: 1; border-radius: var(--radius); overflow: hidden; }
.kolejka-kachel img { width: 100%; height: 100%; object-fit: cover; opacity: .55; }
.kolejka-status { position: absolute; bottom: var(--s1); right: var(--s1);
  width: 21px; height: 21px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; font-size: 13px; font-weight: 700; color: #fff;
  box-shadow: 0 0 0 2px var(--bg-elevated); }
.kolejka-status.wartend { background: var(--label-secondary); }
.kolejka-status.wartend::after { content: ''; width: 8px; height: 8px; border-radius: 50%;
  background: #fff; }
.kolejka-status.laedt { background: var(--accent); animation: dreh 1s linear infinite; }
.kolejka-status.laedt::after { content: ''; width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid #fff; border-top-color: transparent; }
.kolejka-status.fehlgeschlagen { background: var(--danger); }
.kolejka-status.fehlgeschlagen::after { content: '!'; }
/* v.10.30: obrobka. 'roh' - trwa (szaro, jak wartend); 'roh_fehler' - poddala sie i czeka
   na tap. Kafelek bez miniatury musi sam z siebie mowic, ktory to z tych dwoch. */
.kolejka-status.roh { background: var(--label-secondary); }
.kolejka-status.roh::after { content: '…'; }
.kolejka-status.roh_fehler { background: var(--danger); }
.kolejka-status.roh_fehler::after { content: '!'; }
.kolejka-kachel { background: var(--bg-elevated); }
.kolejka-text { position: absolute; left: 0; right: 0; top: 0; padding: 3px var(--s1);
  font-size: 10px; line-height: 1.25; color: #fff; background: rgba(0, 0, 0, .55);
  overflow: hidden; }
/* v.9.75: procent wysylki. Sam spinner nie odrozniał wolnego lacza od zawieszonego. */
.kolejka-prozent { position: absolute; left: 0; right: 0; bottom: 0; padding: 2px 0;
  text-align: center; font-size: 11px; font-weight: 600; color: #fff;
  background: rgba(0, 0, 0, .55); }
.kolejka-prozent[hidden] { display: none; }
.kolejka-kachel[title] { cursor: pointer; }
@keyframes dreh { to { transform: rotate(360deg); } }

/* ---------- arkusz eksportu ---------- */

/* v.9.78: odstep podniesiony z --s1 (8px) na --s3 (21px). Trzy przyciski po 44-48 px
   stykaly sie na tyle blisko, ze w rekawicy latwo bylo trafic w sasiedni - a domek i
   trzy kropki robia zupelnie rozne rzeczy. */
.kopf-aktionen { display: flex; align-items: center; gap: var(--s3); flex-shrink: 0; }
.global-uhr { display: inline-flex; align-items: baseline; gap: var(--s1); white-space: nowrap; }
/* v.13.82: Wochentag ("Di.") groesser als das Datum ("29.09.") - 28:17 = goldener Schnitt,
   aus der Typo-Skala des Projekts (13/17/28/34). */
.global-wochentag { color: var(--label); font-size: 28px; font-weight: 600; white-space: nowrap; }
.global-tag { color: var(--label); font-size: 17px; font-weight: 600; white-space: nowrap; }
/* v.13.82 (Tomasz-Entscheidung nach STOP): unter 360px zurueck auf 15px (Breite wie vor
   dieser Aenderung) - darueber bleibt 28/17. Der Kopf hat auf 320px (iPhone SE 1. Gen.)
   bereits VOR diesem Task horizontalen Overflow (separates, aelteres Problem, siehe Bericht -
   hier NICHT angefasst); 15px vermeidet nur, dass diese Aenderung ihn verschaerft. */
@media (max-width: 359px) {
  .global-wochentag, .global-tag { font-size: 15px; }
  /* Die zwei Spans (Flex-Gap 8px) sind minimal breiter als der frueher EINE Textknoten mit
     normalem Leerzeichen (Gewinn: A7-Regression, siehe Bericht) - 4px auf dieser Breite
     bringt die Gesamtbreite zurueck auf den Stand vor v.13.82. */
  .global-uhr { gap: 4px; }
}
.global-zeit { display: none; font-size: 16px; font-weight: 600; white-space: nowrap; }
@media (pointer: fine) { .global-zeit { display: inline; } }
@media (pointer: coarse) { .global-zeit { display: none; } }
#home, #dok, #kalender, #offline { flex: none; min-width: 44px; min-height: 44px; padding: 0; border: 0;
        border-radius: var(--radius); background: transparent; box-shadow: none;
        color: var(--accent); line-height: 0; }
/* Rozmiar SAMEJ ikony - obszar dotyku zostaje 44x44 (wyzej), tak jak przy #menu. */
#home svg, #dok svg, #kalender svg, #offline svg { width: 29px; height: 29px; display: block; }
/* v.12.82: #offline jest PRZELACZNIKIEM STANU, nie nawigacja - osobny rejestr wizualny,
   inaczej monter czyta go jako "gdzies mnie zabierze" jak reszte naglowka i tapie przez
   pomylke.
   v.13.78: zielone slupki sygnalu = online, czerwone + ukosna kreska = Offline-Modus -
   ksztalt (kreska) rozni stany niezaleznie od koloru (daltonizm czerwono-zielony). */
#offline { color: var(--ok); }
#offline.ein { color: var(--danger); }
/* v.13.87: 420px reichte nicht mehr (Datum seit v.13.82 breiter, "..." ragte bei 430px
   noch 21px raus, siehe Bericht) - auf 480px angehoben, deckt auch Pro-Max-Breiten ab. */
@media (max-width: 480px) { .kopf-aktionen { gap: var(--s1); } header { gap: var(--s1); } }
/* v.13.87: unter 390px reicht selbst gap:var(--s1) zwischen den 5 Icons + Datum nicht mehr
   (5x44px Touch-Ziele + Datum > verfuegbare Breite, siehe Bericht) - noch enger, Touch-Ziele
   bleiben 44x44 (nur der Zwischenraum schrumpft). Icons werden NICHT entfernt/verschoben (DO NOT). */
@media (max-width: 389px) {
  .kopf-aktionen { gap: 4px; }
  header { gap: 4px; padding-left: calc(var(--s1) + env(safe-area-inset-left)); padding-right: calc(var(--s1) + env(safe-area-inset-right)); }
}
/* v.13.87: 320px (iPhone SE) - noch 1-2px zu knapp mit gap:4px, letzter Schritt. */
@media (max-width: 340px) {
  .kopf-aktionen { gap: 2px; }
  header { gap: 2px; }
}
#teilen {
  flex: none;
  min-width: 44px; min-height: 44px;
  padding: 0;
  border: 0; border-radius: var(--radius);
  background: transparent; box-shadow: none;
  color: var(--accent);
  line-height: 0;
}

.blatt-hinter {
  position: fixed; left: 0; right: 0; z-index: 30;
  /* height zamiast inset:0 - z klawiatura na ekranie visualViewport.height jest
     mniejszy niz layout viewport, --vvh (JS) trzyma arkusz nad klawiatura.
     top zamiast 0 - v.10.12: gdy WebKit przewinie layout viewport pod klawiatura
     (visualViewport.offsetTop > 0), top:0 zostawal nad widocznym oknem. --vvt (JS)
     trzyma overlay w widocznym obszarze niezaleznie od tego przewiniecia. */
  top: 0; top: var(--vvt, 0);
  height: 100vh; height: var(--vvh, 100vh);
  display: flex; align-items: flex-end; justify-content: center;
  /* Mocniejsze przyciemnienie i rozmycie: w trybie ciemnym #00000066 na czarnym tle nie
     dawalo ZADNEJ granicy - arkusz zlewal sie z ekranem pod spodem. */
  background: rgba(0, 0, 0, .6);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
/* v.13.57: iOS 26 nie wlicza do visualViewport pasa pod plywajacym paskiem akcesoriow klawiatury, wiec
   nakladka (height: --vvh) konczy sie nad nim i pod przezroczystym paskiem widac strone. Przedluzenie w dol
   (poza ekran; nie zmienia --vvh, wiec pole nad klawiatura zostaje tam, gdzie bylo): to samo przyciemnienie
   i rozmycie, a na telefonie (arkusz na pelna szerokosc) tlo arkusza - arkusz "ciagnie sie" pod klawiature. */
.blatt-hinter::after {
  content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 100vh;
  background: rgba(0, 0, 0, .6);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
@media (max-width: 34rem) {
  .blatt-hinter::after { background: var(--bg-elevated); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
/*
 * Arkusz UNOSI SIE nad tlem (--bg-elevated), a to, co w srodku, schodzi o stopien nizej
 * (--bg). Bez tej drugiej reguly przyciski wziely by --bg-elevated z bazowego `button`,
 * czyli DOKLADNIE tlo arkusza, i zniknely by - w obu motywach.
 * Efekt: ciemny  arkusz #1c1c1e / przyciski #000000,
 *        jasny   arkusz #ffffff / przyciski #f2f2f7.
 */
.blatt button, .blatt .knopf { background: var(--bg); }
/* Ta sama specyficznosc co button.primary wyzej, ale stoi nizej - bez tej reguly
   glowny przycisk arkusza dostaje --bg i w jasnym motywie znika (bialy na #f2f2f7). */
.blatt button.primary, .blatt .knopf.primary { background: var(--accent); }
.blatt {
  width: 100%; max-width: 34rem;
  padding: var(--s3) var(--s3) calc(var(--s3) + env(safe-area-inset-bottom));
  background: var(--bg-elevated);
  border-radius: var(--radius) var(--radius) 0 0;
  animation: hoch .25s ease-out;
  /* 85vh liczone od PELNEGO layout viewportu chowa search-input pod klawiatura -
     ta sama przyczyna co --vvh na .blatt-hinter, wiec ten sam limit tutaj. */
  max-height: 85vh;
  max-height: calc(var(--vvh, 100vh) * .85);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
@keyframes hoch { from { transform: translateY(21px); } to { transform: none; } }

/* v.9.78: naglowek arkusza - tytul i "X" w jednym rzedzie. Dotad wyjscie z arkusza
   bylo tylko na dole (Abbrechen) albo niewidoczne (tap w tlo), przez co z "Was ist neu"
   monter nie widzial drogi powrotnej. */
.blatt-kopf { display: flex; align-items: flex-start; justify-content: space-between;
              gap: var(--s2); margin-bottom: var(--s2); }
.blatt-titel { margin: 0; }
/* `.blatt button` (wyzej) ma wieksza specyficznosc niz sama klasa i nadalby temu
   przyciskowi tlo plyty - stad kwalifikator rodzica, nie !important. */
.blatt .blatt-zu { flex: none; min-width: 44px; min-height: 44px; margin: -6px -6px 0 0;
            padding: 0; border: 0; border-radius: var(--radius);
            background: transparent; box-shadow: none;
            color: var(--label-secondary); font-size: 21px; line-height: 1; }

/* v.10.36: eine Rechte-Zeile im Benutzer-Editor - Etikett links, Segment rechts. */
.blatt-zeile { display: flex; align-items: center; justify-content: space-between;
               gap: var(--s2); margin-bottom: var(--s2); }
.blatt-zeile .segment { flex: 0 0 auto; margin-bottom: 0; }

/*
 * Teilnehmer-Liste: `input, select, textarea { width: 100% }` (Zeile 420) rozciaga pudelko
 * checkboxa do prawej krawedzi wiersza, a WebKit rysuje kwadracik przy LEWEJ krawedzi tego
 * pudelka - czyli pozycja zalezy od dlugosci imienia. Tabela wyrownuje kolumny sama, po
 * najszerszej komorce, bez mierzenia szerokosci w JS.
 */
.teilnehmer-liste { display: table; width: auto; border-spacing: 0 var(--s1); }
.teilnehmer-liste > label { display: table-row; margin: 0; }
.teilnehmer-liste > label > span { display: table-cell; vertical-align: middle;
                                    padding-right: var(--s3); white-space: nowrap; }
.teilnehmer-liste > label > input { display: table-cell; width: auto; min-width: 0;
                                     margin: 0; vertical-align: middle; }

/* Wybor zakresu - segmenty w stylu iOS. */
.segment { display: flex; gap: var(--s1); margin-bottom: var(--s3); }
.segment-knopf {
  flex: 1; min-height: 44px; padding: var(--s1);
  font-size: 13px; font-weight: 500;
  background: var(--bg-elevated); color: var(--label);
  box-shadow: none; border: 1px solid var(--separator);
}
.segment-knopf.aktiv { background: var(--accent); color: var(--accent-kontrast); border-color: var(--accent); }
.stiegen-wahl { flex-wrap: wrap; }
.stiegen-wahl .segment-knopf { flex: 0 0 calc(50% - var(--s1)); }
.pdf-ansicht { position: fixed; inset: 0; z-index: 1000; width: 100vw; height: 100dvh; overflow: hidden; box-sizing: border-box; background: var(--bg-elevated); display: flex; flex-direction: column; }
.pdf-kopf { display: flex; align-items: center; gap: var(--s1); padding: max(var(--s2), env(safe-area-inset-top)) var(--s1) var(--s1); }
.pdf-dateiname { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pdf-kopf button { flex: none; min-width: 44px; min-height: 44px; }
.pdf-zoom { font-size: 48px; line-height: 1; }
.pdf-kopf .pdf-teilen { width: auto; min-width: 0; font-size: 15px; white-space: nowrap; }
.pdf-kopf .pdf-zoom, .pdf-kopf .pdf-teilen { height: 56px; }
.pdf-teilen span { pointer-events: none; }
/* v.15.72: X byl 17px w akcencie na bialym - Tomasz 19.10: "prawie nie zauwazyc, gdzie wyjscie".
   Teraz kafel jak -/+ (56px), znak 30px w kolorze tekstu, nie akcentu - czytelny z dlugosci reki. */
.pdf-kopf .pdf-zu { width: 56px; height: 56px; font-size: 30px; font-weight: 600; line-height: 1; color: var(--label); }
@media (max-width: 767px) {
  .pdf-kopf { display: grid; grid-template-columns: 1fr 3.236fr 1fr; grid-template-rows: auto 56px; }
  .pdf-dateiname { grid-column: 1 / 3; grid-row: 1; }
  .pdf-zu { grid-column: 3; grid-row: 1; justify-self: stretch; }
  .pdf-kopf .pdf-zu { width: 100%; }
  .pdf-kopf .pdf-zoom, .pdf-teilen { grid-row: 2; width: 100%; height: 56px; }
  .pdf-minus { grid-column: 1; }
  .pdf-teilen { grid-column: 2; }
  .pdf-plus { grid-column: 3; }
}
.pdf-seiten { flex: 1; overflow: auto; touch-action: pan-x pan-y; padding: 4px; }
.pdf-vorschau { width: 100%; max-width: 900px; margin: 0 auto; background: #fff; }
.pdf-vorschau canvas { display: block; width: 100%; height: auto; margin-bottom: var(--s2); background: #fff; }
.pdf-vorschau canvas:last-child { margin-bottom: 0; }

.dok-zeile { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--s1); }
.dok-text { min-width: 0; }
.dok-text > a, .dok-text > .meta { display: block; }
.dok-text > a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dok-text > .meta { margin-top: 1px; white-space: nowrap; }

/* Miniatura 44 px = spust 72 px / phi (1,618). */
.kamera-blatt { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; height: 100dvh; z-index: 1000; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; background: #121316; color: #d6d6d0; }
.kamera-bild { position: relative; min-height: 0; overflow: hidden; }
.kamera-blatt video { width: 100%; height: 100%; object-fit: contain; touch-action: none; transform-origin: center; }
.kamera-blatt button { padding: 0; border: 0; box-shadow: none; background: rgba(18,19,22,.6); color: #d6d6d0; }
.kamera-kopf, .kamera-fuss { align-items: center; padding: var(--s2); }
.kamera-kopf { display: flex; justify-content: space-between; padding-top: max(var(--s2), env(safe-area-inset-top)); }
.kamera-kopf button { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; }
.kamera-kopf button:last-child { margin-left: auto; }
.kamera-kopf button[data-an="1"] { background: var(--accent); }
.kamera-kopf .kamera-lampe { position: relative; }
.kamera-fuss { display: grid; grid-template-columns: 1fr auto 1fr; padding-bottom: max(var(--s2), env(safe-area-inset-bottom)); }
.kamera-fuss > button:first-child { justify-self: start; min-height: 44px; background: transparent; font-size: 17px; }
.kamera-fuss .ausloeser { width: 72px; height: 72px; border: 5px solid #d6d6d0; border-radius: 50%; background: transparent; }
.zoom-reihe { position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%); display: flex; align-items: flex-start; justify-content: center; gap: var(--s1); height: auto; min-height: 44px; }
.zoom-reihe button { flex: none; width: 38px; height: 38px; min-height: 0; border-radius: 50%; font-size: 13px; }
.zoom-reihe button.aktiv { width: 44px; height: 44px; color: var(--accent); }
.kamera-zoom { position: absolute; bottom: calc(12px + 44px + 8px); left: 50%; transform: translateX(-50%); font-size: 13px; }
.kamera-miniatur { display: block; width: 44px; height: 44px; object-fit: cover; border-radius: 8px; }
.kamera-miniatur-wrap { position: relative; width: 44px; height: 44px; justify-self: end; margin-right: 6px; }
/* v.15.39 (C): nur helle Zahl, kein Kreis - Schatten, weil die Zahl auf der Miniatur liegt. */
.kamera-zaehler { position: absolute; right: -6px; top: -6px; min-width: 0; padding: 0 4px; border-radius: 0; background: none; color: #f2f2ee; font-size: 28px; font-weight: 700; line-height: 1; text-shadow: 0 1px 3px rgba(0,0,0,.7), 0 0 2px rgba(0,0,0,.5); }
.kamera-blitz { position: absolute; inset: 0; background: #d6d6d0; opacity: 0; pointer-events: none; }
/* v.15.39 (D): Blitz-Animation per element.animate() in app.js (blitzZeigen). */
/* v.15.74: Vorschau der Fotos dieser Kamera-Sitzung (Tipp auf Miniatur) - deckt die Kamera ganz ab. */
.kamera-miniatur, .kamera-zaehler { cursor: pointer; }
.kamera-vorschau { position: absolute; inset: 0; z-index: 2; display: grid; grid-template-rows: auto minmax(0, 1fr); background: #121316; }
.kamera-vorschau-kopf { display: flex; align-items: center; justify-content: space-between; padding: var(--s2); padding-top: max(var(--s2), env(safe-area-inset-top)); }
.kamera-vorschau-kopf button { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; }
.kamera-vorschau-zahl { font-size: 17px; font-weight: 600; }
.kamera-vorschau-bild { width: 100%; height: 100%; object-fit: contain; touch-action: pan-y; padding-bottom: env(safe-area-inset-bottom); box-sizing: border-box; }

/* Kalender-Monatsansicht (Task 182, Zeilenzahl variabel seit Task 186): 7 Spalten, 5-6 Zeilen,
   Wochenstart Montag. Gesamthoehe fix (6 Zeilen x 44px Touch-Ziel + 5 Gaps), damit die Liste
   darunter beim Wechsel zwischen 5- und 6-zeiligen Monaten nicht springt - bei 5 Zeilen werden
   die Zellen dadurch hoeher statt die Zeile leer zu lassen. */
.monat-ansicht { margin-bottom: var(--s3); }
.monat-kopf { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s2); }
.monat-titel { font-size: 17px; font-weight: 600; text-transform: capitalize; }
.monat-pfeil { min-width: 44px; min-height: 44px; padding: 0; background: transparent; box-shadow: none;
               border: 0; color: var(--label); font-size: 20px; }
.monat-wochentage { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 4px; }
.monat-wochentage span { text-align: center; font-size: 11px; color: var(--label-secondary); }
.monat-raster { display: grid; grid-template-columns: repeat(7, 1fr);
                grid-template-rows: repeat(var(--monat-wochen, 6), 1fr);
                height: 274px; gap: 2px; touch-action: pan-y; }
.monat-tag { position: relative; display: flex; align-items: center; justify-content: center;
             width: 44px; min-width: 44px; height: 44px; min-height: 44px; aspect-ratio: 1;
             margin-inline: auto; padding: 0; border: 0; border-radius: 50%;
             background: transparent; color: var(--label); font-size: 15px; box-shadow: none; }
.monat-tag.ausserhalb { opacity: .35; }
.monat-tag.frei { color: var(--danger); }
.monat-tag.heute { box-shadow: inset 0 0 0 2px var(--accent); }
.monat-tag.ausgewaehlt { background: var(--accent); color: var(--accent-kontrast); }
.monat-tag-punkt { position: absolute; bottom: 5px; width: 4px; height: 4px; border-radius: 50%; background: currentColor; }

.blatt-aktionen { display: flex; flex-direction: column; gap: var(--s1); }
/* v.12.71: Suche bleibt oben sichtbar, auch wenn der Artikelkatalog darunter gescrollt wird -
   sticky auf `.blatt` (dem Scrollcontainer), opakes Hintergrund wie das Blatt selbst, damit
   die Liste optisch DARUNTER durchlaeuft statt durchzuscheinen. */
.artikel-kopf { position: sticky; top: 0; z-index: 2;
                display: flex; flex-direction: column; gap: var(--s2);
                background: var(--bg-elevated); }
/* v.13.71: sticky klebt an der INHALTSkante von .blatt - darueber blieb der Padding-Streifen (--s3) frei und
   die Liste schien dort durch. top ueber das Padding hinaus schliesst den Streifen; margin/padding --s2
   gleichen aus, damit das Suchfeld bei scrollTop 0 genau dort bleibt, wo es war (unter .blatt-kopf). */
.artikel-kopf { top: calc(-1 * var(--s3)); margin-top: calc(-1 * var(--s2)); padding-top: var(--s2); }
.blatt-knopf {
  flex-direction: column; align-items: flex-start; gap: 0;
  width: 100%; min-height: 55px;
  text-align: left;
}
.blatt-knopf .meta { color: var(--label-secondary); font-size: 13px; }
.blatt-knopf.primary .meta { color: var(--accent-kontrast); opacity: .8; }
.blatt-knopf.abbrechen { margin-top: var(--s2); justify-content: center; align-items: center;
                         color: var(--label-secondary); }
/* v.13.49: Abbrechen klebt am unteren Rand des Blatts (Scrollcontainer). Bei offener Tastatur ist das Blatt
   niedriger als sein Inhalt - Abbrechen lag dann UNTERHALB des Blatts und der Bildschirm darunter schien durch.
   Der Schatten in Blattfarbe deckt die Zeilen ab, die beim Scrollen unter dem Knopf durchlaufen. */
.blatt > .blatt-knopf.abbrechen { position: sticky; bottom: 0; z-index: 3;
                                  box-shadow: 0 0 0 var(--s2) var(--bg-elevated); }
/* v.13.68: Tastatur offen = Abbrechen weg, die Liste im Blatt bekommt den Platz. Ausgang bei
   offener Tastatur: Tastatur zu (Abbrechen kommt zurueck), "X" im Kopf, Wisch-Geste, Tap ins Hintergrund. */
html.tastatur-offen .blatt > .blatt-knopf.abbrechen { display: none; }
/* v.13.71: unter Abbrechen bleibt das untere Padding (--s3 + safe-area) frei, der Schatten oben deckt nur --s2 -
   die Liste schien dort durch. Eigene sticky Abdeckung genau ueber dem Padding-Streifen: negative
   margin-bottom = kein Platz im Fluss, bottom negativ = klebt an der Aussenkante des Blatts. Ohne Scrollen
   liegt sie im leeren Padding und ist unsichtbar; Padding von .blatt bleibt unveraendert. */
.blatt::after {
  --blatt-unten: calc(var(--s3) + env(safe-area-inset-bottom));
  content: ''; display: block; position: sticky; z-index: 3;
  bottom: calc(-1 * var(--blatt-unten)); height: var(--blatt-unten); margin-bottom: calc(-1 * var(--blatt-unten));
  background: var(--bg-elevated);
}
/* Zablokowany przycisk musi WYGLADAC na zablokowany - inaczej "Endgültig löschen" przed
   wpisaniem kodu kusi tapnieciem i wyglada jak zepsuty. */
.blatt-knopf:disabled { opacity: .4; }

/* ---------- gest, toast, stany ---------- */

#menu { flex: none; min-width: 44px; min-height: 44px; padding: 0; border: 0;
        border-radius: var(--radius); background: transparent; box-shadow: none;
        color: var(--accent); line-height: 0; }
/* Rozmiar SAMYCH kropek. Obszar dotyku zostaje 44x44 (wyzej) - rosnie tylko to, co widac. */
#menu svg { width: 33px; height: 33px; display: block; }

/* Bez touch-action Safari na iPhone anuluje wskaznik przy panie i gest nigdy nie dochodzi.
   Bez user-select/-webkit-touch-callout pan w poziomie iOS interpretuje jako zaznaczanie
   tekstu - podswietlenie i uchwyt nakladaja sie wtedy na odslonieta akcje/stepper.
   Blokada zaznaczania dziala wylacznie na dotyku (ponizej, pointer: coarse) - na komputerze
   z mysza gestu nie ma, wiec zaznaczanie tekstu w wierszu zostaje odblokowane. */
li.wischbar { position: relative; overflow: hidden; padding: 0; touch-action: pan-y;
              user-select: text; }
@media (pointer: coarse) {
  li.wischbar { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
}
/* Tresc musi lezec NAD schowanymi akcjami, inaczej przejmuja one klikniecie w wiersz. */
.wisch-inhalt { position: relative; z-index: 1;
                display: flex; align-items: center; justify-content: space-between;
                gap: var(--s2); width: 100%; min-height: 44px;
                padding: var(--s2) var(--s3); background: var(--bg-elevated);
                transition: transform .25s ease-out, background .12s ease-out; }
.wisch-aktionen { position: absolute; inset: 0 0 0 auto; display: flex; }
.wisch-knopf { min-width: 89px; min-height: 44px; height: 100%; border: 0; border-radius: 0;
               box-shadow: none; background: var(--separator); color: var(--label); }
.wisch-knopf.warnung { background: var(--danger); color: #fff; }

li.ausgeblendet .wisch-inhalt { opacity: .45; }
.leerzeile { justify-content: center; padding: var(--s4) var(--s3); }
.haken { min-width: var(--s3); color: var(--accent); font-weight: 700; }
/* Widoczny wyzwalacz akcji w wierszu - 44x44, ta sama ikona co w pasku. */
.mehr { flex: none; min-width: 44px; min-height: 44px; padding: 0; border: 0;
        border-radius: var(--radius); background: transparent; box-shadow: none;
        color: var(--accent); line-height: 0; }
/* W wierszu odrobine mniej niz w naglowku - inaczej kropki zaczynaja konkurowac z trescia. */
.mehr svg { width: 30px; height: 30px; display: block; }
/* v.13.02: `•••` przy pietrach mniejsze - kropki ~60% (18 px), szary kolor, przycisk 32 px szeroki. Cel dotyku
   zostaje 44x44: ::after rozszerza pole trafienia o 6 px z kazdej strony (padding poszerzylby sam przycisk).
   Celuje wylacznie w .stock-mehr, nie w .mehr przy notatkach ani dokumentach. */
li .row button.stock-mehr { position: relative; min-width: 32px; width: 32px; color: var(--label-secondary); }
li .row button.stock-mehr::after { content: ''; position: absolute; inset: 0 -6px; }
.stock-mehr svg { width: 18px; height: 18px; }
/* Nazwa bez przycisku (brak prawa albo Platzhalter) moze sie zwezic - inaczej dlugi tekst wypycha przyciski poza wiersz. */
.wisch-inhalt > span:first-child { min-width: 0; }
/* v.13.79 (E1): Treffer sind die Hauptsache (accent, fett), "neu anlegen" ist die
   Ausweichroute - eigene Zeile UNTER der Trefferliste (nicht mehr Teil der ul-Karte),
   Abstand + gestrichelter Rahmen ohne Fuellton machen sie bewusst zurueckhaltend. */
.artikel-treffer { color: var(--accent); font-weight: 600; }
/* `.blatt button` (style.css weiter oben) hat groessere Spezifitaet als die blosse Klasse
   und wuerde sonst das Kartenweiss zurueckbringen - Elternqualifikator wie bei .blatt-zu. */
.blatt .anlegen {
  display: block; width: 100%; margin-top: var(--s3);
  text-align: left; font-weight: 400;
  color: var(--label-secondary); background: transparent;
  border: 1px dashed var(--separator); box-shadow: none;
}
.fussnote { margin-top: var(--s4); text-align: center; }
.ok { color: var(--accent); }
button.gefahr { color: var(--danger); }

/* ---------- mysz: hover i wskaznik klikalnosci ---------- */

/* Wiersze list otwierajace ekran, kafle zdjec i pozycje menu w arkuszu sa klikalne, ale
   nie sa <button> - bez tej reguly mysz nie dostaje zadnej wskazowki. Przyciski maja
   cursor:pointer juz z reguly bazowej `button, .knopf` (wyzej). Wykluczamy `.leerzeile`
   (wiersz stanu, nieklikalny), listy `.neu-punkte` (wypunktowanie changelogu, tekst)
   i `.wischbar` (caly wiersz nie jest klikalny, tylko przyciski w srodku). */
ul:not(.neu-punkte) li:not(.leerzeile):not(.wischbar) { cursor: pointer; }

/* Dyskretna reakcja na najechanie - zmiana tla o jeden stopien, bez ramki i cienia.
   Podwojny warunek (hover I pointer:fine) jest celowy: samo `hover: hover` nie wystarcza,
   bo iOS emuluje hover po tapnieciu az do nastepnego dotkniecia (stan "przyklejony"). */
@media (hover: hover) and (pointer: fine) {
  ul:not(.neu-punkte) li:not(.leerzeile):hover,
  button:hover, .knopf:hover,
  .kolejka-kachel:hover {
    background: var(--bg);
  }
  .kachel:hover {
    background: var(--bg-elevated);
  }
}

/* ---------- tablet: tresc dostaje wiecej miejsca, .blatt zostaje na 34rem ---------- */

@media (min-width: 768px) {
  main { max-width: 44rem; }
  header {
    padding-inline: max(var(--s3), calc((100% - 44rem) / 2 + var(--s3)));
  }
  body:has(main.breit) header {
    padding-inline: max(var(--s3), calc((100% - 90rem) / 2 + var(--s3)));
  }
  .grid, .kolejka-offline { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }
}

@media (min-width: 900px) {
  ul.spalten.bauten-gruppen {
    display: block;
    columns: 20rem;
    column-gap: var(--s3);
    overflow: visible;
    background: transparent;
    box-shadow: none;
  }
  ul.bauten-gruppen > li.bauten-gruppe {
    break-inside: avoid;
    margin: 0 0 var(--s3);
    background: transparent;
  }
  .bauten-gruppe > .bauten-buchstabe { padding-left: 0; position: static; background: none; }
  .bauten-gruppe > ul { background: var(--bg-elevated); }
  .bauten-gruppe > ul > li + li { box-shadow: inset 0 1px 0 var(--separator); }
}

@media (min-width: 1024px) {
  .blatt-hinter { align-items: center; }
  .blatt {
    border-radius: var(--radius);
    padding-bottom: var(--s3);
    max-height: 80vh;
  }
  main.breit { max-width: 90rem; }
  ul.spalten {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
    gap: 1px;
    background: transparent;
    box-shadow: none;
  }
  ul.spalten > li { background: var(--bg-elevated); }
  ul.spalten > li.leerzeile { grid-column: 1 / -1; }
  ul.spalten > li + li { box-shadow: none; }
  /* Stockwerke: Spalten von oben nach unten fuellen (DB, DG, 6 ... KG untereinander), nicht zeilenweise wie das Grid. */
  ul.spalten.stockwerk-spalten { display: block; columns: 22rem; column-gap: 1px; }
  ul.stockwerk-spalten > li { break-inside: avoid; margin-bottom: 1px; }
  /* elementy inne niz listy kolumnowe nie rozciagaja sie na cala szerokosc - kazda inna
     lista (notiz-liste, regie-liste, uploads, neu-punkte...) trzyma sie wzorca
     li{display:flex; justify-content:space-between}, wiec przy 90rem rozjezdzalaby sie
     tak samo jak listy kolumnowe przed tym zadaniem (STEP 2a). */
  main.breit ul:not(.spalten) { max-width: 44rem; margin-inline: auto; }
  /* v.11.39: Verwaltung-Einstellungenliste bekommt eine eigene Klasse, damit sie aus der
     Regel oben ausgenommen werden kann, ohne Kalender/Notizen (dieselbe Regel) anzufassen. */
  main.breit ul.verwaltung-einstellungen-liste { margin-inline: 0; }
  .blatt-knopf.verwaltung-neu { width: fit-content; margin-inline: auto; flex-direction: row; align-items: center; }
  .verwaltung-abschnitt { max-width: 44rem; }
  .verwaltung-auftraggeber-form { max-width: 44rem; }
  .verwaltung-auftraggeber-form input { flex: 1 1 auto; max-width: 20rem; }
  .verwaltung-auftraggeber-form button { width: fit-content; flex: 0 0 auto; }
}

/* ---------- otwarte punkty ---------- */

.notiz-liste { margin-top: var(--s2); }
.notiz-zeile { align-items: flex-start; }
.notiz-details { min-width: 0; flex: 1; }
.notiz-titel { display: block; }
/* Kalender-Kachel: Zeit und Ort/Baustelle als eigene Zeilen statt aneinandergeklebt (v.10.44). */
.termin-details > .meta { display: block; }
.notiz-text { margin: var(--s1) 0 0; white-space: pre-wrap; }
.notiz-fotos { display: flex; gap: var(--s1); margin-top: var(--s2); overflow-x: auto; }
.notiz-fotos img { width: 55px; height: 55px; flex: none; object-fit: cover; border-radius: var(--radius); }
.notiz-check { flex: none; width: 44px; min-width: 44px; height: 44px; min-height: 44px; aspect-ratio: 1; margin: 4px; padding: 0;
  border: 1px solid var(--separator); border-radius: 50%; box-shadow: none; }
.notiz-check.erledigt { background: var(--accent); border-color: var(--accent); color: var(--accent-kontrast); }
.ist-erledigt .notiz-titel { text-decoration: line-through; color: var(--label-secondary); }
.notiz-zeile.ist-erledigt { opacity: .6; }

/* ---------- Regie ---------- */

.regie-liste { margin-top: var(--s2); }
.regie-zeile { align-items: flex-start; }
.regie-fotos { display: flex; gap: var(--s1); margin-top: var(--s2); overflow-x: auto; }
.regie-fotos img { width: 55px; height: 55px; flex: none; object-fit: cover; border-radius: var(--radius); }

/* v.13.78 (E3): heller statt #000-artigem --label-Hintergrund (Tomasz: "nervt" auf Schwarz). */
.toast { position: fixed; left: var(--s3); right: var(--s3);
         bottom: calc(var(--s3) + env(safe-area-inset-bottom)); z-index: 40;
         display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
         min-height: 44px; padding: var(--s2) var(--s3);
         background: var(--bg-elevated); color: var(--label); border-radius: var(--radius);
         box-shadow: var(--schatten); }
.toast-knopf { min-height: 44px; padding: 0 var(--s2); border: 0; box-shadow: none;
               background: none; color: var(--accent); font-weight: 600; }

.lb-loeschen, .lb-markieren, .lb-verschieben { min-width: 44px; min-height: 44px; padding: 0 var(--s2);
               border-radius: var(--radius); background: #ffffff26; color: #fff;
               box-shadow: none; font-size: 15px; }
/* v.13.76: bei @media (max-width:400px) siehe unten - Zaehler wandert dann in .lb-fuss. */
.zaehler-fuss { display: none; }
.lb-fuss { position: absolute; left: 0; right: 0;
           bottom: calc(env(safe-area-inset-bottom) + var(--s1));
           padding: var(--s2) var(--s3); text-align: center; color: #fff; font-size: 15px;
           background: linear-gradient(transparent, #000000cc); }

/* ---------- lightbox ---------- */

body.ohne-scroll { overflow: hidden; }
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 35;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000000;
  /* v.9.75: bylo touch-action:none, co zabijalo pinch - detalu na zdjeciu nie dalo sie
     obejrzec. pinch-zoom zostaje przegladarce, swipe jednym palcem nadal nasz. */
  touch-action: pinch-zoom;
  overscroll-behavior: contain;
}
.lightbox img.gross { max-width: 100%; max-height: 100%; object-fit: contain;
                      -webkit-touch-callout: none;
                      transform-origin: center center; transition: transform .18s ease; }
.lightbox img.gross.gezoomt { cursor: zoom-out; }
.lb-leiste {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  padding: calc(var(--s1) + env(safe-area-inset-top)) var(--s3) var(--s1);
  background: linear-gradient(#000000cc, transparent);
}
.zaehler { color: #fff; font-size: 15px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lb-loeschen, .lb-markieren, .lb-verschieben { white-space: nowrap; }
/* v.13.76: drittes Knopf braucht Platz - .lb-leiste bei mit-verschieben IMMER enger
   (gap/padding), nicht erst ab @media: bei 440px (Tomasz' iPhone) reicht der
   Standardabstand (gap/padding var(--s3)) mit drei Knoepfen nicht mehr (gemessen:
   ~29px Ueberlauf trotz "passt bei 440px"-Annahme der Entscheidung). Ohne den Knopf
   (kein .mit-verschieben) bleibt .lb-leiste unveraendert - K6-Regression. */
.mit-verschieben .lb-leiste { gap: var(--s1); padding-left: var(--s2); padding-right: var(--s2); }
/* Auf schmalen Screens reicht das enger Basis-Layout allein nicht - Knopf-Padding
   schrumpft zuerst, und wenn das nicht reicht wandert der Zaehler in .lb-fuss. */
@media (max-width: 400px) {
  .mit-verschieben .lb-loeschen,
  .mit-verschieben .lb-markieren,
  .mit-verschieben .lb-verschieben { padding: 0 var(--s1); }
  .mit-verschieben .zaehler { display: none; }
  .mit-verschieben .zaehler-fuss { display: inline; margin-right: var(--s1); }
}
.lb-zu, .lb-pfeil {
  min-width: 44px; min-height: 44px;
  padding: 0;
  border-radius: var(--radius);
  background: #ffffff26;
  box-shadow: none;
  color: #fff;
  font-size: 21px;
}
.lb-pfeil { position: absolute; top: 50%; transform: translateY(-50%); font-size: 28px; }
.lb-pfeil.links { left: var(--s1); }
.lb-pfeil.rechts { right: var(--s1); }

/* Elementy wydruku nie istnieja na ekranie. */
.druckkopf, .druckfuss, table.materialliste, .druck-abschnitt { display: none; }
/* v.9.32: chwilowe, jawne odslonienie do pomiaru naturalnego rozmiaru w JS (patrz
   skalujDrukMaterialMatrix() w app.js) - .druckkopf ma WLASNA regule display:none
   wyzej, wiec samo odslonienie rodzica (.druck-abschnitt) nie wystarczy, potrzebny
   jawny wyjatek i dla dziecka. Element i tak stoi poza ekranem (position:fixed,
   ustawiane w JS), user tego nie widzi. */
.druck-messung.druck-abschnitt, .druck-messung .druckkopf { display: block !important; }

/*
 * Rozmiar/uklad kratownicy materialu POZA @media print (celowo) - v.9.32 mierzy
 * naturalny (nieobciety) rozmiar tego bloku w JS PRZED wydrukiem (patrz
 * skalujDrukMaterialMatrix() w app.js), zeby policzyc wspolczynnik skalowania k
 * gwarantujacy jedna strone. Pomiar wymaga, zeby te reguly dzialaly takze poza
 * kontekstem drukowania (element pokazywany na chwile poza ekranem). Nieszkodliwe
 * na ekranie - klasy .druck-matrix/.materialmatrix istnieja WYLACZNIE w DOM-ie
 * budowanym przez druckMaterialMatrix(), ktory i tak jest ukryty regula wyzej,
 * chyba ze JS jawnie odkryje go do pomiaru.
 *
 * Kratownica materialu: JEDNA strona pozioma w dokumencie, ktorego reszta zostaje
 * portretowa (@page NIE jest dotykane - `page:`/nazwane strony nie dzialaja w
 * Safari/iOS, wiec zamiast tego caly blok jest obrocony o 90st. w ramach zwyklej
 * strony portrait. 271mm x 184mm = obszar strony A4 (297x210) minus marginesy @page
 * (13mm z kazdej strony), zamieniony bokami - to jest FIZYCZNY BUDZET, do ktorego
 * v.9.32 dopasowuje skalowaniem k, nie sztywnym rozmiarem kontenera.
 */
/* v.9.35: overflow:hidden - siatka zabezpieczajaca przeciw pustej 2. stronie z zaokraglen
   Quartz/WebKit na granicy 271mm (real-PDF, historia v.9.29/v.9.32). Height 271mm ZOSTAJE
   dokladnie na budzecie (proba zmniejszenia go w v.9.29 byla bledem - mniej miejsca na TA
   SAMA tresc, pogarsza przeciekanie) - to jest czysto DEFENSYWNE przyciecie ewentualnego
   sub-milimetrowego naddatku, nie zmiana budzetu. Nie tnie normalnie sprawdzonej tresci -
   .druck-matrix-dreh jest teraz poprawnie skalowany DOKLADNIE w budzet (scale w
   skalujDrukMaterialMatrix(), app.js), overflow:hidden dziala jako ostatnia linia obrony,
   nie jako mechanizm dopasowania. */
.druck-matrix { position: relative; height: 271mm; overflow: hidden; }
.druck-matrix-dreh {
  position: absolute; top: 0; left: 0;
  /* v.9.35: SZEROKOSC PRZYBITA do budzetu (271mm) - v.9.32 mial ja shrink-to-fit,
     co przy 15 pietrach dawalo tabele 360mm szeroka (48+12+15*20mm), wiec pomiar
     liczyl WSPOLCZYNNIK SZEROKOSCI 271/360=0,75 - mniejszy niz potrzeba, i ten sam
     jednolity k (brany jako MIN z obu osi) kurczyl tez wysokosc bardziej niz
     trzeba, zostawiajac kratownice mala w rogu z pustym marginesem. Szerokosc
     PRZYBITA eliminuje ten wspolczynnik z gry calkowicie - k liczy sie juz TYLKO
     z wysokosci (patrz skalujDrukMaterialMatrix() w app.js). WYSOKOSC zostaje
     naturalna (shrink-to-fit) - to jest jedyna os, ktora mierzymy i skalujemy. */
  width: 271mm;
  transform-origin: top left;
  transform: rotate(90deg) translateY(-100%);
}
/* Naglowek dokumentu mniejszy TYLKO tutaj - dzieli te same 184mm z tabela, a przy
   duzej liczbie wierszy kazdy milimetr sie liczy. */
.druck-matrix .druckkopf { margin-bottom: 2mm; }
.druck-matrix .druckmarke { gap: 2mm; margin-bottom: 1mm; }
.druck-matrix .druckmarke .gmerek-zeichen { width: 7mm; height: 7mm; }
.druck-matrix .druckkopf h1 { font-size: 11pt; margin: 0; }
.druck-matrix .druckkopf .zeile { font-size: 6.5pt; line-height: 1.2; }

table.materialmatrix { display: table; border-collapse: collapse; table-layout: fixed; width: 100%; }
table.materialmatrix thead { display: table-header-group; }
table.materialmatrix tbody { display: table-row-group; }
/* v.9.35: width:100% (rodzica .druck-matrix-dreh, teraz przybitego do 271mm) zamiast
   JS-owej sumy N*20mm+60mm. Sprawdzone w v.9.32: table-layout:auto w kontenerze BEZ
   wlasnej szerokosci dawal patologiczny wynik (kolumna Artikel ~23px) - to nie problem
   "auto" per se, tylko brak jawnej szerokosci rodzica, ktora teraz jest (271mm, wyzej).
   BEZ page-break-inside:avoid na <tr> - w WebKit to wymuszalo przeniesienie CALEGO
   ostatniego wiersza na druga strone. Skalowanie k jest GWARANCJA jednej strony, nie
   sztywne tiery czcionki - te zostaja jako baza czytelnosci PRZED skalowaniem.
   v.9.36: BLAD w powyzszym zalozeniu (v.9.35) - "table-layout:fixed rozklada kolumny
   proporcjonalnie, gdy suma nie zgadza sie z 271mm" byl PRAWDZIWY tylko gdy suma <
   271mm (extra miejsce faktycznie sie rozklada). Gdy suma > 271mm (>=11 pieter: 48 +
   12 + 11*20 = 280mm), fixed layout NIE kurczy - wedlug CSS 2.1 17.5.2.1 uzywana
   szerokosc tabeli to WIEKSZA z (width:100%, suma zadeklarowanych kolumn), wiec tabela
   po prostu rosla ponad 271mm i WebKit lamal ja na 2. strone (kolumny Gesamt.materiał
   znikaly u Tomasza na iOS - zgloszenie, real-PDF). `.material` NIE MA JUZ jawnej
   szerokosci (usunieta) - w fixed layout kolumny bez width dziela RESZTE (271-48-12=
   211mm) po rowno miedzy siebie, wiec suma NIGDY nie przekroczy 271mm bez wzgledu na N.
   Przy malej liczbie pieter kolumny nadal wychodza szersze niz przy duzej - to zostaje,
   tylko liczone teraz przez sama przegladarke (auto-podzial reszty), nie przez
   deklarowana (i przy N>=11 blednie zbyt duza) sume 20mm/kolumne. */
table.materialmatrix th, table.materialmatrix td {
  border: .3pt solid #ccc; padding: .5mm 1mm; text-align: center;
  line-height: 1.1;
}
/* Etykieta (nazwa artykulu) i naglowek kolumny (pietro) czytelne wprost - caly blok
   jest juz obrocony o 90st. jako calosc (patrz .druck-matrix-dreh), wiec nie potrzeba
   dodatkowego writing-mode na pojedynczych komorkach. BEZ nowrap/ellipsis na etykiecie -
   v.9.26 obcinal nazwy artykulow, to byl glowny zarzut, teraz zawijaja sie normalnie. */
table.materialmatrix .etykieta { width: 48mm; text-align: left; white-space: normal;
  word-break: break-word; }
/* v.9.36: BEZ width - patrz komentarz wyzej przy width:100% (fixed layout dzieli
   reszte 271-48-12=211mm po rowno miedzy kolumny .material, suma NIGDY nie
   przekroczy 271mm, niezaleznie od N). */
table.materialmatrix .gesamt { width: 12mm; font-weight: 700; background: #f2f2f2; }
table.materialmatrix tr.matrix-summe td { border-top: 2px solid #000; font-weight: 700; background: #f2f2f2; }
/* Naglowek kolumn (pietra) i pierwsza kolumna (nazwy artykulow) - gruba ramka na
   zewnetrznej krawedzi calego bloku "opis", oddzielajaca go od bloku "dane" (ilosci).
   border-collapse bierze szerszy z dwoch sasiadujacych brzegow, wiec wystarczy
   zadeklarowac to tu - miedzy naglowkiem a pierwszym wierszem danych i miedzy
   kolumna etykiet a pierwsza kolumna danych automatycznie wychodzi gruba linia. */
table.materialmatrix thead th { border-top: 1.2pt solid #000; border-bottom: 1.2pt solid #000; }
table.materialmatrix .etykieta { border-left: 1.5pt solid #000; border-right: 1.5pt solid #000; }

/*
 * Gestosc/wysokosc wiersza zalezna od liczby UZYWANYCH artykulow (wiersze) - katalog
 * rosnie na biezaco. Font-size na CALYM wierszu (th,td), nie tylko .material - inaczej
 * etykieta/gesamt (bez override) zostawaly przy najwiekszym foncie i to ONE dyktowaly
 * wysokosc wiersza. Te progi to BAZA czytelnosci PRZED skalowaniem k (v.9.32) - k
 * dopiero potem gwarantuje, ze calosc (przy tej bazie) zmiesci sie w jednej stronie.
 */
table.materialmatrix.matrix-gesty th, table.materialmatrix.matrix-gesty td { font-size: 8pt; padding: 1mm 1.5mm; }
table.materialmatrix.matrix-sredni th, table.materialmatrix.matrix-sredni td { font-size: 6pt; padding: .5mm 1mm; }
table.materialmatrix.matrix-waski th, table.materialmatrix.matrix-waski td { font-size: 4.5pt; padding: .2mm .6mm; }

/* ---------- wydruk ---------- */

@media print {
  /* Wydruk jest zawsze czarny na bialym, niezaleznie od trybu ciemnego na ekranie. */
  :root {
    --bg: #fff; --bg-elevated: #fff; --label: #000;
    --label-secondary: #000; --separator: #888; --schatten: none;
  }
  @page { size: A4 portrait; margin: 13mm; }

  body { background: #fff; color: #000; font-size: 11pt; }
  header, .lightbox { display: none !important; }
  main { max-width: none; margin: 0; padding: 0; }

  /* Na papier idzie WYLACZNIE tabela materialu - cala reszta ekranu znika. */
  /* #druckbereich jest kontenerem sekcji, sam klasy nie nosi - bez tego wyjatku
     regula chowala go razem z cala zawartoscia i z drukarki wychodzila sama stopka. */
  #app > *:not(.druck-abschnitt):not(.druckfuss):not(#druckbereich) { display: none !important; }
  #druckbereich { display: block !important; }
  .druck-abschnitt { display: block !important; }

  .druckkopf { display: block !important; margin-bottom: var(--s3); }
  .druckkopf h1 { font-size: 18pt; margin: 0 0 var(--s1); }
  /* Znak Gmerek IT obok nazwy budowy - na papierze zawsze czarny. */
  .druckmarke { display: flex !important; align-items: center; gap: var(--s2); }
  .druckmarke .gmerek-zeichen { display: block !important; width: 13mm; height: 13mm;
                                color: #000; }
  .druckmarke h1 { margin: 0; }
  .druckkopf .zeile { font-size: 10pt; }

  /* v.9.40: Firmenlogo (blau) zentriert ueber der Tabelle - gleiches Bild/Layout wie
     im PDF der Materialmatrix (src/pdf_matrix.php). Ausserhalb von @media print bleibt
     es versteckt, weil der Elternknoten .druck-abschnitt schon display:none hat
     (Regel oben in der Datei, ausserhalb dieses Blocks). */
  .druck-logo { display: block; margin: 0 auto 4mm; max-width: 60mm; max-height: 20mm; }

  table.materialliste { display: table !important; width: 100%; border-collapse: collapse; }
  table.materialliste tbody { display: table-row-group; }
  table.materialliste tfoot { display: table-footer-group; }
  table.materialliste thead { display: table-header-group; }   /* naglowek na kazdej stronie */
  table.materialliste tr { page-break-inside: avoid; }
  table.materialliste th {
    text-align: left; font-size: 9pt; text-transform: uppercase; letter-spacing: .06em;
    border-bottom: 1px solid #000; padding: var(--s1) 0;
  }
  table.materialliste td { padding: var(--s1) 0; border-bottom: 1px solid #ddd; }
  table.materialliste .nr { width: 8%; color: #555; }
  table.materialliste .menge, table.materialliste .einheit { text-align: right; width: 13%; }
  table.materialliste tfoot td { border-top: 1px solid #000; border-bottom: 0; font-weight: 700; }

  .druck-abschnitt { page-break-after: always; }
  .druck-abschnitt:last-child { page-break-after: auto; }
  .druckfuss { display: block !important; margin-top: var(--s3); font-size: 9pt; color: #555; }

  /* .druck-matrix zajmuje cala wysokosc strony - stopka po niej nie ma juz miejsca i
     wypycha druga, prawie pusta strone. W obroconej orientacji i tak by nie byla
     czytelna, wiec znika calkowicie zamiast dokladac strone. Rozmiar/uklad samej
     kratownicy - patrz sekcja PRZED @media print (potrzebna tam do pomiaru w JS). */
  #druckbereich:has(.druck-matrix) + .druckfuss { display: none !important; }
}

/* v.10.30: ekran Warteschlange (Diagnose) w Einstellungen - stan kolejki do wklejenia
   z telefonu. Monospace i lamanie, bo to zrzut do skopiowania, nie element UI. */
.diagnose { font-family: ui-monospace, Menlo, monospace; font-size: 11px; line-height: 1.5;
  white-space: pre-wrap; word-break: break-all; user-select: text; -webkit-user-select: text;
  max-height: 45vh; overflow: auto; padding: var(--s2); border-radius: var(--radius);
  background: var(--bg-elevated); color: var(--label-secondary); }
.diagnose-knoepfe { display: flex; gap: var(--s1); margin-top: var(--s1); }

/* v.13.11: Auftraggeber nur lesend - Knoepfe zum Schreiben weg (Server prueft ohnehin, app.js nurLesen). */
.nur-lesen .schreiben { display: none !important; }

.kamera-kopf .kamera-system { width: auto; padding: 0 12px; border-radius: 8px; margin-left: 8px; background: #1c1d21; }

/* v.15.39 (E): Ersatzfeld haelt die iOS-Tastatur offen zwischen Katalog-Tipp und Mengenfeld
   (font-size 16px: kein Zoom beim Fokus). Neue Zeile kurz hervorgehoben. */
.fokus-ersatz { position: fixed; top: 0; left: 0; width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; font-size: 16px; pointer-events: none; }
.material-zeile.hervor { animation: material-hervor 1.2s ease-out; }
@keyframes material-hervor { from { background-color: color-mix(in srgb, var(--accent) 25%, transparent); } }
/* v.15.39 (F): Material-Knopf im Kamera-Kopf, Form wie .kamera-system. */
.kamera-kopf .kamera-material { margin-left: 13px; }

/* v.15.54: Kamera im Querformat wie die iPhone-Kamera - Vorschau ueber die ganze Hoehe in der
   Mitte, links die runden Knoepfe (Lampe, Material, Schliessen unten), rechts Fertig / Ausloeser / Miniatur.
   Ausloeser 72 px zu Knopf 44 px ~ phi; Abstaende 13/21 px (Fibonacci). max-height: nur Handys,
   ein Tablet quer behaelt das Hochformat-Layout mit Kopf und Fuss. */
@media (orientation: landscape) and (max-height: 540px) {
  /* Mittelspalte = 4:3 der Hoehe (Stream 1920x1440), Seitenspalten teilen sich den Rest gleich -
     Vorschau mittig, Knoepfe mittig in ihrer Spalte. */
  .kamera-blatt { grid-template-rows: none; grid-template-columns: minmax(70px, 1fr) minmax(0, calc(100dvh * 4 / 3)) minmax(89px, 1fr); }
  .kamera-kopf { flex-direction: column; justify-content: flex-start; align-items: center; gap: 21px;
    padding: max(13px, env(safe-area-inset-top)) 13px max(13px, env(safe-area-inset-bottom)) max(13px, env(safe-area-inset-left)); }
  /* v.15.55: ta sama kolejnosc co w pionie (Lampe, Material ... X) - X osobno na koncu kolumny,
     tak jak w pionie stoi osobno na prawym koncu paska (Tomasz 15.10: nie zmieniamy kolejnosci). */
  .kamera-kopf button:last-child { margin: auto 0 0; }
  .kamera-kopf .kamera-material { margin-left: 0; }
  .kamera-fuss { grid-template-columns: none; grid-template-rows: 1fr auto 1fr; justify-items: center; min-width: 89px;
    padding: max(13px, env(safe-area-inset-top)) max(13px, env(safe-area-inset-right)) max(13px, env(safe-area-inset-bottom)) 13px; }
  .kamera-fuss > button:first-child { justify-self: center; align-self: start; }
  .kamera-miniatur-wrap { justify-self: center; align-self: end; margin-right: 0; }
  /* Zaehler ueber der Miniatur statt auf ihr - im Querformat ist dafuer Platz. */
  .kamera-zaehler { top: auto; right: auto; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%); font-size: 21px; }
}

/* v.15.50: Zeile 2 eines LV-Artikels - kleiner, grau, bei schmalem Bildschirm mit Ellipsis. */
.artikel-text { display: flex; flex-direction: column; min-width: 0; text-align: left; }
.lv-zeile { color: var(--label-secondary); font-size: 12px; font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
li.alle-artikel { font-weight: 600; text-transform: none; padding-top: 12px; }

/* v.15.50: Leiste "Neue Version verfuegbar" - oben, ueber allem, Notch beachten. */
#neue-version { position: fixed; top: 0; left: 0; right: 0; z-index: 9999; display: flex; gap: 12px; align-items: center; justify-content: center;
  padding: calc(env(safe-area-inset-top, 0px) + 8px) 12px 8px; background: var(--accent); color: var(--accent-kontrast, #fff); font-size: 14px; }
#neue-version button { background: transparent; border: 1px solid currentColor; color: inherit; border-radius: 8px; padding: 4px 10px; font: inherit; font-weight: 600; }

/* v.15.51: Verwaltung > Einstellungen - Gruppen als Karten, Schalter, Segment.
   Abstand zwischen Gruppen (21 px) groesser als zwischen Zeilen (13 px) ~ 1:1,618. */
.einst-gruppen { display: flex; flex-direction: column; gap: var(--s3); max-width: 44rem; }
.einst-gruppe > h2 { margin: 0 0 var(--s1); }
ul.einst-karte { background: var(--bg-elevated); border: 1px solid var(--separator); border-radius: var(--radius); overflow: hidden; margin: 0; padding: 0; list-style: none; }
ul.einst-karte > li.einst-zeile { background: transparent; border-radius: 0; box-shadow: none; margin: 0; min-height: 44px; padding: var(--s2) var(--s3); display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
ul.einst-karte > li.einst-zeile + li.einst-zeile { border-top: 1px solid color-mix(in srgb, var(--label) 22%, transparent); }
.einst-label { font-size: 17px; color: var(--label); }
.einst-zeile .meta { font-size: 13px; color: var(--label-secondary); }
.einst-hinweis { margin-top: 2px; }
input.einst-zahl { width: 6.5em; max-width: 6.5em; text-align: right; flex: 0 0 auto; }
li.einst-zeile > input:not(.einst-zahl) { flex: 0 1 14rem; text-align: right; }
li.einst-zeile-segment { flex-wrap: wrap; }
li.einst-zeile-segment .einst-segment { flex: 0 0 auto; min-width: 11rem; margin-bottom: 0; }
ul.einst-karte > li.einst-zeile:has(> .einst-schalter) { padding: 0; }
.einst-schalter { all: unset; box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: var(--s2); width: 100%; min-height: 56px; padding: var(--s2) var(--s3); cursor: pointer; touch-action: manipulation; }
.einst-schalter:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.einst-schalter[disabled] { opacity: .6; }
.einst-track { position: relative; flex: 0 0 auto; width: 51px; height: 31px; border-radius: 16px; background: color-mix(in srgb, var(--label) 28%, transparent); transition: background .2s ease-out; }
.einst-daumen { position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px #0004; transition: transform .2s ease-out; }
.einst-schalter.an .einst-track { background: var(--ok); }
.einst-schalter.an .einst-daumen { transform: translateX(20px); }
@media (prefers-reduced-motion: reduce) { .einst-track, .einst-daumen { transition: none; } }
