@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');/* Bericht Form - Dark Theme wie Hauptdesign */
.bericht-page { max-width: 600px; margin: 0 auto; padding: 0 0 5rem; }
/* Mobile: Platz für fixed lang-bar (40px) und mobile-nav (60px) */
@media(max-width:768px) {
  .bericht-page { padding-top: 44px; }
}

/* ══ S65: DESKTOP-Layout (ab 1100 px zweispaltig) ══════════════════════
   FK: „kannst du bitte den edit modus auch noch optimal zusätzlich auf
   DesktopVersion anpassen". Gemessen: bei 1500 px Viewport war die Seite
   600 px breit und einspaltig — 900 px ungenutzt.

   Warum ein GRID und nicht nur mehr Breite: eine breitere einspaltige
   Zeile „Menge / Einheit / Trommel-Nr." wäre eine breitere einspaltige
   Zeile. Der Hebel ist die zweite Spalte.

   `.sec-breit-*` = Sektionen, die durchgehend laufen. Fotos, Referenzen
   und Scans enthalten Bilder/Tabellen; halbiert wären sie unbrauchbar.
   Der Kopfbereich (Fortschritt + Typ) bleibt einspaltig darüber. */
@media(min-width:1100px) {
  .bericht-page { max-width: 1240px; }
  .sec-raster { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; align-items: start; }
  .sec-raster > .sec-slot { min-width: 0; }   /* Grid-Standard min-content kann
                                               die Spalte sprengen (lange
                                               Tabellen/Adressen) */
  /* Durchgehende Sektionen */
  .sec-raster > .sec-breit-fotos,
  .sec-raster > .sec-breit-referenzen,
  .sec-raster > .sec-breit-kopfdaten { grid-column: 1 / -1; }
  /* In einer 2-Spalten-Sektion: Kopfzeile links, Inhalt rechts — sonst
     stünde die 1. Zeile allein in der linken Hälfte. */
  .sec-raster > .sec-slot > .sec { margin: 0; }
  .bericht-page .btn-area { max-width: none; }
}

.error-bar { background: rgba(239,68,68,.15); color: var(--red); padding: .6rem 1rem; border-radius: 6px; margin: .5rem 0; font-size: .85rem; font-weight: 500; }

/* Sections */
.sec { background: var(--bg2); border: 1px solid var(--bg3); border-radius: 10px; margin: 10px 0; overflow: hidden; }
.sec-h {
  display: flex; align-items: center; gap: 6px; padding: 10px 14px; cursor: pointer;
  background: var(--bg3); border-bottom: 1px solid var(--bg3); font-weight: 600; font-size: 13px;
  color: var(--fg); user-select: none;
}
.sec-h span:first-of-type { flex: 1; }
.sec-h .toggle { font-size: 11px; color: var(--fg3); }
.sec-b { padding: 10px 14px; }

/* Labels */
.sec-b label { display: block; font-size: 11px; font-weight: 500; color: var(--fg2); margin-bottom: 2px; margin-top: 6px; }
.sec-b label:first-child { margin-top: 0; }

/* Inputs */
.sec-b input, .sec-b select, .sec-b textarea {
  width: 100%; padding: 7px 10px; border: 1px solid var(--bg3); border-radius: 6px;
  font-size: 13px; background: var(--bg); color: var(--fg); font-family: inherit;
}
.sec-b input:focus, .sec-b select:focus, .sec-b textarea:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 2px rgba(59,130,246,.2);
}
.sec-b .ro { background: var(--bg3); color: var(--fg3); cursor: default; }
.sec-b textarea { resize: vertical; min-height: 60px; }

.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

.auto { background: rgba(59,130,246,.15); color: var(--blue); font-size: 9px; padding: 1px 5px; border-radius: 4px; font-weight: 600; }

/* Weather */
.w-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-bottom: 8px; }
.w-btn {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 4px; border: 2px solid var(--bg3); border-radius: 8px;
  background: var(--bg); cursor: pointer; font-size: 11px; color: var(--fg2);
}
.w-btn .ico { font-size: 20px; }
.w-btn.on { border-color: var(--blue); background: rgba(59,130,246,.1); color: var(--blue); font-weight: 600; }

/* Quick buttons */
.quick-btns { display: flex; gap: 5px; margin-top: 8px; flex-wrap: wrap; }
.q-btn {
  padding: 5px 10px; border: 2px solid var(--blue); border-radius: 14px;
  background: transparent; color: var(--blue); font-size: 11px; font-weight: 600; cursor: pointer;
}
.q-btn:active { background: rgba(59,130,246,.15); }

.add-btn {
  border: 2px dashed var(--bg3); border-radius: 7px; padding: 8px 14px;
  background: transparent; cursor: pointer; font-size: 13px; color: var(--blue); font-weight: 600; flex: 1;
}

.del-btn { background: none; border: none; color: var(--red); font-size: 16px; cursor: pointer; padding: 2px 6px; }
.del-btn:active { background: rgba(239,68,68,.15); }

/* Tables */
.mach-tbl, .mat-tbl { width: 100%; border-collapse: collapse; font-size: 12px; }
.mach-tbl th, .mat-tbl th { text-align: left; font-size: 11px; color: var(--fg3); font-weight: 500; padding: 4px 0; }
.mach-tbl td, .mat-tbl td { padding: 3px 4px; }
.mach-tbl input, .mach-tbl select, .mat-tbl input { font-size: 12px; padding: 5px 6px; }
.mach-tbl tr, .mat-tbl tr { border-bottom: 1px solid var(--bg3); }

.mach-add { margin-top: 8px; }
.mach-add button {
  width: 100%; border: 2px dashed var(--bg3); border-radius: 7px; padding: 8px;
  background: transparent; cursor: pointer; font-size: 12px; color: var(--blue); font-weight: 600;
}

/* FTTH Grid */
.ftth-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; }
.ftth-grid label { font-size: 11px; }
.ftth-grid input { font-size: 12px; padding: 6px 8px; }
.ftth-sep { grid-column: 1/-1; height: 1px; background: var(--bg3); margin: 4px 0; }

.total { text-align: right; font-size: 14px; font-weight: 700; color: var(--blue); white-space: nowrap; }
.hint { font-size: 11px; color: var(--fg3); margin-bottom: 4px; }

/* Photos */
.foto-area { text-align: center; }
.foto-btns { display: flex; gap: 10px; justify-content: center; margin-bottom: 10px; }
.foto-btn {
  display: flex; align-items: center; gap: 6px; padding: 10px 16px;
  border: 2px solid var(--blue); border-radius: 8px; background: transparent;
  color: var(--blue); font-size: 13px; font-weight: 600; cursor: pointer;
}
.foto-btn:active { background: rgba(59,130,246,.15); }
.foto-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; }
.foto-thumb { position: relative; border-radius: 6px; overflow: hidden; aspect-ratio: 1; }
.foto-thumb img { width: 100%; height: 100%; object-fit: cover; }
.foto-del {
  position: absolute; top: 2px; right: 2px; background: rgba(0,0,0,.6); color: #fff;
  border: none; border-radius: 50%; width: 20px; height: 20px; font-size: 10px;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
/* Lightbox info panel */
.lb-panel { width: 300px; background: var(--bg2); border-left: 1px solid var(--bg3); overflow-y: auto; padding: 1rem; font-size: .8rem; color: var(--fg); flex-shrink: 0; }
@media(max-width:768px) {
  .lb-panel {
    position: fixed; bottom: 0; left: 0; right: 0; width: 100%;
    max-height: 45vh; border-left: none; border-top: 1px solid var(--bg3);
    border-radius: 12px 12px 0 0; z-index: 10001;
  }
}

/* Buttons */
.btn-area { display: flex; gap: 8px; margin-top: 12px; }
.btn-area .btn { flex: 1; justify-content: center; padding: 10px; font-size: 13px; font-weight: 600; }

/* Mitarbeiter Tabelle */
.ma-table { width: 100%; border-collapse: collapse; font-size: .8rem; }
.ma-table th { text-align: left; font-size: .7rem; color: var(--fg3); font-weight: 500; text-transform: uppercase; letter-spacing: .5px; padding: .5rem .6rem; border-bottom: 1px solid var(--bg3); }
.ma-table td { padding: .5rem .6rem; border-bottom: 1px solid var(--bg3); vertical-align: top; }
.ma-table tr:hover td { background: rgba(59,130,246,.03); }
.ma-table .name-cell { font-weight: 600; }
.ma-table .sub { font-size: .7rem; color: var(--fg3); }
.ma-table .actions { display: flex; gap: .25rem; flex-wrap: wrap; }

/* Stunden-Anzeige */
.stunden-badge { display: inline-block; background: rgba(59,130,246,.15); color: var(--blue); padding: .15rem .4rem; border-radius: 4px; font-size: .7rem; font-weight: 600; }

@media (max-width: 400px) {
  .row2 { grid-template-columns: 1fr; }
  .ftth-grid { grid-template-columns: 1fr; }
  .w-grid { grid-template-columns: repeat(2, 1fr); }
  .foto-grid { grid-template-columns: repeat(2, 1fr); }
  .ma-table { font-size: .75rem; }
  .ma-table th, .ma-table td { padding: .4rem; }
}
/* Projekt-Leiter (Leistungsverzeichnis) — Session 50
   Responsive: Desktop / Tablet / Handy */

.pl { display: flex; flex-direction: column; gap: .75rem; min-width: 0; }

.pl-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: .5rem; }
.pl-sub { font-size: .72rem; color: var(--fg3); }
.pl-subnav { display: flex; gap: .35rem; }
.pl-tab {
  font-size: .78rem; padding: .35rem .7rem; border-radius: 999px;
  background: var(--bg3); color: var(--fg2); border: 1px solid var(--border);
}
.pl-tab.active { background: var(--blue); color: #fff; border-color: transparent; font-weight: 600; }
.pl-tab.disabled { opacity: .6; cursor: default; }
.pl-tab em { font-style: normal; font-size: .68rem; opacity: .8; }

.pl-msg {
  font-size: .8rem; padding: .5rem .7rem; border-radius: var(--radius);
  background: var(--bg3); border: 1px solid var(--blue); color: var(--fg);
}
.pl-card { display: flex; flex-direction: column; gap: .6rem; /* S50: min-width:0 — sonst drückt die Tabellen-Mindestbreite die ganze Seite breiter (Flexbox-Trap) */ min-width: 0; max-width: 100%; }

.pl-row { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; }
.pl-row label { font-size: .78rem; font-weight: 600; color: var(--fg2); }
.pl-row select, .pl-row input, .pl-suche, .pl-grpinput {
  font-size: .82rem; padding: .35rem .5rem; border: 1px solid var(--border);
  border-radius: 6px; background: var(--bg2); color: var(--fg); max-width: 100%;
}
.pl-row input { flex: 1; min-width: 160px; }
.pl-grpinput { width: 130px; padding: .15rem .35rem; }

.pl-lvtools { border-top: 1px dashed var(--border); padding-top: .55rem; }
.pl-filebtn { cursor: pointer; }

.pl-pill {
  display: inline-flex; align-items: center; gap: .3rem; font-size: .74rem;
  padding: .2rem .55rem; border-radius: 999px; background: var(--bg3);
  border: 1px solid var(--border); color: var(--fg2); white-space: nowrap;
}
.pl-pill b { font-weight: 700; }
.pl-pill.grp { cursor: pointer; user-select: none; }
.pl-pill.grp.on { background: var(--blue); color: #fff; border-color: transparent; }
.pl-pill.grp.new { border-style: dashed; cursor: pointer; }
.pl-pill-actions { font-style: normal; display: inline-flex; gap: .1rem; margin-left: .15rem; }
.pl-pill-actions button { background: none; border: none; cursor: pointer; font-size: .7rem; padding: 0 .1rem; color: inherit; opacity: .75; }
.pl-pill-actions button:hover { opacity: 1; }
.pl-pill.running { background: #f59e0b22; border-color: #f59e0b; color: #b45309; }
.pl-pill.err { background: var(--bg3); border-color: var(--red); color: var(--red); }
.pl-ueb { display: flex; flex-wrap: wrap; gap: .35rem; }

.pl-lvlist { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: .55rem; }
.pl-lvcard {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  padding: .6rem .7rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg2); cursor: pointer; transition: border-color .15s, transform .1s;
}
.pl-lvcard:hover { border-color: var(--blue); }
.pl-lvcard:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.pl-lvcard-title { font-weight: 600; font-size: .88rem; }
.pl-lvcard-meta { font-size: .72rem; color: var(--fg3); margin-top: .15rem; }
.pl-lvcard-actions { display: flex; gap: .25rem; flex-shrink: 0; }
.pl-empty { font-size: .8rem; color: var(--fg3); padding: .7rem .3rem; text-align: center; }

.pl-lvhead { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; }
.pl-lvhead-title { display: flex; flex-direction: column; min-width: 0; }
.pl-lvhead-title strong { font-size: 1rem; }
.pl-lvhead-actions { margin-left: auto; display: flex; gap: .25rem; }

/* S61: FK „der graue rahmen im hintergrund nicht komplett, entweder so lange
   oder zu kurz. ich denke eher zu kurz."

   Root-Cause: Es gab gar KEINEN Rahmen um `.pl-lvhead` — die sichtbare
   Begrenzung war der 1px-Rand des umgebenden `.card`, der wegen
   `gap:.6rem` und `padding:1rem` deutlich neben dem Kopf liegt. Sichtbar
   bleibt also nur ein Stück Kartenrand, nicht der Kopf selbst.
   Fix: eigener Kasten um den Kopf, mit Rahmen, Innenabstand und
   Untergrenze — der Rahmen umschließt die Kopfzeile jetzt vollständig
   UND greift den Bereich darunter mit auf (per negativem Außenabstand),
   damit er nicht als zweiter, konkurrierender Rahmen wirkt. */
.pl-lvhead-box {
  border: 1px solid var(--bg3);
  border-left: 4px solid var(--blue);
  border-radius: var(--radius);
  background: var(--bg3);
  padding: .55rem .7rem;
  margin: -.25rem 0 .1rem;
}

.pl-summen { display: flex; flex-wrap: wrap; gap: 1rem; }
.pl-summen > div { display: flex; flex-direction: column; font-size: .78rem; }
.pl-summen span { color: var(--fg3); font-size: .68rem; text-transform: uppercase; letter-spacing: .4px; }
.pl-summen b { font-size: .95rem; }
.pl-quelle { max-width: 260px; }
.pl-quelle b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pl-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; min-width: 0; }
.pl-suche { flex: 1 1 190px; min-width: 160px; max-width: 100%; }
/* S61: FK „kannst du dort um die suche immer einen rahmen machen, sonst faellt
   die suchleiste gar nicht so auf" — die Suche bekommt einen kräftigen Rahmen,
   Hintergrund und Fokusrahmen, damit sie als Werkzeug erkennbar ist. */
.pl-suchebox {
  display: flex; align-items: center; gap: .35rem; flex: 1 1 240px; min-width: 190px;
  max-width: 100%; padding: .12rem .5rem .12rem .6rem;
  background: var(--bg); border: 2px solid var(--fg3); border-radius: 9px;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.25);
}
.pl-suchebox:focus-within { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(59,130,246,.25); }
.pl-suchebox .pl-suche-lupe { font-size: .9rem; opacity: .75; pointer-events: none; }
.pl-suchebox .pl-suche { border: none; background: transparent; padding: .35rem 0; min-width: 0; }
.pl-suchebox .pl-suche:focus { outline: none; }
.pl-suche-clear {
  border: none; background: var(--bg3); color: var(--fg2); cursor: pointer;
  border-radius: 50%; width: 20px; height: 20px; line-height: 1; font-size: .7rem;
  display: inline-flex; align-items: center; justify-content: center; padding: 0;
}
.pl-suche-clear:hover { background: var(--red); color: #fff; }
.pl-seg { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.pl-seg button {
  font-size: .75rem; padding: .32rem .6rem; border: none; background: var(--bg2);
  color: var(--fg2); cursor: pointer;
}
.pl-seg button.active { background: var(--blue); color: #fff; font-weight: 600; }

.pl-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; font-size: .75rem; }
/* S61b: FK: „das + Zu Gruppen hinzufügen ist mit der schwarzen Farbe absolut nicht
   richtig lesbar. bitte auch eine umrandung und eine andere schriftfarbe wählen."
   Der native Select übernimmt sonst die System-Farben (schwarz auf dunkel). */
.pl-gruppe-select{
  font-size:.75rem;padding:.3rem .5rem;min-width:170px;max-width:100%;
  background:var(--bg2);color:var(--fg);
  border:1px solid var(--blue);border-radius:7px;
}
.pl-gruppe-select:hover{border-color:var(--blue-dark);color:var(--fg)}
.pl-gruppe-select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 2px rgba(59,130,246,.25)}
.pl-gruppe-select option{background:var(--bg2);color:var(--fg)}
/* Gleiche Behandlung für die Auswahl-Gruppe (Baustelle/Tagesbericht in der Toolbar) */
.pl-gruppen { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }

/* Tabelle */
.pl-tablewrap { overflow-x: auto; max-height: 62vh; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius); min-width: 0; max-width: 100%; }
.pl-table { font-size: .8rem; min-width: 640px; }
.pl-table thead th { position: sticky; top: 0; z-index: 2; background: var(--bg3); font-size: .7rem; text-transform: uppercase; letter-spacing: .4px; }
.pl-table td, .pl-table th { padding: .35rem .5rem; }
.pl-col-chk { width: 28px; text-align: center; }
.pl-col-fav { width: 30px; text-align: center; }
.pl-col-pos { width: 92px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.pl-col-menge { width: 76px; }
.pl-col-einheit { width: 58px; }
.pl-col-ep, .pl-col-sum { width: 96px; }
.pl-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.pl-rowpos { cursor: pointer; }
.pl-rowpos:hover { background: var(--bg3); }
.pl-rowpos.marked { background: var(--bg3); }
.pl-catrow { background: var(--bg3); font-weight: 600; }
.pl-catrow td { border-top: 2px solid var(--border); font-size: .78rem; }
/* S61: FK „das grau z.b. bei 1. Verkehrsicherung ist viel zu schwach, das kann
   man fast nicht lesen". --fg3 (#64748b) auf #334155-Hintergrund ist ein
   Kontrast von ~1,7:1 — weit unter der Lesegrenze. Deshalb:
   Ebene 1 = vollweiß, Ebene 2 = --fg, Ebene 3 = --fg2, und alle Ebenen
   bekommen zusätzlich eine linke Akzentfarbe, damit die Gliederung auch ohne
   Farbsehen erkennbar bleibt. */
.pl-catrow[data-ebene='1'] .pl-catcell { color: var(--fg); font-weight: 700; font-size: .82rem; }
.pl-catrow[data-ebene='2'] .pl-catcell { color: var(--fg); font-weight: 600; }
.pl-catrow[data-ebene='3'] .pl-catcell { color: var(--fg2); font-weight: 600; }
.pl-catrow[data-ebene='4'] .pl-catcell,
.pl-catrow[data-ebene='5'] .pl-catcell { color: var(--fg2); font-weight: 500; }
.pl-catrow .pl-catcell { border-left: 4px solid transparent; }
.pl-catrow[data-ebene='1'] .pl-catcell { border-left-color: var(--blue); }
.pl-catrow[data-ebene='2'] .pl-catcell { border-left-color: var(--teal); }
.pl-catrow[data-ebene='3'] .pl-catcell { border-left-color: #f59e0b; }
.pl-catcell { white-space: normal; }
.pl-star { background: none; border: none; cursor: pointer; font-size: .95rem; color: var(--fg3); padding: 0 .1rem; }
.pl-star.on { color: #f59e0b; }

/* Baum */
.pl-baum { border: 1px solid var(--border); border-radius: var(--radius); padding: .4rem .55rem; max-height: 62vh; overflow-y: auto; background: var(--bg2); min-width: 0; max-width: 100%; }
.pl-knoten { margin: .12rem 0; }
.pl-knoten > summary { cursor: pointer; display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; padding: .22rem .1rem; font-size: .82rem; }
.pl-knoten > summary:hover { color: var(--blue); }
.pl-knoten-titel { font-weight: 600; }
.pl-knoten[data-ebene='1'] > summary .pl-knoten-titel { color: var(--fg); font-weight: 700; }
.pl-knoten[data-ebene='2'] > summary .pl-knoten-titel { color: var(--fg); font-weight: 600; }
.pl-knoten[data-ebene='3'] > summary .pl-knoten-titel { color: var(--fg2); font-weight: 600; }
.pl-knoten[data-ebene='4'] > summary .pl-knoten-titel,
.pl-knoten[data-ebene='5'] > summary .pl-knoten-titel { color: var(--fg2); font-weight: 500; }
.pl-knoten[data-ebene='1'] > summary { border-left: 3px solid var(--blue); padding-left: .4rem; }
.pl-knoten[data-ebene='2'] > summary { border-left: 3px solid var(--teal); padding-left: .4rem; }
.pl-knoten[data-ebene='3'] > summary { border-left: 3px solid #f59e0b; padding-left: .4rem; }
.pl-knoten-body { border-left: 2px solid var(--border); margin-left: .35rem; padding-left: .55rem; }
.pl-treepos {
  display: flex; align-items: center; gap: .5rem; font-size: .78rem;
  padding: .2rem .25rem; border-radius: 5px; cursor: pointer;
}
.pl-treepos:hover { background: var(--bg3); }
.pl-tree-kurz { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-tree-zahlen { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Trefferliste */
.pl-treffer { display: flex; flex-direction: column; gap: .4rem; }
.pl-hit {
  border: 1px solid var(--border); border-radius: var(--radius); padding: .5rem .65rem;
  cursor: pointer; background: var(--bg2); font-size: .82rem;
  display: flex; flex-direction: column; gap: .12rem;
}
.pl-hit:hover { border-color: var(--blue); }
.pl-hit p { margin: .15rem 0 0; font-size: .75rem; color: var(--fg2); }
.pl-hit mark { background: #fde68a; color: #111; border-radius: 2px; padding: 0 1px; }
.pl-hit.txt { border-left: 4px solid var(--blue); }
.pl-hit.txt.art-neben { border-left-color: #f59e0b; }
.pl-hit.txt.art-vorbemerkung { border-left-color: #10b981; }

/* Texte */
.pl-texte { display: flex; flex-direction: column; gap: .45rem; border-top: 1px dashed var(--border); padding-top: .5rem; }
.pl-texte details { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg2); }
.pl-texte summary { cursor: pointer; padding: .45rem .6rem; font-size: .82rem; font-weight: 600; }
.pl-text { padding: .4rem .7rem .7rem; }
.pl-text-titel { font-size: .78rem; font-weight: 600; margin-bottom: .2rem; }
/* S61b: KEIN eigener Scrollbereich je Text. FK: „mehrere abschnitte sollten nicht
   ineinander scrollbar sein … dann erst scrollbar, aber dann nur einmal."
   Vorher stand hier `max-height:340px; overflow-y:auto` — drei Texte ergaben
   drei ineinanderliegende Scrollbalken. Der Text wächst jetzt mit; gescrollt
   wird die Seite bzw. der eine Tabellen-Wrapper. */
.pl-text pre {
  white-space: pre-wrap; word-break: break-word; font: inherit; font-size: .78rem;
  color: var(--fg2); margin: 0; overflow: visible; max-height: none;
}

/* S61: Allgemeine Bestimmungen stehen jetzt GANZ OBEN (über Projekt/LV) */
.pl-texte-oben { border-top: none; padding-top: 0; margin-bottom: 0; }
.pl-texte-oben summary { font-size: .88rem; }
.pl-texte-body { padding: 0 .6rem .5rem; }
.pl-texte details > summary { list-style: none; display: flex; align-items: center; gap: .35rem; }
.pl-texte details > summary::-webkit-details-marker { display: none; }
.pl-texte details > summary::before {
  content: '▸'; color: var(--fg3); font-size: .8em; transition: transform .12s;
}
.pl-texte details[open] > summary::before { content: '▾'; }

/* S61: Nebenbestimmungen/Vorbemerkungen am Abschnitt — bewusst auffällig,
   weil sie im LV die Vorgabe für die Positionen darunter sind.
   S61b: auf-/zuklappbar (je Abschnitt EIN Block), Startzustand ZU, und
   KEIN Scrollbereich je Text — vorher `max-height:220px; overflow-y:auto`. */
.pl-texterow td { background: rgba(245,158,11,.07); padding: 0 !important; }
.pl-abschnitt-texte {
  display: block; border-left: 4px solid #f59e0b; background: var(--bg2);
  border-radius: 0 6px 6px 0; margin: .3rem .4rem;
}
.pl-abschnitt-texte[open] { margin-bottom: .4rem; }
.pl-abschnitt-kopf {
  display: flex; align-items: center; gap: .4rem; cursor: pointer; list-style: none;
  padding: .38rem .6rem; font-size: .76rem; font-weight: 700; color: var(--fg);
  text-transform: uppercase; letter-spacing: .4px;
}
.pl-abschnitt-kopf::-webkit-details-marker { display: none; }
.pl-abschnitt-kopf::after { content: ''; }
.pl-abschnitt-texte > summary::before {
  content: '▸'; color: #f59e0b; font-size: .85em;
}
.pl-abschnitt-texte[open] > summary::before { content: '▾'; }
.pl-abschnitt-liste { display: flex; flex-direction: column; gap: .35rem; padding: 0 .5rem .5rem; }
.pl-abschnitt-text {
  border-left: 3px solid rgba(245,158,11,.5);
  border-radius: 0 6px 6px 0; padding: .3rem .55rem .4rem;
}
.pl-abschnitt-text.vb { border-left-color: var(--teal); }
.pl-abschnitt-titel {
  display: block; font-size: .74rem; font-weight: 700; color: var(--fg);
  text-transform: uppercase; letter-spacing: .4px; margin-bottom: .18rem;
}
.pl-abschnitt-text pre {
  white-space: pre-wrap; word-break: break-word; font: inherit; font-size: .8rem;
  color: var(--fg); margin: 0; overflow: visible; max-height: none;
}
/* In der Baumansicht ohne Rahmen, damit die Positionen darunter lesbar bleiben */
.pl-knoten-body .pl-abschnitt-texte { margin: .3rem 0 .45rem; }
.pl-knoten-body .pl-abschnitt-text { border-left-width: 2px; }

/* Aufmaß-Zeilen */
.pl-menge { width: 100%; min-width: 74px; font-size: .8rem; padding: .25rem .35rem;
  border: 1px solid var(--border); border-radius: 5px; background: var(--bg); color: var(--fg);
  text-align: right; font-variant-numeric: tabular-nums; }
.pl-menge:focus { outline: none; border-color: var(--blue); }
.pl-menge.fehler { border-color: var(--red); background: rgba(239,68,68,.12); }
.pl-nummerrow { background: rgba(59,130,246,.10); font-size: .8rem; }
.pl-nummerrow td { border-top: 1px dashed var(--border); }
.pl-nummerrow .pl-col-kurz b { color: var(--fg); }
.pl-sumrow td { background: var(--bg3); border-top: 2px solid var(--border); font-size: .82rem; }
.pl-hint { font-size: .72rem; color: var(--fg2); background: var(--bg2);
  border: 1px dashed var(--border); border-radius: 6px; padding: .3rem .5rem; }

/* Detail-Panel */
.pl-detail {
  position: fixed; top: 0; right: 0; height: 100vh; width: min(430px, 94vw);
  background: var(--bg); border-left: 1px solid var(--border); z-index: 60;
  display: flex; flex-direction: column; box-shadow: -8px 0 24px rgba(0,0,0,.18);
}
.pl-detail-head {
  display: flex; align-items: center; gap: .5rem; padding: .7rem .8rem;
  border-bottom: 1px solid var(--border);
}
.pl-detail-head b { font-size: 1.02rem; }
.pl-detail-head .btn { margin-left: auto; }
.pl-detail-body { padding: .8rem; overflow-y: auto; display: flex; flex-direction: column; gap: .6rem; }
.pl-detail-kurz { margin: 0; font-size: .92rem; }
.pl-detail-lang { margin: 0; font-size: .8rem; color: var(--fg2); white-space: pre-wrap; }
.pl-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .45rem; }
.pl-detail-grid > div { background: var(--bg2); border: 1px solid var(--border); border-radius: 7px; padding: .4rem .5rem; }
.pl-detail-grid span { display: block; font-size: .65rem; text-transform: uppercase; letter-spacing: .4px; color: var(--fg3); }
.pl-detail-grid b { font-size: .9rem; font-variant-numeric: tabular-nums; }
.pl-detail-actions { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.pl-komp { font-size: .75rem; border-top: 1px dashed var(--border); padding-top: .4rem; }

/* Export-Dialog */
.pl-modal { position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 70; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.pl-modal-box {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  width: min(420px, 100%); padding: .8rem; display: flex; flex-direction: column; gap: .55rem;
  max-height: 90vh; overflow-y: auto;
}
.pl-modal-head { display: flex; align-items: center; justify-content: space-between; font-size: .95rem; }
.pl-opt { display: flex; align-items: center; gap: .5rem; font-size: .8rem; flex-wrap: wrap; }
.pl-opt select { font-size: .8rem; padding: .3rem .4rem; border: 1px solid var(--border); border-radius: 6px; background: var(--bg2); flex: 1; min-width: 150px; }
.pl-modal-actions { display: flex; justify-content: flex-end; gap: .4rem; margin-top: .2rem; }

/* ── Handy (<640px) ───────────────────────────────────── */
@media (max-width: 640px) {
  .pl-head { align-items: flex-start; }
  .pl-summen { gap: .6rem; }
  .pl-summen > div { flex: 1 1 40%; }
  .pl-quelle { max-width: 100%; }
  .pl-lvlist { grid-template-columns: 1fr; }
  .pl-lvcard { flex-wrap: wrap; }
  .pl-lvcard-actions { width: 100%; justify-content: flex-end; }
  .pl-suche { min-width: 100%; order: -1; }
  .pl-toolbar { gap: .35rem; }
  .pl-table { font-size: .74rem; min-width: 560px; }
  .pl-table td, .pl-table th { padding: .3rem .35rem; }
  .pl-col-ep { display: none; }          /* EP mobil ausblenden — Betrag bleibt */
  .pl-tablewrap { max-height: 55vh; }
  .pl-baum { max-height: 55vh; }
  /* Detail-Panel als Bottom-Sheet */
  .pl-detail {
    top: auto; bottom: 0; right: 0; left: 0; width: 100%; height: auto;
    max-height: 76vh; border-left: none; border-top: 1px solid var(--border);
    border-radius: var(--radius) var(--radius) 0 0;
  }
  .pl-detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pl-tree-zahlen { font-size: .72rem; }
}

/* ── Tablet (641–1024px) ─────────────────────────────── */
@media (min-width: 641px) and (max-width: 1024px) {
  .pl-table { font-size: .78rem; }
  .pl-lvlist { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
  .pl-detail { width: min(400px, 70vw); }
}

/* ── S51: Tabs, Aufmaß, Kennzahlen, Bibliothek, Vergleich ── */
.pl-subnav { flex-wrap: wrap; }
.pl-subnav .pl-tab { cursor: pointer; font-family: inherit; }

.pl-hint {
  font-size: .76rem; color: var(--fg2); background: var(--bg3);
  border: 1px dashed var(--border); padding: .35rem .55rem; border-radius: var(--radius);
}
.pl-h4 { margin: .55rem 0 .2rem; font-size: .8rem; font-weight: 700; color: var(--fg2); }

/* Aufmaß */
.pl-amtools { gap: .5rem; }
.pl-amtools select { min-width: 190px; }
.pl-menge {
  width: 76px; font-size: .8rem; padding: .18rem .3rem; text-align: right;
  border: 1px solid var(--border); border-radius: 5px; background: var(--bg2); color: var(--fg);
}
.pl-menge:focus { outline: 1px solid var(--blue); }
.pl-col-nr { width: 34px; }
.pl-col-del { width: 42px; text-align: center; }
.pl-col-del .btn { font-size: .7rem; }
.pl-sumrow td { background: var(--bg3); font-weight: 600; }
.pl-freitext input { max-width: 460px; }

/* Kennzahlen */
.pl-kz-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .5rem; }
.pl-kz {
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg2);
  padding: .5rem .6rem; display: flex; flex-direction: column; gap: .1rem; min-width: 0;
}
.pl-kz span { font-size: .66rem; text-transform: uppercase; letter-spacing: .4px; color: var(--fg3); }
.pl-kz b { font-size: 1rem; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; }
.pl-kz-flags { display: flex; flex-wrap: wrap; gap: .4rem; }
.pl-flag {
  font-size: .75rem; padding: .3rem .55rem; border-radius: 999px;
  border: 1px solid var(--border); background: var(--bg3); color: var(--fg2); cursor: pointer;
}
.pl-flag.on { background: var(--blue); color: #fff; border-color: transparent; font-weight: 600; }
.pl-kz-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: .8rem; }
.pl-kz-two h4 { margin: .35rem 0 .2rem; font-size: .76rem; text-transform: uppercase;
  letter-spacing: .4px; color: var(--fg3); }
.pl-bar-row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(60px, 32%) auto;
  align-items: center; gap: .5rem; font-size: .76rem; padding: .16rem .1rem; cursor: default;
}
.pl-bar-row[role='button'] { cursor: pointer; }
.pl-bar-row:hover { background: var(--bg3); }
.pl-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-bar { display: block; height: 8px; border-radius: 999px; background: var(--bg3); overflow: hidden; }
.pl-bar i { display: block; height: 100%; background: var(--blue); }
.pl-chips { display: flex; flex-wrap: wrap; gap: .3rem; }

/* Vergleich / Diff */
.pl-vbtools { gap: .5rem; }
.pl-vbtools select { min-width: 170px; }
.pl-diff.grp-neu h4 { color: #10b981; }
.pl-diff.grp-geaendert h4 { color: #f59e0b; }
.pl-diff.grp-geloescht h4 { color: var(--red); }
.pl-diffline { font-size: .74rem; line-height: 1.35; }
.pl-delta { color: var(--red); font-style: normal; font-weight: 700; }
.pl-bib-tabelle td { max-width: 340px; overflow: hidden; text-overflow: ellipsis; }

@media (max-width: 640px) {
  .pl-kz-grid { grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); }
  .pl-kz-two { grid-template-columns: 1fr; }
  .pl-bar-row { grid-template-columns: minmax(0, 1fr) auto; }
  .pl-bar { display: none; }
  .pl-col-nr { display: none; }
  .pl-amtools select { min-width: 100%; }
}
/* S53 — Trommel-Modul */

.tr-page { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }

.tr-kopf { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.tr-kopf h1 { margin: 0; font-size: 1.35rem; }
.tr-kopf-aktionen { margin-left: auto; display: flex; gap: .5rem; flex-wrap: wrap; }

.tr-sub { font-size: .75rem; font-weight: 400; color: var(--fg3); }

/* Kennzahlen */
.tr-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: .6rem; }
.tr-stat { background: var(--bg3); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .55rem .7rem; display: flex; flex-direction: column; gap: 2px; }
.tr-stat b { font-size: 1.25rem; }
.tr-stat span { font-size: .7rem; color: var(--fg3); text-transform: uppercase; letter-spacing: .04em; }
.tr-stat.q b { color: var(--blue, #1f6feb); }

/* Toolbar */
.tr-toolbar { display: flex; gap: .6rem; flex-wrap: wrap; }
.tr-toolbar input { flex: 1 1 260px; min-width: 0; }
.tr-toolbar select { flex: 0 0 auto; }

/* Tabelle */
.tr-table { overflow: visible; }
.tr-table table { width: 100%; border-collapse: collapse; }
.tr-table th { text-align: left; font-size: .7rem; text-transform: uppercase; color: var(--fg3);
  padding: .45rem .5rem; border-bottom: 2px solid var(--border); position: sticky; top: 0;
  background: var(--bg); z-index: 2; }
.tr-table td { padding: .45rem .5rem; border-bottom: 1px solid var(--border); font-size: .85rem;
  max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tr-table tbody tr:hover { background: var(--bg3); }
.tr-table .num { text-align: right; }
.tr-table .mono, .mono { font-family: ui-monospace, Consolas, monospace; }
.tr-leer { color: var(--fg3); font-size: .85rem; padding: .8rem .5rem !important; }

/* Status-Pill */
.tr-status { display: inline-block; font-size: .7rem; font-weight: 700; padding: 2px 8px;
  border-radius: 10px; background: var(--bg3); color: var(--fg2); white-space: nowrap; }
.st-bestand { background: rgba(34,197,94,.16); color: #22c55e; }
.st-ausgegeben { background: rgba(59,130,246,.16); color: #3b82f6; }
.st-verbraucht { background: rgba(148,163,184,.18); color: #94a3b8; }
.st-retoure { background: rgba(245,158,11,.18); color: #f59e0b; }

/* Scan-Ergebnis */
.tr-ergebnis { border: 1px solid var(--border); border-left: 4px solid var(--fg3);
  border-radius: var(--radius); background: var(--bg3); overflow: hidden; }
.tr-ergebnis.ok { border-left-color: #22c55e; }
.tr-ergebnis.warn { border-left-color: #f59e0b; }
.tr-ergebnis.neu { border-left-color: #ef4444; }
.tr-ergebnis-kopf { display: flex; align-items: center; gap: .6rem; padding: .55rem .7rem;
  border-bottom: 1px solid var(--border); }
.tr-ergebnis-kopf .tr-roh { flex: 1; min-width: 0; font-family: ui-monospace, Consolas, monospace;
  font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg3); }
.tr-badge { font-weight: 700; font-size: .85rem; white-space: nowrap; }
.tr-ergebnis-body { padding: .6rem .7rem; display: flex; flex-direction: column; gap: .5rem; }
.tr-treffer { font-size: .9rem; }
.tr-hinweis { font-size: .8rem; color: var(--fg3); }
.tr-analyse { display: flex; gap: .8rem; flex-wrap: wrap; font-size: .8rem; }
.tr-analyse b { font-family: ui-monospace, Consolas, monospace; }
.tr-btns { display: flex; gap: .5rem; flex-wrap: wrap; }
.tr-kandidaten { display: flex; flex-direction: column; gap: .35rem; }
.tr-kand { text-align: left; background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .4rem .6rem; font-size: .82rem; cursor: pointer; color: var(--fg); }
.tr-kand:hover { border-color: var(--blue, #1f6feb); }

/* Meldung */
.tr-msg { padding: .55rem .75rem; border-radius: var(--radius); font-size: .85rem; }
.tr-msg.fehler { background: rgba(239,68,68,.12); border: 1px solid rgba(239,68,68,.4); color: #ef4444; }

/* Detail */
.tr-kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: .5rem .9rem; }
.tr-kv { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tr-kv span { font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--fg3); }
.tr-kv b { font-size: .88rem; font-weight: 600; word-break: break-word; }

.tr-zwei { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; }
.tr-zeile { display: flex; gap: .6rem; align-items: center; padding: .3rem 0;
  border-bottom: 1px dashed var(--border); font-size: .8rem; }
.tr-zeile:last-child { border-bottom: none; }
.tr-zeile .mono { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tr-user { color: var(--fg3); font-size: .72rem; white-space: nowrap; }
.tr-chip { font-size: .68rem; font-weight: 700; padding: 1px 7px; border-radius: 9px;
  background: var(--bg3); text-transform: uppercase; }
.e-bekannt { background: rgba(34,197,94,.16); color: #22c55e; }
.e-neu { background: rgba(239,68,68,.14); color: #ef4444; }
.e-mehrdeutig { background: rgba(245,158,11,.16); color: #f59e0b; }
.e-unbekannt { background: rgba(148,163,184,.18); color: #94a3b8; }

/* Codes */
.tr-codes { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: .8rem; }
.tr-code { border: 1px solid var(--border); border-radius: var(--radius); padding: .6rem;
  text-align: center; background: var(--bg3); }
.tr-code-l { font-size: .68rem; font-weight: 700; text-transform: uppercase; color: var(--fg3);
  margin-bottom: .4rem; }
.tr-code-b { display: flex; justify-content: center; background: #fff; border-radius: 4px; padding: .4rem; }
.tr-code-b svg { max-width: 100%; height: auto; }
.tr-code-v { font-family: ui-monospace, Consolas, monospace; font-size: .72rem; margin-top: .4rem;
  word-break: break-all; }
.tr-code-h { font-size: .66rem; color: var(--fg3); margin-top: 2px; }

/* Formular */
.tr-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: .7rem; }
.tr-feld { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.tr-feld span { font-size: .72rem; color: var(--fg3); text-transform: uppercase; letter-spacing: .03em; }
.tr-voll { grid-column: 1 / -1; }

/* Verlauf unter der Liste */
.tr-verlauf { display: flex; flex-direction: column; }

/* Live-Hinweis in der Materialzeile (Bericht erstellen/bearbeiten) */
.tr-hin { display: inline-flex; align-items: center; gap: 5px; font-size: .68rem; font-weight: 700;
  padding: 2px 7px; border-radius: 9px; white-space: nowrap; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; }
.tr-hin.ok { background: rgba(34,197,94,.16); color: #22c55e; }
.tr-hin.warn { background: rgba(245,158,11,.18); color: #f59e0b; cursor: help; }
.tr-hin.neu { background: rgba(239,68,68,.14); color: #ef4444; }
.tr-hin-btn { font-size: .64rem; font-weight: 700; padding: 1px 6px; border-radius: 8px;
  border: 1px solid currentColor; background: transparent; color: inherit; cursor: pointer;
  font-family: inherit; }
.tr-hin-btn:disabled { opacity: .6; cursor: wait; }
.tr-hin-fehler { font-size: .6rem; color: #ef4444; font-style: normal; }

/* ── S54: Foto-Lauf (Barcode/Crop/OCR) + Belegfoto ─────────────── */
.tr-lesart {
  display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center;
  padding: 7px 10px; margin: 6px 10px 4px; border-radius: 8px;
  background: var(--bg); border: 1px dashed var(--border);
  font-size: .74rem; color: var(--fg2); line-height: 1.35;
}
.tr-lesart-weg { font-weight: 700; color: var(--fg); }
.tr-lesart-neu { color: #2f9e44; font-weight: 700; }
.tr-lesart-warn { color: #c47f0a; }
.tr-beleg {
  max-height: 132px; max-width: 100%; border-radius: 8px;
  border: 1px solid var(--bg3); display: block; flex: 0 0 auto;
}
.tr-beleg-laedt { font-size: .7rem; opacity: .6; padding: 24px 10px; }

/* Handy */
@media (max-width: 768px) {
  .tr-kopf h1 { font-size: 1.1rem; }
  .tr-kopf-aktionen { margin-left: 0; width: 100%; }
  .tr-kopf-aktionen .btn { flex: 1 1 auto; }
  .tr-stats { grid-template-columns: repeat(2, 1fr); }
  .tr-table th:nth-child(4), .tr-table td:nth-child(4),
  .tr-table th:nth-child(7), .tr-table td:nth-child(7) { display: none; }
  .tr-table td, .tr-table th { font-size: .78rem; padding: .4rem .35rem; }
  .tr-codes { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

*{margin:0;padding:0;box-sizing:border-box}
html{scrollbar-gutter:stable}
:root{--bg:#0f172a;--bg2:#1e293b;--bg3:#334155;--fg:#f8fafc;--fg2:#94a3b8;--fg3:#64748b;--blue:#3b82f6;--blue-dark:#2563eb;--green:#22c55e;--red:#ef4444;--yellow:#eab308;--violet:#8b5cf6;--cyan:#06b6d4;--orange:#f97316;--pink:#ec4899;--teal:#14b8a6;--indigo:#6366f1;--radius:8px;--shadow:0 1px 3px rgba(0,0,0,.3)}
/* S72: Die Unterschriften-Sektion hat eine **eigene** Farbe, weil `--pink`
   schon `bemerkungen` und `--violet` schon `referenzen` gehört. Ein zweiter
   Balken in einer belegten Farbe macht zwei Sektionen gleichfarbig — die
   Sektionsfarbe wäre dann nur noch Dekoration. */
:root{--unterschrift:#d946ef}
body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--fg);min-height:100vh;-webkit-text-size-adjust:100%}
a{color:var(--blue);text-decoration:none}

/* Desktop */
.app{display:flex;min-height:100vh}
.sidebar{width:220px;background:var(--bg2);border-right:1px solid var(--bg3);padding:1rem 0;display:flex;flex-direction:column;position:fixed;height:100vh;overflow-y:auto;z-index:10}
.sidebar .logo{padding:0 1rem;font-size:1.1rem;font-weight:700;color:var(--blue);margin-bottom:.75rem}
.sidebar nav a{display:flex;align-items:center;gap:.6rem;padding:.5rem 1rem;color:var(--fg2);font-size:.85rem;transition:all .15s}
.sidebar nav a:hover,.sidebar nav a.active{background:var(--bg3);color:var(--fg)}
/* S81: Unterpunkte in der Navigation (FK, 14.10.2026 — "Import-Fotos"
   sollte ein Unterpunkt von "Dateien" sein, kein eigener Punkt).
   Die Leiste war vorher eine flache Liste ohne Unterpunkte; die
   Mechanik kam mit `NavLinke` in App.jsx dazu.

   Ein Unterpunkt ist kleiner, eingerueckt und etwas blasser. Damit
   faellt sofort auf, dass er zur Gruppe gehoert — ohne dass die
   Gruppenlinie noetig waere, die in einer 220px breiten Leiste
   ohnehin keine Rolle spielt. */
.sidebar nav .nav-kind{padding:.4rem 1rem .4rem 1.6rem;font-size:.8rem;color:var(--fg3)}
.sidebar nav .nav-kind:hover,.sidebar nav .nav-kind.active{color:var(--fg);background:var(--bg3)}
.sidebar nav .nav-kind-strich{color:var(--fg3);opacity:.6;font-size:.75rem}
/* Der Pfeil zeigt, dass der Punkt eine Gruppe ist. Ohne ihn ist nicht
   erkennbar, ob sich unter "Dateien" etwas oeffnet. */
.sidebar nav .nav-pfeil{margin-left:auto;font-size:.65rem;opacity:.55;line-height:1}
.sidebar .spacer{flex:1}
.sidebar .user-info{padding:1rem;border-top:1px solid var(--bg3);font-size:.8rem;color:var(--fg3)}
/* S49: overflow-x:hidden berechnete sich zu auto => main wurde zum Scrollport und
   position:sticky am Tabellen-Kopf wirkte NIE (Kopf scrollte mit). clip clippt weiter
   horizontal, ist aber KEIN Scrollport => sticky haftet jetzt am Dokument-Fenster. */
.main{margin-left:220px;flex:1;padding:1.5rem;padding-bottom:5rem;min-height:100vh;overflow-x:clip;min-width:0}
.mobile-nav{display:none}
.mobile-lang-bar{display:none}

/* Cards */
.card{background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);padding:1rem;margin-bottom:.75rem}
.card h2{font-size:.95rem;font-weight:600;margin-bottom:.75rem}
.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.75rem}
.card-header h2{margin-bottom:0}

/* Forms */
.form-group{margin-bottom:.6rem}
.form-group label{display:block;font-size:.75rem;color:var(--fg2);margin-bottom:.2rem}
.form-group input,.form-group select,.form-group textarea{width:100%;padding:.45rem .6rem;background:var(--bg);border:1px solid var(--bg3);border-radius:var(--radius);color:var(--fg);font-size:.85rem;font-family:inherit}
.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--blue)}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:.5rem}
/* ⛔⛔ `<option>` erbt NICHT die Farben des Selects, sondern die des Systems.
   In der dunklen Oberflaeche heisst das: weisser Text auf weissem Grund,
   sobald man die Liste aufklappt — unlesbar (gemessen 12.10.2026 am
   SDX-Fenster „± 1 Woche"). Bis hierher gab es nur eine Regel fuer
   `.fg-projekt`; jedes andere Auswahlfeld war davon nicht erfasst.
   Diese eine Zeile deckt jetzt alle ab. */
select option{background:var(--bg2);color:var(--fg)}
select option:checked{background:var(--blue);color:#fff}

/* Buttons */
.btn{display:inline-flex;align-items:center;gap:.4rem;padding:.45rem .8rem;border:none;border-radius:var(--radius);font-size:.8rem;font-weight:500;cursor:pointer;transition:all .15s;font-family:inherit}
.btn-primary{background:var(--blue);color:#fff}.btn-primary:hover{background:var(--blue-dark)}
.btn-danger{background:var(--red);color:#fff}.btn-danger:hover{opacity:.9}
.btn-ghost{background:transparent;color:var(--fg2);border:1px solid var(--bg3)}.btn-ghost:hover{background:var(--bg3);color:var(--fg)}
.btn-sm{padding:.3rem .5rem;font-size:.7rem}
.btn-success{background:var(--green);color:#fff}
.btn-warning{background:var(--yellow);color:#000}
.btn-group{display:flex;gap:.4rem;flex-wrap:wrap}

/* Status */
.badge{display:inline-block;padding:.12rem .4rem;border-radius:99px;font-size:.65rem;font-weight:600}
.badge-draft{background:rgba(234,179,8,.15);color:var(--yellow)}
.badge-ok{background:rgba(34,197,94,.15);color:var(--green)}
.badge-warn{background:rgba(249,115,22,.15);color:#f97316}
.badge-info{background:rgba(59,130,246,.15);color:#3b82f6}
.badge-off{background:rgba(239,68,68,.15);color:var(--red)}
.badge-deleted{background:rgba(239,68,68,.15);color:var(--red);text-decoration:line-through}

/* Login */
.login-page{display:flex;align-items:center;justify-content:center;min-height:100vh;padding:1rem}
.login-box{background:var(--bg2);border:1px solid var(--bg3);border-radius:12px;padding:2rem;width:100%;max-width:360px}
.login-box h1{font-size:1.3rem;margin-bottom:.2rem}.login-box p{color:var(--fg2);font-size:.85rem;margin-bottom:1.5rem}
.login-box .btn{width:100%;justify-content:center;padding:.6rem}
.error{color:var(--red);font-size:.8rem;margin-top:.5rem}
.error-card{border-left:3px solid var(--red)}

/* Stats */
.stat{text-align:center;padding:.5rem}
.stat .num{font-size:1.8rem;font-weight:700;color:var(--blue)}
.stat .label{font-size:.7rem;color:var(--fg2);margin-top:.1rem}
.grid-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:.5rem}

/* Calendar */
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.cal-header{text-align:center;font-size:.65rem;color:var(--fg3);padding:.2rem;font-weight:600}
.cal-day{aspect-ratio:1;display:flex;align-items:center;justify-content:center;border-radius:var(--radius);font-size:.75rem;cursor:pointer}
.cal-day.empty{cursor:default}.cal-day.has-data{background:rgba(34,197,94,.15);color:var(--green);font-weight:600}
.cal-day.today{border:2px solid var(--blue)}

/* Tabs */
.tabs{display:flex;gap:0;border-bottom:1px solid var(--bg3);margin-bottom:1rem;overflow-x:auto}
.tab{padding:.5rem .75rem;font-size:.8rem;color:var(--fg3);cursor:pointer;border-bottom:2px solid transparent;white-space:nowrap}
.tab.active{color:var(--blue);border-bottom-color:var(--blue)}

/* Weather buttons */
.w-btns{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:.75rem}
.w-btn{padding:.3rem .6rem;border-radius:var(--radius);border:1px solid var(--bg3);background:var(--bg);color:var(--fg2);font-size:.75rem;cursor:pointer}
.w-btn.on{background:var(--blue);color:#fff;border-color:var(--blue)}

/* Row cards (Mobile-first lists) */
.row-card{display:flex;gap:.4rem;align-items:center;padding:.5rem 0;border-bottom:1px solid var(--bg3)}
.row-card:last-child{border-bottom:none}
.row-card select,.row-card input{flex:1;padding:.4rem .5rem;background:var(--bg);border:1px solid var(--bg3);border-radius:var(--radius);color:var(--fg);font-size:.8rem}
.row-card .btn-danger{flex-shrink:0}

/* User cards */
.user-card{padding:.75rem 0;border-bottom:1px solid var(--bg3)}
.user-card:last-child{border-bottom:none}
.user-card-main{margin-bottom:.5rem}
.user-card-detail{font-size:.75rem;color:var(--fg2);margin-top:.15rem}
.user-card-actions{display:flex;gap:.3rem;flex-wrap:wrap}

/* Bericht cards */
.bericht-card{display:block;color:var(--fg);transition:all .15s}
.bericht-card:hover{border-color:var(--blue)}

/* S58/S59: Plausibilitaet — rot = Datenfehler, gelb = Formalien fehlen */
.berichte-row.bericht-unvoll{background:rgba(239,68,68,.10)}
.berichte-row.bericht-unvoll:hover{background:rgba(239,68,68,.18)}
.berichte-row.bericht-unvoll td:first-child{border-left:3px solid var(--red)}
.berichte-row.bericht-formfehler{background:rgba(234,179,8,.08)}
.berichte-row.bericht-formfehler:hover{background:rgba(234,179,8,.15)}
.berichte-row.bericht-formfehler td:first-child{border-left:3px solid var(--yellow)}
.plausi-badge{display:inline-block;background:rgba(239,68,68,.18);color:#fca5a5;
  border:1px solid rgba(239,68,68,.5);padding:.1rem .35rem;border-radius:4px;
  font-size:.68rem;font-weight:600;white-space:nowrap;max-width:170px;
  overflow:hidden;text-overflow:ellipsis}
.plausi-badge.plausi-gelb{background:rgba(234,179,8,.16);color:#fcd34d;
  border-color:rgba(234,179,8,.5)}
.bericht-card-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:.25rem}
.bericht-card-mid{font-size:.85rem}.bericht-card-bot{font-size:.75rem;color:var(--fg3)}

/* Audit cards */
.audit-card{background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);padding:.6rem;margin-bottom:.5rem;font-size:.8rem}
.audit-top{display:flex;gap:.5rem;align-items:center}.audit-mid{color:var(--fg2);font-size:.7rem;margin-top:.2rem}.audit-bot{font-size:.75rem;margin-top:.2rem}

/* Modal */
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:100;padding:1rem}
/* S40: GpsEditModal — OBEN im Viewport statt am Seitenende (fixed statt statisch) */
.modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:flex-start;justify-content:center;padding:1rem 1rem 2rem;z-index:10100;overflow-y:auto}
.modal-backdrop .modal{margin-bottom:1rem}
.modal{background:var(--bg2);border:1px solid var(--bg3);border-radius:12px;padding:1.5rem;width:100%;max-width:400px}
.modal h3{margin-bottom:1rem}

/* MA total */
.ma-total{text-align:right;font-size:.8rem;font-weight:600;color:var(--blue);padding-top:.5rem}

/* Empty */
.empty{text-align:center;padding:2rem;color:var(--fg3)}

/* Table */
/* S49: overflow-x:auto machte die Tabelle zum Scrollport (sticky am thead wirkungslos)
   -> overflow:visible; die Tabelle ist seit S48 table-layout:fixed + width:100% und
   laeuft damit nicht mehr aus dem Rahmen. */
.table-wrap{overflow:visible}
table{width:100%;border-collapse:collapse;font-size:.8rem}
th,td{padding:.4rem .6rem;text-align:left;border-bottom:1px solid var(--bg3)}
th{color:var(--fg2);font-weight:500;font-size:.7rem;text-transform:uppercase;letter-spacing:.5px}

/* Baustellen-Kacheln */
.bs-grid{display:flex;gap:.5rem;overflow-x:auto;padding-bottom:.5rem;margin-bottom:.75rem;-webkit-overflow-scrolling:touch}
.bs-grid::-webkit-scrollbar{height:4px}
.bs-grid::-webkit-scrollbar-thumb{background:var(--bg3);border-radius:2px}
.bs-tile{flex:0 0 auto;min-width:120px;padding:.6rem .8rem;border:2px solid;border-radius:var(--radius);cursor:pointer;transition:all .15s;text-align:center;user-select:none}
.bs-tile:hover{transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.15)}
.bs-tile.bs-active{transform:translateY(-1px);box-shadow:0 2px 12px rgba(0,0,0,.2)}
.bs-tile-name{font-size:.75rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:140px}
.bs-tile-addr{font-size:.65rem;color:var(--fg3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:140px;margin-top:1px}
.bs-tile-count{font-size:1.1rem;font-weight:700;color:var(--fg);margin-top:2px}
.bericht-card-addr{font-size:.75rem;color:var(--fg3);margin-top:2px}

/* Berichte-Tabelle */
.berichte-tbl{width:100%;border-collapse:collapse;font-size:.8rem}
.berichte-tbl th{position:sticky;top:0;background:var(--bg2);z-index:1;text-align:left;font-size:.7rem;text-transform:uppercase;letter-spacing:.5px;color:var(--fg2);padding:.5rem .6rem;border-bottom:2px solid var(--bg3);white-space:nowrap}
.berichte-tbl td{padding:.45rem .6rem;border-bottom:1px solid var(--bg3);vertical-align:middle}
.berichte-row{cursor:pointer;transition:background .1s}
/* S49: Bulk-Leiste + Tabellen-Kopf bleiben beim Scrollen oben stehen (FK).
   --bulk-h liefert App.jsx per ResizeObserver der Leiste => der Kopf klebt UNTER der Leiste,
   ohne Leiste (keine Markierung) gilt top:0. Nur innerhalb .bulk-sticky, damit die
   Berichts-/Konfig-Tabellen unverändert top:0 behalten. */
.bulk-sticky [data-testid="bulk-toolbar"]{position:sticky;top:0;z-index:60}
.bulk-sticky .berichte-tbl th{top:var(--bulk-h,0px)}
@media(max-width:768px){.bulk-sticky [data-testid="bulk-toolbar"]{top:44px}}
.berichte-row:hover{background:rgba(59,130,246,.05)}
.berichte-row:active{background:rgba(59,130,246,.1)}
.addr-hint{font-size:.7rem;color:var(--fg3);font-weight:400}
.anlagen-badge{display:inline-block;background:rgba(59,130,246,.1);color:var(--blue);padding:.1rem .4rem;border-radius:4px;font-size:.75rem;font-weight:600;white-space:nowrap}
.tbl-action{cursor:pointer;font-size:.9rem;opacity:.5;transition:opacity .1s;text-decoration:none;margin-left:.3rem}
.tbl-action:hover{opacity:1}
.nowrap{white-space:nowrap}
.tbl-date{font-size:.75rem;color:var(--fg3)}
.tbl-bem{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.75rem;color:var(--fg3);cursor:pointer}
.tbl-bem:hover{color:var(--fg)}
.tbl-bem-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}
.group-header:hover{background:rgba(59,130,246,.05)!important}
.group-header td{transition:background .1s}
.berichte-sum td{border-top:2px solid var(--bg3);font-size:.8rem;color:var(--fg2);padding:.5rem .6rem}

/* Mobile: Tabelle → Karten */
@media(max-width:768px){
  .berichte-tbl thead{display:none}
  .berichte-tbl tbody tr{display:block;padding:.6rem;border-bottom:1px solid var(--bg3);position:relative}
  .berichte-tbl tbody td{display:flex;justify-content:space-between;align-items:center;padding:.15rem 0;border:none;font-size:.8rem}
  .berichte-tbl tbody td::before{content:attr(data-label);font-weight:600;color:var(--fg3);font-size:.7rem;text-transform:uppercase;min-width:80px}
  .berichte-tbl tbody td:last-child{justify-content:flex-end;gap:.5rem}
  .berichte-tbl tfoot{display:none}
  .berichte-tbl tbody td.tbl-date::before{content:'Geändert'}
  .berichte-tbl tbody td:nth-child(1)::before{content:'Datum'}
  .berichte-tbl tbody td:nth-child(2)::before{content:'Baustelle'}
  .berichte-tbl tbody td:nth-child(3)::before{content:'Autor'}
  .berichte-tbl tbody td:nth-child(4)::before{content:'Wetter'}
  .berichte-tbl tbody td:nth-child(5)::before{content:'Status'}
  .berichte-tbl tbody td:nth-child(6)::before{content:'Anlagen'}
  .berichte-tbl tbody td:nth-child(7)::before{content:'📎'}
  .berichte-tbl tbody td:nth-child(8)::before{content:'Bemerkung'}
  .berichte-tbl tbody td:nth-child(9)::before{content:'Geändert'}
}

/* Mobile */
@media(max-width:768px){
  .sidebar{display:none}
  .main{margin-left:0;padding:1rem;padding-top:44px;padding-bottom:7rem}
  /* ebenfalls ueber Leaflet — sonst taucht die Sprachleiste unter
     einer Karte. */
  .mobile-lang-bar{display:flex;justify-content:flex-end;padding:.4rem .5rem;background:var(--bg2);border-bottom:1px solid var(--bg3);position:fixed;top:0;left:0;right:0;z-index:901}
  /* ⛔⛔ z-index 900 statt 100: Leaflet legt seine Ebenen bei
     200-700 und seine Bedienelemente bei 800 an. Mit 100 lag die
     Navigationsleiste **unter** der Karte — beim Scrollen lag das
     Bildraster ueber der Leiste (12.10.2026, gemeldet fuer die
     SDX-Minikarte). 900 liegt ueber Leaflet, aber weiterhin unter
     der Lightbox (10000), die weiterhin alles verdecken darf. */
  .mobile-nav{display:flex;position:fixed;bottom:0;left:0;right:0;background:var(--bg2);border-top:1px solid var(--bg3);z-index:900;padding:.4rem 0;overflow-x:auto;flex-wrap:nowrap;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .mobile-nav::-webkit-scrollbar{display:none}
  .mobile-nav a,.mobile-nav button{display:flex;flex-direction:column;align-items:center;gap:2px;color:var(--fg3);font-size:.6rem;background:none;border:none;cursor:pointer;padding:.3rem .5rem;text-decoration:none;flex-shrink:0;white-space:nowrap}
  .mobile-nav a.active,.mobile-nav button.active{color:var(--blue)}
  .mobile-nav .icon{font-size:1.2rem}
  .mobile-nav .label{font-size:.55rem}
/* S81: Unterpunkte in der Mobil-Leiste. Die Leiste ist eine
   **waagerechte, scrollende Reihe** (`flex-wrap:nowrap`,
   `overflow-x:auto`), deshalb wird die Gruppe dort zu einer Spalte:
   Punkt oben, Unterpunkt darunter. So bleibt die Leiste auf einer
   Zeile — ein eingerueckter Unterpunkt daneben waere breiter als
   die Leiste und wuerde alles seitlich verschieben.

   Der Strich (`└`) aus der Desktop-Variante entfaellt hier: waagerecht
   gelesen wuerde er falsch liegen. */
.nav-mobil-gruppe{display:flex;flex-direction:column;align-items:center;flex-shrink:0}
.nav-mobil-gruppe > a{padding:.2rem .4rem}
.nav-mobil-gruppe > a .nav-pfeil{font-size:.45rem;line-height:.7;margin-top:-1px;opacity:.5}
.nav-mobil-gruppe .nav-mobil-kind{border-top:1px solid var(--bg3);padding:.15rem .4rem}
.nav-mobil-gruppe .nav-mobil-kind .icon{font-size:.9rem}
.nav-mobil-gruppe .nav-mobil-kind .label{color:var(--fg3)}
  .form-row{grid-template-columns:1fr}
  .grid-3{grid-template-columns:1fr}
  .w-btns{gap:3px}.w-btn{padding:.25rem .5rem;font-size:.7rem}
  .row-card{flex-wrap:wrap}.row-card select,.row-card input{min-width:0}
  .user-card-actions{flex-direction:column}.user-card-actions .btn{width:100%;justifyContent:center}
  /* Baustellen-Kacheln */
  .bs-tile{min-width:100px;padding:.5rem .6rem}
  .bs-tile-name{font-size:.7rem;max-width:110px}
  .bs-tile-count{font-size:.95rem}
  /* Bericht cards */
  .bericht-card{padding:.75rem!important}
  .bericht-card-top{font-size:.85rem}
  .bericht-card-mid{font-size:.8rem}
  .bericht-card-bot{font-size:.75rem}
  /* Tables */
  table{font-size:.75rem}
  th,td{padding:.3rem .4rem}
  /* Cards */
  .card{padding:.75rem}
  .card h2{font-size:1rem;margin-bottom:.5rem}
  /* Buttons */
  .btn{font-size:.8rem;padding:.4rem .8rem}
  .btn-sm{font-size:.75rem;padding:.3rem .6rem}
  .btn-group{gap:.3rem}
  /* Detail */
  .foto-grid{grid-template-columns:repeat(2,1fr);gap:.5rem}
  .foto-thumb img{height:100px!important}
  /* Forms */
  select,input,textarea{font-size:.9rem;padding:.45rem}
  .sec-h{font-size:.85rem}
  /* Kalender */
  .cal-grid{gap:2px}
  .cal-day{min-height:2.2rem;font-size:.75rem}
}
@media(min-width:769px){
  .main{max-width:900px;margin-left:220px}
  .foto-grid{grid-template-columns:repeat(4,1fr)}
  table{font-size:.85rem}
  th,td{padding:.5rem .7rem}
}
@media(min-width:1400px){
  .main{max-width:1200px;margin-left:220px}
}
@media(min-width:1800px){
  .main{max-width:1600px;margin-left:220px}
}
@media(min-width:2400px){
  .main{max-width:2000px;margin-left:220px}
}

/* Hover row for team member list */
.hover-row:hover { background: var(--bg2) !important; }

/* Lightbox Overlay
   S69 — **`--lb-kopfreserve` lebt wieder auf, aus einem anderen Grund.**

   Die Reserve war in S68 entstanden, weil der ⬇ oben rechts dem ✏️ im
   Panel-Kopf im Weg lag (26 px Überschneidung, live gemessen). Mit dem ⬇
   in der Zoom-Leiste ist dieser Grund weg — und die Reserve wurde mit ihm
   entfernt. **Das war der Fehler:** „der Grund ist weg" heißt nicht „der
   Konflikt ist weg". Es heißt, dass ein *anderer* Nachbar frei wird — und
   der war der **✕** des Overlays (`.lb-close`, seit S39 am oberen rechten
   Rand, `right:16px`, 36×36, `top:12px`).

   Live gemessen, Desktop 1500×950, **nach** dem Wegfall der Reserve:
     Stift 1437.4…1469.0 × y 16…39   ✕ 1433…1469 × y 12…48
     `elementFromPoint(1453, 28)` → **`lightbox-close`**, nicht der Stift.
   Der Klick auf „Bearbeiten" wäre also im Schließen-Knopf gelandet — genau
   der Fehler, den S68 behoben hatte, mit anderem Nachbarn.

   **Die Herleitung geht die Kette hoch, nicht die Summe im Kopf** (S68 hat
   vier Fehlversuche gekostet, weil vom Nachbarrand statt vom Zeilenende aus
   gezählt wurde — AGENTS Punkt 18):
     Panel-Außenkante        1485   (gemessen, `.lb-panel`)
     Panel-Padding rechts      16   (`.lb-panel{padding:1rem}`)
     → Zeilenende Kopfzeile  = 1485 − 16 = **1469**   (gemessen, nicht gerechnet)
     ✕-Kante links           1433   (gemessen, nicht gerechnet)
     → Lücke                   10
     → Reserve = 1469 − (1433 − 10) = **46 px**

   ⚠⚠ **Das VORZEICHEN ist der ganze Fehler, und ich habe ihn S69 selbst
     gemacht — trotz der Warnung zwei Absätze darüber.** Meine erste
     Herleitung war `1469 − 1433 − 10 = 26`. Ergebnis nach dem Deploy:
     **gemessene Lücke −11 px**, der Stift endete auf 1444, der ✕ begann
     auf 1433 — der Overlap, den ich beseitigen wollte, war wieder da.
     Die Lücke wird **addiert**, nicht abgezogen: je weiter links der
     Knopf stehen soll, desto **größer** muss sein `margin-right` sein.
     `1469 − 1423 = 46`, nicht `1469 − 1443 = 26`.
     **Ein Vorzeichenfehler in einer Layoutherleitung sieht aus wie ein
     gerundeter Messwert — deshalb wird der Wert hier gegen das RECHTECK
     geprüft und nicht gegen die Rechnung.** Block 14 meldet bei einem
     Rücksprung sofort „die Reserve WIRKT" rot, mit der gemessenen Lücke.

   ⚠ **Und warum das jetzt eine Variable ist und nicht `margin-right: 46px`:**
     `margin-right` gegen einen Nachbarn bewegt den Knopf **nicht**, solange
     der Dateiname die Zeile füllt (`justify-content:space-between` verteilt
     nur den Rest). Genau daran ist S68 zweimal gescheitert: der Wert stand im
     `getComputedStyle`, der Knopf blieb auf x=1380. Erst `flex-shrink:0` am
     Knopf **und** `text-overflow:ellipsis` am Namen (LightboxPanel) machen
     die Reserve wirksam.

   ┌─────────────────────────────────────────────────────────────────┐
   │ ⛔ SPERRE (S69, `layout-blind` **zum 5. Mal** gemeldet).         │
   │ Diese Zahl darf **nicht** aus einer Rechnung im Kopf stammen.    │
   │ Beim Ändern des Werts gilt: **erst `elementFromPoint` messen**,  │
   │ dann den Wert setzen. Ein `NaN` oder ein vertauschtetes         │
   │ Vorzeichen sieht aus wie ein gerundeter Messwert — S69          │
   │ produzierte `26` statt `46` und deployte einen Overlap von     │
   │ −11 px. Der Block-14-Check „die Reserve WIRKT (Rechteck, nicht  │
   │ Computed-Style)" ist die Sperre in Code: er wird rot, sobald     │
   │ jemand an dieser Zahl dreht.                                    │
   └─────────────────────────────────────────────────────────────────┘ */
.lb-overlay{--lb-kopfreserve:46px; position:fixed;inset:0;background:rgba(0,0,0,.85);display:flex;z-index:10000;outline:none}
.lb-panel{width:300px;background:var(--bg2);border-left:1px solid var(--bg3);overflow-y:auto;padding:1rem;font-size:.8rem;color:var(--fg);flex-shrink:0}
@media(max-width:768px){
  .lb-panel{position:fixed;bottom:0;left:0;right:0;width:100%;max-height:45vh;border-left:none;border-top:1px solid var(--bg3);border-radius:12px 12px 0 0;z-index:10001}
}
/* S35: Mobile-Lightbox — zuerst nur das grosse Bild, Bildinfos per Button (FK) */
.lb-infobtn{display:none;position:absolute;bottom:10px;right:10px;z-index:10003;background:rgba(0,0,0,.6);color:#fff;border:1px solid rgba(255,255,255,.35);border-radius:99px;padding:.45rem .85rem;font-size:.8rem;cursor:pointer}
/* S36: Foto-Link kopieren (Direktlink ?foto=<id>) — links unten, immer sichtbar */
.lb-copylink{position:absolute;bottom:10px;left:10px;z-index:10003;background:rgba(0,0,0,.6);color:#fff;border:1px solid rgba(255,255,255,.35);border-radius:99px;padding:.45rem .85rem;font-size:.8rem;cursor:pointer;white-space:nowrap}
/* S39/S69: Panel-Kopf-Buttons (Stift/✕). **Kein eigener px-Wert** — die
   Reserve kommt aus `--lb-kopfreserve` am Vorfahren `.lb-overlay`; sie ist
   oben aus der **gemessenen** Kette hergeleitet, nicht geraten (S68: vier
   Fehlversuche). Der Stift braucht `flex-shrink:0` und der Dateiname
   `text-overflow:ellipsis` (LightboxPanel), sonst füllt der Name die Zeile
   und **kein** Wert wirkt. */
.lb-headbtn{margin-right:var(--lb-kopfreserve,0px);flex-shrink:0}
/* Unter 768 px liegt das Panel unten (S35) — es gibt keine Kopfzeile, die
   den Knöpfen ausweichen müsste, und 46 px Reserve würden den Dateinamen
   auf dem Handy unlesbar machen. */
@media(max-width:768px){
  .lb-overlay{--lb-kopfreserve:0px}
  .lb-headbtn{margin-right:0}
}
@media(max-width:768px){
  .lb-infobtn{display:block}
  .lb-overlay .lb-img{max-width:100vw!important;max-height:100vh!important}
  .lb-panel{display:none}
  .lb-overlay.lbinfo-open .lb-panel{display:block;max-height:56vh!important}
  .lb-overlay.lbinfo-open .lb-img{max-height:40vh!important}
}
/* S64: Bildhalter der Lightbox. Desktop = Panel (300 px) steht rechts, also
   bleibt Platz; unter 768 px ist das Panel per CSS aus (S35) und das Bild
   nimmt die volle Breite. Vorher stand `calc(100vw - 320px)` INLINE — Inline
   gewinnt gegen jedes Media-Query, auf 390 px blieben 70 px übrig. */
/* S69: **Unter 768 px überdeckt das offene Info-Panel die Zoom-Leiste.**
   Live gemessen (Tablet 768×1024, Sonde 4 + Suite): der ⬇ sitzt bei
   y=486…514, das Panel (`.lb-panel`, `position:fixed; bottom:0;
   max-height:45vh; z-index:10001`) reicht **über** diese Zeile, und
   `elementFromPoint(441, 486)` lieferte `lightbox-panel` statt `zl-download`
   — der Knopf war sichtbar und **nicht klickbar**.

   Bis S69 lag der ⬇ oben rechts neben dem ✕, also **über** dem Panel und
   von diesem Überlappen nicht betroffen. Mit dem Umzug in die Leiste ist
   er erstmals in den Bereich geraten, den das Panel auf Tablet/Handy
   belegt. Das ist ein **Produktfehler aus meinem eigenen Umbau**, und er
   fällt nur auf, wenn man den Klick-Punkt misst statt „der Knopf ist da".

   ⚠ Und die Reserve ist hier `0px` — sie kann nichts retten, denn sie
     steht am Panel-Kopf und der Konflikt ist Panel-gegen-Leiste, nicht
     Knopf-gegen-Knopf. */
.lb-bildhalter{display:flex;flex-direction:column;align-items:center;gap:8px;
  max-width:calc(100vw - 320px);max-height:calc(100vh - 40px)}
/* F10.40 — Kontext-Deckel für die Bilderschiene UNTER dem Bild
   (`BildLeiste` in der Lightbox, ~90 px + 8 px gap).

   ⛔ Gemessen ohne diesen Deckel: `.zl-bild` darf `100vh − 120` hoch
      sein, zusammen mit der Schiene ergab das ~`100vh − 22` — der
      Halter endet aber bei `100vh − 40`: die Schiene wäre aus dem
      Halter gelaufen (derselbe Fehler wie an der Messkarte, nur früher
      gemessen).

   ⛔ Steht VOR der Media-Query darunter: `.lb-overlay.lbinfo-open
      .zl-bild` (38vh) muss bei geöffnetem Panel weiterhin gewinnen —
      gleiche Spezifität, die spätere Regel entscheidet. */
.lb-bildhalter .zl-flaeche,.lb-bildhalter .zl-bild{max-height:calc(100vh - 230px)}
@media(max-width:768px){
  .lb-bildhalter{max-width:96vw;max-height:100vh;padding-bottom:34px}
  /* Ist das Info-Panel offen, gehört die Leiste **darüber**, nicht daneben.
     Live gemessen (Sonde 5, Mobile 390×844, Panel offen):
       Panel        y 371…844  (max-height 56vh = 472 px, Inhalt höher)
       Zoom-Leiste  y 391…429  → **mitten im Panel**, `elementFromPoint`
                               lieferte `lightbox-panel`.
     Eine Verkleinerung des Bildes allein reicht nicht: auf 390 px nimmt das
     Panel die halbe Höhe **plus** den Zähler, und die Leiste sitzt genau in
     diesem Band. Die Leiste wird deshalb **über** das Panel gehoben
     (`position:fixed` + `bottom`), damit sie auf **jeder** Breite
     bedienbar bleibt — unabhängig davon, wie hoch der Panel-Inhalt ist.

     ⚠ `bottom` statt `top`: die Leiste gehört ans **untere** Ende des
       Bildbereichs, und das ist die Hälfte, die auch bei geöffnetem Panel
       frei ist. Eine `top`-Position klebte sie an den ✕ (oben rechts). */
  .lb-overlay.lbinfo-open .zl-flaeche,
  .lb-overlay.lbinfo-open .zl-bild{max-height:38vh;max-width:96vw}
  .lb-overlay.lbinfo-open .zl-wrap{gap:4px}
  .lb-overlay.lbinfo-open .zl-leiste{
    position:fixed;z-index:10004;bottom:8px;left:50%;transform:translateX(-50%);
  }
  /* Der Zähler („3 / 12") und der 🔗-Knopf liegen unten — sie rutschen mit
     dem Panel nach oben, sonst stünden sie auf dem Panel. */
  .lb-overlay.lbinfo-open .lb-zaehler{bottom:auto;top:44vh}
}

/* ══ S60: Zoom + Vergrößerungslupe (Lightbox) ══════════════════════ */
.zl-wrap{display:flex;flex-direction:column;align-items:center;gap:8px;max-width:100%}
/* S64: `touch-action:none` ist Pflicht für die Touch-Bedienung. Ohne das
   behält sich der Browser die Geste vor und scrollt/zoomt die Seite selbst —
   `preventDefault()` im React-Handler allein genügt bei Touch NICHT zuverlässig.
   Es ist die einzige Stelle, an der man dem Browser die Geste abnimmt, BEVOR
   React sie sieht. Zwei Finger = Pinch, ein Finger = Pan/Lupe. */
.zl-flaeche{position:relative;display:flex;align-items:center;justify-content:center;
  max-width:100%;max-height:calc(100vh - 120px);overflow:hidden;border-radius:6px;
  touch-action:none;-webkit-tap-highlight-color:transparent;
  -webkit-user-select:none;user-select:none}
.zl-flaeche.mit-lupe{cursor:zoom-in}
.zl-bild{max-width:100%;max-height:calc(100vh - 120px);object-fit:contain;
  display:block;border-radius:6px;transition:transform .12s ease-out;user-select:none;-webkit-user-drag:none}
/* F10.40 — Kontext-Regel für die SDX-Großansicht der Messkarte.
   Dort stehen Pfeile, Steuer-Leiste („📥 Übernehmen") und Bilderschiene
   NICHT im Fenster, sondern IM Overlay — die Standard-Regel oben kennt
   nur das Fenster.

   ⛔⭐ Gemessen (Fenster 1213 px): Bild 1093 px (= 100vh − 120) +
      Pfeile 66 + Steuer 48 + Schiene 101 ⇒ Block höher als der
      Bildschirm. Der zentrierte Überlauf drückte die Steuer-Leiste in
      die Schiene hinein — der Knopf war nicht mehr klickbar
      (FK 27.10.: „hier ist die alte leiste verdeckt, ich kann nichts
      übernehmen").

   Dieselbe Lösungsform wie `.lb-overlay.lbinfo-open .zl-bild` (oben) —
   dort aus exakt demselben Grund eine Kontext-Regel, keine
   Globale: ein deckelndes `.zl-bild` würde jede andere ZoomLupe
   beschneiden. */
.mess-foto-gross .zl-flaeche,.mess-foto-gross .zl-bild{max-height:calc(100vh - 260px)}
/* F10.40 — Die SDX-Großansicht der Foto-Maske (`GrossesBild`): das Bild
   muss Platz für Steuer-Band UND Bilderschiene lassen (beide laufen im
   Fluss darunter). Ohne diese Kontext-Regel rechnet `.zl-bild` nur das
   Fenster (`100vh − 120`) und der untere Rand verschwindet hinter der
   Schiene — dieselbe Begründung wie `.lb-bildhalter .zl-bild` oben. */
.gross-bild .zl-flaeche,.gross-bild .zl-bild{max-height:calc(100vh - 260px);max-width:96vw}
/* Die Lupe: quadratisches Fenster, dem Zeiger folgend, Inhalt stark vergrößert */
.zl-lupe{position:absolute;width:190px;height:190px;margin:-95px 0 0 -95px;
  border:2px solid rgba(255,255,255,.92);border-radius:10px;overflow:hidden;
  box-shadow:0 8px 26px rgba(0,0,0,.65);pointer-events:none;z-index:5;
  background-repeat:no-repeat}
.zl-lupe-innen{position:absolute;inset:0;background-repeat:no-repeat}
.zl-lupe-kreuz{position:absolute;left:50%;top:50%;width:16px;height:16px;
  margin:-8px 0 0 -8px;border:1.5px solid rgba(255,255,255,.9);border-radius:50%;
  box-shadow:0 0 0 1px rgba(0,0,0,.5)}
.zl-lupe-label{position:absolute;right:4px;bottom:3px;font-size:.65rem;color:#fff;
  background:rgba(0,0,0,.65);padding:1px 5px;border-radius:4px;font-weight:700}
.zl-leiste{display:flex;align-items:center;gap:5px;background:rgba(20,20,25,.86);
  padding:4px 9px;border-radius:99px;border:1px solid rgba(255,255,255,.16)}
.zl-btn{background:transparent;border:1px solid rgba(255,255,255,.24);color:#fff;
  width:28px;height:28px;border-radius:50%;cursor:pointer;font-size:.95rem;line-height:1;
  display:flex;align-items:center;justify-content:center}
.zl-btn:hover{background:rgba(255,255,255,.16)}
.zl-btn:disabled{opacity:.4;cursor:default}
.zl-btn.aktiv{background:var(--blue);border-color:var(--blue)}
/* S69: der ⬇ in der Leiste. Er unterscheidet sich **nur** in der Farbe von
   den Bildwerkzeugen — er lädt die Datei herunter und verändert das Bild
   nicht. Kein eigener Positionswert: er ist das letzte Kind der `flex`-Reihe
   und steht damit mit dem Leisten-`gap:5px` neben der 🔍. Genau deshalb
   braucht es hier keinen px-Wert — S68 hat viermal an genau so einer Zahl
   gescheitert (`layout-blind`, AGENTS Punkt 18). */
.zl-dl{border-color:rgba(56,189,248,.75);color:#7dd3fc}
.zl-dl:hover{background:rgba(56,189,248,.22);border-color:#7dd3fc}
.zl-zoom{color:#fff;font-size:.78rem;font-weight:700;min-width:38px;text-align:center}
.zl-lupe-faktor{background:rgba(0,0,0,.5);color:#fff;border:1px solid rgba(255,255,255,.24);
  border-radius:6px;font-size:.72rem;padding:2px 4px;cursor:pointer}
@media(max-width:768px){
  .zl-flaeche,.zl-bild{max-height:78vh;max-width:96vw}
  .zl-lupe{width:130px;height:130px;margin:-65px 0 0 -65px}
}

/* ══ S60: Foto-GIS-Vorschau ═══════════════════════════════════════ */
.fg-box{margin-bottom:.9rem}
.fg-kopf{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}
.fg-hinweis{font-size:.72rem;color:var(--fg3)}
/* S62: Projekt-Auswahl = Ablageordner der importierten Fotos */
.fg-projekt{display:inline-flex;align-items:center;gap:.3rem;font-size:.72rem;color:var(--fg2)}
.fg-projekt select{
  font-size:.72rem;padding:.2rem .4rem;max-width:230px;
  background:var(--bg2);color:var(--fg);border:1px solid var(--border);border-radius:6px;
}
.fg-projekt select:focus{outline:none;border-color:var(--blue)}
.fg-projekt option{background:var(--bg2);color:var(--fg)}
.fg-inhalt{margin-top:.7rem;padding-top:.7rem;border-top:1px solid var(--bg3)}
.fg-regler{display:flex;align-items:center;gap:.45rem;flex-wrap:wrap;margin-bottom:.6rem}
.fg-label{font-size:.75rem;color:var(--fg2);font-weight:600}
.fg-radius-werte{display:flex;gap:3px;flex-wrap:wrap}
.fg-frei{width:82px;padding:.25rem .4rem;background:var(--bg);color:var(--fg);
  border:1px solid var(--bg3);border-radius:6px;font-size:.78rem}
.fg-status{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap;font-size:.78rem;
  color:var(--fg2);margin-bottom:.6rem;min-height:1.2rem}
.fg-modus{font-weight:700;color:var(--blue)}
.fg-detail{color:var(--fg3)}
.fg-warn{color:#f59e0b}
.fg-fehler{color:var(--red);font-weight:600}
.fg-ok{color:#2f9e44;font-weight:600}
.fg-leiste{display:flex;align-items:center;gap:.6rem;margin-bottom:.5rem;font-size:.78rem}
.fg-gitter{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:9px;
  max-height:520px;overflow-y:auto;padding:3px}
.fg-kachel{position:relative;border:2px solid var(--bg3);border-radius:var(--radius);
  overflow:hidden;cursor:pointer;background:var(--bg2);transition:border-color .12s}
.fg-kachel:hover{border-color:var(--blue)}
.fg-kachel.gewaehlt{border-color:#2f9e44;box-shadow:0 0 0 2px rgba(47,158,68,.35)}
.fg-kachel img{width:100%;aspect-ratio:3/4;object-fit:cover;display:block;background:var(--bg3)}
.fg-platzhalter{width:100%;aspect-ratio:3/4;display:flex;align-items:center;justify-content:center;
  font-size:1.8rem;background:var(--bg3)}
.fg-info{padding:5px 7px;font-size:.68rem;color:var(--fg3);display:flex;
  flex-direction:column;gap:2px}
.fg-zeile1{display:flex;justify-content:space-between;gap:6px}
.fg-entf{color:var(--blue);font-weight:700}
.fg-zeit{white-space:nowrap}
.fg-adr{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fg-tags{display:flex;gap:3px;flex-wrap:wrap;margin-top:2px}
.fg-tag{background:var(--bg3);border-radius:3px;padding:0 4px;font-size:.62rem}
.fg-tag.wetter{background:rgba(99,102,241,.22)}
.fg-haken{position:absolute;top:6px;right:6px;width:22px;height:22px;border-radius:50%;
  background:#2f9e44;color:#fff;display:none;align-items:center;justify-content:center;
  font-size:.8rem;font-weight:700;box-shadow:0 2px 6px rgba(0,0,0,.5)}
.fg-kachel.gewaehlt .fg-haken{display:flex}
.fg-fuss{display:flex;align-items:center;gap:.6rem;margin-top:.7rem;flex-wrap:wrap}
/* S63: „Bilder laden" — die Abfrage passiert erst auf Klick */
.fg-laden{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;
  padding:.7rem .8rem;border:1px dashed var(--bg3);border-radius:var(--radius);
  background:var(--bg2);margin-bottom:.7rem}
.fg-laden-text{flex:1 1 240px;font-size:.75rem;color:var(--fg3);line-height:1.4}
/* S63: Vorauswahl aus unseren Dateien (Formular + Stift-Panel + Lese-Modus) */
.fv-leiste{display:flex;align-items:center;gap:.6rem;margin:4px 0 6px;font-size:.72rem;color:var(--fg3);flex-wrap:wrap}
.fv-leiste button{padding:3px 10px;border-radius:12px;font-size:.72rem;font-weight:600;cursor:pointer;
  border:1px solid var(--bg3);background:var(--bg);color:var(--fg2)}
.fv-leiste button:hover{border-color:var(--blue);color:var(--blue)}

/* ══ S65: Spaltenzahl 1/2/3/4/6 (User-Pref `fv_spalten`) ══════════════
   Der Wert kommt als `--fv-spalten` VOM Raster. Vorher stand die
   Spaltenzahl als `minmax(74px,1fr)` INLINE im Grid — Inline gewinnt
   gegen jedes @media (S61b), deshalb war das Raster nicht anpassbar. */
.fv-spalten{display:inline-flex;align-items:center;gap:2px;margin-left:auto;
  padding:2px 4px;border:1px solid var(--bg3);border-radius:12px;background:var(--bg)}
.fv-spalten-lbl{font-size:.7rem;color:var(--fg3);white-space:nowrap;padding:0 3px}
.fv-spalten button{min-width:22px;padding:2px 4px;border-radius:9px;font-size:.68rem;font-weight:700;
  cursor:pointer;border:1px solid transparent;background:transparent;color:var(--fg2)}
.fv-spalten button:hover{border-color:var(--blue);color:var(--blue)}
.fv-spalten button.aktiv{background:var(--blue);border-color:var(--blue);color:#fff}
/* Auf dem Handy ist die Leiste voll — die Spaltenzahl wandert unter die
   „Alle markieren"-Zeile, statt die Breite zu sprengen. */
@media(max-width:768px){.fv-spalten{margin-left:0}}

/* Das Raster. `--fv-n` ist die einzige Quelle für die Spaltenzahl: vorher
   stand `minmax(74px,1fr)` inline und schlug damit jedes @media (S61b).
   Die Zahl setzt FotoRaster selbst — sie ist die kleinere aus Wunsch und
   Platz, damit auf dem Handy keine unbrauchbar kleinen Kacheln entstehen
   (gemessen: 6 Spalten wären 53 px) und auf dem Desktop trotzdem exakt
   die gewünschte Zahl steht. */
.fv-gitter{display:grid;gap:6px;grid-template-columns:repeat(var(--fv-n,6),minmax(0,1fr))}
.fv-kachel{position:relative;cursor:pointer;overflow:hidden;border-radius:8px;
  border:2px solid var(--bg3);background:var(--bg3);transition:border-color .12s}
.fv-kachel:hover{border-color:var(--fg3)}
.fv-kachel.gewaehlt{border-color:var(--blue);box-shadow:0 0 0 2px rgba(59,130,246,.35)}
/* Bilder sind quadratisch, damit 1 bis 6 Spalten dieselbe Kachelhöhe haben
   und der Name bei breitem Raster (4/6) nicht den Platz wegnimmt. */
.fv-kachel img,.fv-kachel .fv-platzhalter{width:100%;aspect-ratio:1/1;object-fit:cover;display:block;background:var(--bg3)}
.fv-kachel .fv-platzhalter{display:flex;align-items:center;justify-content:center;font-size:1.1rem;color:var(--fg3)}
/* Mit --fv-spalten=1 ist die Kachel riesig — dort wird das Bild nicht
   quadratisch, sonst hätte man eine 1200×1200 px grosse Kachel. */
.fv-gitter[data-spalten="1"] .fv-kachel img,
.fv-gitter[data-spalten="1"] .fv-kachel .fv-platzhalter{aspect-ratio:16/10}
.fv-haken{position:absolute;top:3px;left:4px;font-size:.9rem;line-height:1;
  color:#fff;text-shadow:0 0 3px #000;pointer-events:none}
.fv-m{position:absolute;top:3px;right:4px;font-size:.58rem;line-height:1;
  color:#fff;text-shadow:0 0 3px #000;pointer-events:none;white-space:nowrap}
/* S65: Der ℹ️-Knopf ist IMMER da (nicht per Media-Query ausgeblendet) —
   auf Touch gibt es keinen Hover, ohne ihn wäre die Karte dort unerreichbar
   (dieselbe Falle wie das Lightbox-Panel, S35). */
.fv-info-btn{position:absolute;bottom:3px;right:3px;width:24px;height:24px;line-height:1;
  display:flex;align-items:center;justify-content:center;border-radius:6px;cursor:pointer;
  border:1px solid rgba(255,255,255,.35);background:rgba(15,23,42,.8);color:#fff;font-size:.78rem;padding:0}
.fv-info-btn:hover{background:var(--blue);border-color:var(--blue)}
.fv-name{font-size:.6rem;padding:3px 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  background:rgba(0,0,0,.55);color:#fff}

/* ══ S65: Die Bild-Karte (Hover / Klick auf ℹ️) ══════════════════════
   `position:fixed` am Zeiger. Nicht `absolute` im Raster: die Kachel ist im
   Scrollport, das Raster steht in einem Panel, und die Karte soll nicht
   den Platz verschieben. */
.fv-karte{position:fixed;z-index:10050;width:330px;max-width:calc(100vw - 16px);
  background:var(--bg2);border:1px solid var(--blue);border-radius:10px;
  box-shadow:0 10px 34px rgba(0,0,0,.6);overflow:hidden;font-size:.72rem;color:var(--fg2)}
.fv-karte-kopf{display:flex;align-items:center;gap:7px;padding:6px;border-bottom:1px solid var(--bg3);
  background:var(--bg3);position:relative}
.fv-karte-bild{width:44px;height:44px;object-fit:cover;border-radius:5px;flex-shrink:0;background:var(--bg)}
.fv-karte-titel{flex:1;font-weight:700;font-size:.72rem;color:var(--fg);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fv-karte-x{border:none;background:transparent;color:var(--fg3);cursor:pointer;font-size:.9rem;
  line-height:1;padding:2px 4px;flex-shrink:0}
.fv-karte-x:hover{color:var(--red)}
.fv-karte-zeilen{padding:5px 7px;display:flex;flex-direction:column;gap:3px;max-height:52vh;overflow-y:auto}
.fv-karte-zeile{display:grid;grid-template-columns:82px 1fr;gap:7px;align-items:start}
.fv-karte-label{color:var(--fg3);font-weight:600}
.fv-karte-wert{color:var(--fg);word-break:break-word}
@media(max-width:768px){
  .fv-karte{width:calc(100vw - 24px)}
  .fv-karte-zeile{grid-template-columns:74px 1fr}
}
@media(max-width:768px){
  .fg-gitter{grid-template-columns:repeat(auto-fill,minmax(120px,1fr));max-height:60vh}
}

/* ══ S60: Berichts-Sprungmarke (Tag vor/zurück) ══════════════════ */
.sprung-aussen{display:flex;margin-bottom:.4rem}
.sprung-aussen.sprung-recht{justify-content:flex-end}
.sprung-wrap{display:inline-flex;align-items:center;gap:.4rem;
  background:var(--bg2);border:1px solid var(--bg3);border-radius:99px;padding:3px 5px}
.sprung-btn{width:30px;height:30px;border-radius:50%;border:1px solid var(--bg3);
  background:var(--bg);color:var(--fg);font-size:1.15rem;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center}
.sprung-btn:hover:not(:disabled){border-color:var(--blue);color:var(--blue)}
.sprung-btn:disabled{opacity:.3;cursor:default}
.sprung-info{display:flex;align-items:center;gap:.45rem;font-size:.72rem;color:var(--fg3);
  white-space:nowrap}
.sprung-zaehler{font-weight:700;color:var(--fg2)}
.sprung-datum{color:var(--fg)}
.sprung-nachbar{color:var(--fg3)}

/* Foto Grid — engerer Abstand */
.foto-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px}
/* Galerie Cards mit Baustellen-Name */
.foto-card{position:relative;background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);overflow:hidden;cursor:pointer;transition:all .15s}
/* S49: Multi-Modus Galerie — Auswahl-Häkchen oben links auf der Kachel */
.foto-card-sel{position:absolute;top:6px;left:6px;z-index:5;background:rgba(15,23,42,.75);border:1px solid rgba(255,255,255,.3);border-radius:6px;padding:4px 5px;line-height:1;cursor:pointer;display:flex}
.foto-card.marked{border-color:var(--blue);box-shadow:0 0 0 2px rgba(59,130,246,.55)}
.foto-card:hover{border-color:var(--blue);transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.2)}
.foto-card-img{width:100%;height:140px;object-fit:cover;display:block}
.foto-card-info{padding:.4rem .5rem;font-size:.7rem}
/* S69: `.foto-card-name` wird nicht mehr gerendert (FK: „bei der Galerie
   kannst du dort den Dateiname entfernen"). Die Regel bleibt als dokumentierte
   Stelle, falls er zurückkommt — sie kostet nichts und verhindert, dass das
   beim nächsten Ausbau neu erfunden wird. */
.foto-card-name{font-weight:600;color:var(--fg);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.foto-card-bs{color:var(--fg3);font-size:.65rem;margin-top:1px}
.foto-card-meta{display:flex;justify-content:space-between;align-items:center;margin-top:3px;color:var(--fg3);font-size:.6rem}
@media(min-width:769px){.foto-grid{grid-template-columns:repeat(4,1fr);gap:8px}}
@media(min-width:1400px){.foto-grid{grid-template-columns:repeat(5,1fr)}}

/* === S66: Galerie — Fotobeschreibung + Mini-Karte ===
   Die Fotobeschreibung steht UNTER dem Namen und über der Baustelle. Zwei
   Zeilen mit Ellipse; ohne die Klammerung würde ein 300-Zeichen-Text die
   Kachel um das Doppelte aufblähen und das Raster zerschießen. */
.foto-card-beschr{
  color:var(--fg2);font-size:.68rem;margin-top:2px;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
/* 📍-Knopf oben rechts. Er ist auf JEDEM Gerät sichtbar (nicht per @media
   ausgeblendet) — auf Touch gibt es keinen Hover, und ein ausgeblendeter
   Knopf ist ein toter Weg (S35, S65). */
.foto-card-karte-btn{
  position:absolute;top:6px;right:6px;z-index:6;
  width:28px;height:28px;border-radius:6px;line-height:1;font-size:.85rem;
  background:rgba(15,23,42,.78);border:1px solid rgba(255,255,255,.32);
  color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;
  backdrop-filter:blur(2px);
}
.foto-card-karte-btn:hover{background:var(--blue);border-color:var(--blue)}
.foto-card-karte-btn:active{transform:scale(.94)}

/* Der Kasten der Mini-Karte: position:fixed, damit er nicht von einem
   .foto-card mit `overflow:hidden` abgeschnitten wird (S61b-Klasse). */
.gal-karte-kasten{
  position:fixed;z-index:20050;width:268px;
  background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);
  box-shadow:0 10px 32px rgba(0,0,0,.45);overflow:hidden;
}
.gal-karte-kopf{display:flex;align-items:center;gap:6px;padding:6px 8px;border-bottom:1px solid var(--bg3);background:var(--bg)}
.gal-karte-titel{flex:1;font-size:.72rem;font-weight:700;color:var(--fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gal-karte-x{background:transparent;border:none;color:var(--fg3);font-size:.95rem;cursor:pointer;line-height:1;padding:2px 4px;border-radius:4px}
.gal-karte-x:hover{color:var(--fg);background:var(--bg3)}
.gal-karte{position:relative;background:var(--bg3)}
.gal-karte-box{width:100%;height:100%;border-radius:0}
/* Leaflet setzt .leaflet-container inline — die Höhe muss von uns kommen. */
.gal-karte .leaflet-container{width:100%;height:100%;background:var(--bg3);font:inherit}
.gal-karte-ohne{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:.75rem;color:var(--fg3);background:var(--bg2)}
.gal-karte-zeilen{padding:6px 8px 8px;max-height:220px;overflow:auto}
.gal-karte-zeile{display:flex;gap:8px;padding:2px 0;font-size:.7rem;line-height:1.35;border-bottom:1px solid var(--bg3)}
.gal-karte-zeile:last-child{border-bottom:none}
.gal-karte-label{flex:0 0 40%;color:var(--fg3);font-weight:600}
.gal-karte-wert{flex:1;color:var(--fg);word-break:break-word}

/* === S66: Bilderleiste unter der Karte ===
   Der Auftrag war „die Bilder nochmal größer": 96 px gegen 40 px des
   Markers. Der eigene Scroll-Container ist gewollt — die Leiste soll die
   Karte NICHT dehnen, sonst schiebt sie die ganze Seite nach unten. */
.kartenleiste{border-top:1px solid var(--bg3);background:var(--bg2)}
.kartenleiste-kopf{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;padding:.45rem .75rem;font-size:.75rem;color:var(--fg2)}
.kartenleiste-hinweis{color:var(--fg3);font-size:.68rem}
.kartenleiste-bilder{display:flex;gap:8px;overflow-x:auto;padding:.5rem .75rem .75rem;scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch}
.kartenleiste-bild{
  flex:0 0 auto;width:96px;height:96px;padding:0;cursor:pointer;background:var(--bg3);
  border:1px solid var(--bg3);border-radius:8px;overflow:hidden;scroll-snap-align:start;
  transition:border-color .15s, transform .15s;
}
.kartenleiste-bild:hover{border-color:var(--blue);transform:translateY(-1px)}
.kartenleiste-bild img{width:100%;height:100%;object-fit:cover;display:block}
.kartenleiste-platzhalter{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:1.2rem;color:var(--fg3)}
/* Auf dem Handy ist 96 px fast die halbe Breite — dort etwas kleiner, damit
   mehr als ein Bild ohne Ziehen sichtbar ist. */
@media(max-width:768px){.kartenleiste-bild{width:80px;height:80px}}

/* === S66: Zeitraum-Filter === */
.zr-box{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;width:100%;
  padding:.5rem .6rem;margin-top:.4rem;background:var(--bg2);
  border:1px solid var(--bg3);border-left:3px solid var(--blue);border-radius:var(--radius)}
.zr-feldwahl{display:flex;gap:2px;background:var(--bg3);padding:2px;border-radius:6px}
.zr-feldwahl button{border:none;background:transparent;color:var(--fg3);cursor:pointer;
  padding:.25rem .5rem;border-radius:4px;font-size:.72rem;white-space:nowrap}
.zr-feldwahl button.aktiv{background:var(--blue);color:#fff;font-weight:600}
.zr-daten{display:flex;gap:.5rem;flex-wrap:wrap}
.zr-ein{display:flex;flex-direction:column;gap:2px;font-size:.65rem;color:var(--fg3)}
.zr-ein input{background:var(--bg);border:1px solid var(--bg3);border-radius:6px;
  padding:.25rem .4rem;color:var(--fg);font-size:.78rem}
/* iOS/Dark: `color-scheme` sorgt dafür, dass der Kalender-Picker nicht weiß wird */
.zr-ein input{color-scheme:dark}
.zr-presets{display:flex;gap:.3rem;flex-wrap:wrap}
.zr-treffer{margin-left:auto;font-size:.72rem;color:var(--fg2);white-space:nowrap}
.zr-treffer strong{color:var(--fg);font-weight:700}
.zr-aktiv-hinweis{display:none}

/* === S67: Infopanel über der Kartenansicht ===
   Feste Position ÜBER der Karte (rechts oben), damit der Marker darunter
   anklickbar bleibt. `hidden` schaltet nur aus, der Inhalt bleibt im DOM. */
.karten-info{position:absolute;top:12px;right:12px;width:270px;z-index:1200;
  background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);
  box-shadow:0 8px 26px rgba(0,0,0,.45)}
.karten-info[hidden]{display:none}
.karten-info-kopf{display:flex;align-items:center;gap:6px;padding:6px 8px;
  border-bottom:1px solid var(--bg3);background:var(--bg)}
.karten-info-titel{flex:1;font-size:.72rem;font-weight:700;color:var(--fg);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.karten-info-x{background:transparent;border:none;color:var(--fg3);font-size:.95rem;
  cursor:pointer;line-height:1;padding:2px 4px;border-radius:4px}
.karten-info-x:hover{color:var(--fg);background:var(--bg3)}
.karten-info-zeilen{padding:6px 8px 8px;max-height:230px;overflow:auto}
.karten-info-zeile{display:flex;gap:8px;padding:2px 0;font-size:.7rem;line-height:1.35;
  border-bottom:1px solid var(--bg3)}
.karten-info-zeile:last-child{border-bottom:none}
.karten-info-label{flex:0 0 42%;color:var(--fg3);font-weight:600}
.karten-info-wert{flex:1;color:var(--fg);word-break:break-word}
/* Auf dem Handy nimmt ein 270-px-Panel die halbe Karte weg — dort nur
   öffnen, wenn der Nutzer es ausdrücklich anfasst (Tippen auf den Marker). */
@media(max-width:768px){.karten-info{width:calc(100vw - 32px);right:16px;top:8px}}

/* === S67/S69: Lightbox — Klassen für Pfeile/Zähler
   Die Lightbox war vorher an zwei Stellen inline gestylt; die Werte, die sich
   mit der Viewportbreite ändern (Bildbreite, Panel), liegen jetzt in
   Klassen (S61b).

   S69: **`.lb-download` ist entfernt** — der ⬇ sitzt jetzt in der Zoom-Leiste
   (`zl-dl`, s. `.zl-leiste`). Die Regel hier zielte auf einen Knoten, den es
   nicht mehr gibt. */
.lb-close{position:absolute;top:12px;right:16px;color:#fff;font-size:1.6rem;z-index:10002;
  cursor:pointer;opacity:.7;background:rgba(0,0,0,.5);border-radius:50%;width:36px;height:36px;
  display:flex;align-items:center;justify-content:center}
.lb-mitte{flex:1;display:flex;align-items:center;justify-content:center;position:relative;min-width:0}
.lb-pfeil{position:absolute;top:50%;transform:translateY(-50%);color:#fff;font-size:2.2rem;
  cursor:pointer;z-index:10002;background:rgba(0,0,0,.4);border:none;border-radius:50%;
  width:48px;height:48px;display:flex;align-items:center;justify-content:center;opacity:.6;padding:0}
.lb-pfeil-l{left:12px}
.lb-pfeil-r{right:12px}
.lb-pfeil:hover{opacity:1;background:var(--blue)}
.lb-zaehler{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);color:#fff;
  font-size:.75rem;background:rgba(0,0,0,.6);padding:.25rem .75rem;border-radius:99px}

/* === Camera-Karte (S34) === */
.cm-pin{width:26px;height:26px;background:var(--blue);border:2px solid #fff;border-radius:50% 50% 50% 0;transform:rotate(-45deg);box-shadow:0 2px 6px rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center}
.cm-pin span{transform:rotate(45deg);color:#fff;font-size:.7rem;font-weight:700;line-height:1}
.cm-pin.cm-pin-aktiv{width:34px;height:34px;background:#f59e0b;box-shadow:0 0 0 5px rgba(245,158,11,.45),0 2px 8px rgba(0,0,0,.5);z-index:1000}
.cm-pin.cm-pin-aktiv span{font-size:.85rem}
.cm-gps{width:16px;height:16px;background:#22c55e;border:3px solid #fff;border-radius:50%;box-shadow:0 0 0 5px rgba(34,197,94,.4)}
.cm-gps.cm-gps-manuell{background:#f59e0b;box-shadow:0 0 0 5px rgba(245,158,11,.45)}
.cam-item{position:relative;aspect-ratio:1;border-radius:6px;overflow:hidden;border:2px solid var(--bg3);cursor:pointer}
.cam-item-aktiv{border-color:var(--blue);box-shadow:0 0 0 3px rgba(59,130,246,.45)}
.cam-nr{position:absolute;bottom:2px;left:2px;min-width:18px;height:18px;border-radius:9px;background:var(--blue);color:#fff;font-size:.62rem;font-weight:700;display:flex;align-items:center;justify-content:center;padding:0 4px}
.cam-item-aktiv .cam-nr{background:#f59e0b}
.cam-thumbs{display:flex;gap:6px;overflow-x:auto;padding:.4rem 0;-webkit-overflow-scrolling:touch}
.cam-thumbs::-webkit-scrollbar{display:none}
.cam-thumb{position:relative;flex:0 0 auto;width:52px;height:52px;border-radius:6px;overflow:hidden;border:2px solid var(--bg3);cursor:pointer}
.cam-thumb.cam-thumb-aktiv{border-color:#f59e0b;box-shadow:0 0 0 3px rgba(245,158,11,.45)}
/* Bild ohne Standort: im Daumenverzeichnis sichtbar, nicht nur im Tooltip —
   auf dem Handy erscheint kein title. */
.cam-thumb-ohne{border-color:#ef4444;border-style:dashed}
.cam-thumb-ohne .cam-nr{background:#ef4444}
.cam-flag{position:absolute;top:1px;right:1px;background:#ef4444;color:#fff;font-size:.6rem;font-weight:700;line-height:1;padding:2px 3px;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.5)}
.gps-warn{border-left:4px solid #ef4444;background:rgba(239,68,68,.08)}
.gps-ok{display:flex;gap:.7rem;align-items:center;flex-wrap:wrap;padding:.7rem .9rem;margin-bottom:.7rem}

/* S43: Spalten-Resize + Column-Picker (Table-Skill)
   - th bleibt position:sticky (fuer den Scroll-Header) — sticky ist positioned → resizer kann absolut darin liegen
   - col-resizable: S48 -> table-layout:fixed.
     auto-Layout nimmt pro Spalte IMMER max(Wunschbreite, Textbreite): eine Textspalte
     kleiner zu ziehen aenderte optisch NIE etwas (Wunsch stand zwar in localStorage,
     die Spalte sprang aber auf die Textbreite zurueck) + der click nach dem Loslassen
     traf den th und loeste die Sortierung aus (siehe App.jsx justResizedRef).
     fix: Spalte = Wunschbreite aus dem th, Spalten ohne Wunschbreite teilen sich den
     Rest gleichmaessig; td clippt den Ueberlauf statt ihn ueber die Nachbarspalte zu
     malen. Horizontal-Scroll liefert .table-wrap (overflow-x:auto). */
.berichte-tbl.col-resizable{table-layout:fixed;width:100%;min-width:100%}
.col-resizable td{overflow:hidden}
.resizer{position:absolute;top:0;right:0;bottom:0;width:9px;cursor:col-resize;z-index:30}
.resizer:hover{background:rgba(59,130,246,.4)}
.col-pick-item{display:flex;align-items:center;gap:.35rem;padding:.15rem .1rem;font-size:.72rem;cursor:grab;border-bottom:1px solid var(--bg3)}
.col-pick-item:hover{background:var(--bg2)}
/* S61b: Spalten-Picker als KLASSEN, damit er auf dem Handy die Breite bekommt.
   Vorher stand die Breite inline (`width:440px`) — Inline gewinnt gegen jedes
   Media-Query, deshalb war das Fenster dort nur zur Hälfte sichtbar. */
.col-picker-box{
  background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);
  padding:.5rem;z-index:70;width:440px;max-width:calc(100vw - 1.2rem);
  box-shadow:0 4px 12px rgba(0,0,0,.3);position:absolute;top:100%;
}
.col-picker-box.links{left:0}
.col-picker-box.rechts{right:0}
.col-picker-hinweis{font-size:.7rem;font-weight:600;color:var(--fg3);margin-bottom:.4rem}
.col-picker-panels{display:flex;gap:.5rem}
.col-picker-panel{
  flex:1 1 0;min-width:0;background:var(--bg);border:1px solid var(--bg3);
  border-radius:var(--radius);padding:.3rem;max-height:270px;overflow-y:auto;
}
.col-picker-panel-titel{font-size:.65rem;color:var(--fg3);margin-bottom:.2rem}
.col-picker-fuss{display:flex;justify-content:space-between;margin-top:.4rem}
.col-pick-dropline{height:2px;background:var(--blue);border-radius:2px;margin:2px 4px}
@media (max-width:768px){
  /* Handy: Fenster an den Viewport koppeln, Panels untereinander (je halb so hoch) */
  .col-picker-box{
    position:fixed;top:auto;left:.5rem;right:.5rem;bottom:.5rem;width:auto;max-width:none;
    z-index:120;box-shadow:0 -4px 18px rgba(0,0,0,.35);
  }
  .col-picker-panels{flex-direction:column}
  .col-picker-panel{max-height:26vh}
}

/* ===== S52: Bulk-Leiste Berichte, Status „abgegeben", Wasserzeichen, Firmenlogo ===== */
.bulkbar{display:flex;gap:.6rem;align-items:center;flex-wrap:wrap;background:var(--bg2);
  border:1px solid var(--bg3);border-left:3px solid var(--blue);border-radius:var(--radius);
  padding:.55rem .8rem;margin-bottom:.7rem}
.bulkbar span{font-size:.85rem;font-weight:600}
.badge-warning{background:rgba(139,92,246,.15);color:#8b5cf6}
.wm-toggle-wrap input{accent-color:var(--blue)}
.logo-card img{image-rendering:auto}
/* S70: Unterschriften-Felder im Bericht */

/* Zwei Unterschriftsfelder nebeneinander — genau die zwei Zeilen im PDF.
   ⚠ In einer **Klasse**, nicht im Inline-Style: `@media` wirkt dort nicht
   (S61b, live gemessen — React ignoriert den Media-Key still).
   Grenze 768 px ist dieselbe wie überall im Projekt (Lightbox-Panel S35,
   Tabellenkopf S43). */
.unt-felder{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:12px}
@media (max-width:768px){.unt-felder{grid-template-columns:1fr;gap:10px}}

/* Die Zeichenfläche selbst. `background:#fff` ist **Pflicht**, auch im Dark
   Theme: der Normalisierer löscht Weiß (Alpha 0). Auf dunklem Grund
   entstünde im PDF eine schwarze Fläche. `touch-action:none` ebenso —
   ohne das geht die Geste an den Browser (S64, L3, live). */
.unt-canvas{display:block;touch-action:none;cursor:crosshair}
/* ── S71: Büro-Prüfung der vom MA draußen angelegten Trommeln ──────────
   ⚠ Kein Inline-Style: die Liste ist ein **Block** mit Foto, Daten und
   zwei Knöpfen, und auf dem Handy muss sie **untereinander** stapeln
   (S61b: ein Layoutwert, der sich mit der Viewportbreite ändert,
   gehört in eine Klasse).
   Die Anordnung Foto | Daten | Knöpfe ist Desktop; darunter 400 px wird
   einspaltig, weil drei Spalten auf dem Handy unlesbar sind. */
.tr-pruefliste{background:var(--bg2);border:2px solid var(--blue);border-radius:var(--radius);
  padding:.75rem;margin-bottom:.75rem}
.tr-pruefliste h3{display:flex;align-items:center;gap:.5rem;margin:0 0 .3rem;font-size:.95rem;color:var(--blue)}
.tr-pruef-zahl{background:var(--blue);color:#fff;border-radius:10px;padding:0 .45rem;
  font-size:.75rem;font-weight:700}
.tr-pruef-hinweis{font-size:.75rem;color:var(--fg2);margin:0 0 .5rem}
.tr-pruef-zeile{display:flex;gap:.6rem;align-items:flex-start;padding:.5rem 0;
  border-top:1px solid var(--bg3)}
.tr-pruef-foto{flex:0 0 auto}
.tr-pruef-foto .tr-beleg{width:104px;height:78px;object-fit:cover;border-radius:6px;
  border:1px solid var(--bg3);display:block}
.tr-pruef-foto .tr-beleg-kein{display:flex;align-items:center;justify-content:center;
  font-size:.65rem;color:var(--fg3);text-align:center;line-height:1.2}
.tr-pruef-daten{flex:1 1 auto;min-width:0;font-size:.78rem}
.tr-pruef-zeile2{color:var(--fg2);font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tr-pruef-zeile3{color:var(--fg3);font-size:.7rem}
.tr-pruef-hinweis-klein{font-size:.72rem;color:var(--fg2);margin-top:.2rem;font-style:italic}
.tr-pruef-knöpfe{flex:0 0 auto;display:flex;gap:.3rem;flex-wrap:wrap}
/* S72: Die Knöpfe der Büro-Prüfung waren **23,6 px** hoch (live gemessen,
   `getBoundingClientRect().height`) — kleiner als eine Fingerkuppe, und genau
   FKs Kern-Kritik: „wenn sie aber die button felder nicht vollständig sehen
   dann werden diese nicht bearbeitet".

   ⚠ **Kein geratener Pixelwert:** `min-height: 2.75rem` = **44 px** ist die
   iOS-Richtlinie für Daumen-Ziele. Darunter liegt nichts — der alte Wert war
   23,6 px, also **unter der Hälfte**. */
.tr-pruef-knöpfe .btn{min-height:2.75rem;padding:.4rem .9rem}
@media (max-width:560px){
  .tr-pruef-zeile{flex-wrap:wrap}
  .tr-pruef-daten{flex:1 1 100%;order:3}
  .tr-pruef-knöpfe{flex:1 1 100%;order:4}
  .tr-pruef-knöpfe .btn{flex:1 1 auto;min-height:2.75rem}
  .tr-pruef-foto .tr-beleg{width:88px;height:66px}
}

/* ── S71 (FK „A"): Charge **nachtragen**, wenn das Label unlesbar war ──
   ⚠ Wie `.tr-pruefliste`: eine Klasse, kein Inline-Style, weil die
   Zeile auf dem Handy unter 560 px ohnehin einspaltig stapelt. */
.tr-charge-nach{margin:.35rem 0 .15rem}
.tr-charge-zeile{display:flex;gap:.3rem;align-items:center;flex-wrap:wrap}
.tr-charge-fehler{font-size:.7rem;color:#ff6b6b;margin-top:.2rem}
.tr-charge-ok{font-size:.72rem;color:#2ecc71;margin-top:.2rem;font-weight:600}
@media (max-width:560px){
  .tr-charge-zeile{flex-wrap:nowrap}
  .tr-charge-zeile .btn{flex:0 0 auto}
}



/* ═══ S72: Der Sektions-Editor auf dem Handy als **Bottom-Sheet** ═══════
   FK: „wäre es allmein möglich bei einem edit den bereich in mobile ansicht
   als pop zu öffnen und so das man alle felder entsprechend sieht? die
   mitarbeiter sollten damit draußen mobile arbeiten. wenn sie aber die
   button felder nicht vollständig sehen dann werden diese nicht bearbeitet."

   ⛔⚠ **Vorher gemessen, nicht geraten** (iPhone-16-Klasse, 390×844,
   Sonde `tests/sonde-s72c.js`):

   | was | Wert |
   |---|---|
   | Material-Tabelle | **574 px** breit im Container von **374 px** |
   | Felder **außerhalb** des Viewports | **3 von 7** |
   | Material-`<select>` | **60 px** bei 40 Optionen |
   | **Speicher-Knöpfe** | y = **1030** — **186 px unter** dem Viewport |

   Die Knöpfe lagen also **unterhalb** des Schirms: genau FKs „die button
   felder nicht vollständig sehen dann werden diese nicht bearbeitet".

   ⇒ **Zwei Maßnahmen, beide nötig** — ein Sheet allein reicht nicht:
        a) das Sheet (unten, `position:fixed`), damit man nicht durch die
           ganze Seite scrollen muss, um an die Knöpfe zu kommen;
        b) die **Tabelle bricht auf dem Handy um** (`display:block` auf
           `tr`/`td`), sonst bleibt die 574-px-Tabelle auch im Sheet 574 px
           breit und der Material-Select bleibt 60 px („nur den Anfang").

   ⚠ **Die Grenze 768 px ist GEMESSEN, nicht gefühlt:** dieselbe Grenze
   trägt überall im Projekt (Lightbox-Panel S35, Tabellenkopf S43,
   `.col-picker` S61b, `.unt-felder` S70). Darüber bleibt die Tabelle
   eine Tabelle — sonst hätte ich die Desktop-Ansicht zerstört (S69:
   „Der Grund ist weg" heißt nicht „der Konflikt ist weg").

   ⚠ **Keine JS-Sichtbarkeit.** Das Sheet ist eine **Darstellung**
   (reines CSS an einer Klasse), kein State — sonst überlebt es
   Blöcke und Seiten (S67-L12 / AGENTS 17). */

/* Der Container, den die Stift-Sektionen bekommen. Auf dem Desktop ist er
   **unsichtbar** (position:static, keine Wirkung) — deshalb kann man ihn
   gefahrlos an alle 8 Sektionen setzen. */
.sec-edit-inhalt{position:relative}


@media (max-width:768px){
  /* Der Knopf-Bereich (`secBtns` in `App.jsx:1323`) muss **immer** sichtbar
     sein — er lag bei y=1030, also 186 px unter dem Schirm (gemessen).
     `flex:0 0 auto` + `margin-top:auto` halten ihn unten, wenn der Inhalt
     scrollt. */
  .sec-edit-inhalt .sec-btns{
    margin-top:auto;padding-top:.6rem;
    border-top:1px solid var(--bg3);
    display:flex;gap:8px;justify-content:flex-end;flex:0 0 auto;
    background:var(--bg);
  }
  .sec-edit-inhalt .sec-btns .btn{flex:1 1 auto;justify-content:center}

  /* Der Kopf (Sektionstitel + ✕). Das ✕ ist **nötig**: ein Sheet muss auch
     ohne Speichern zu gehen — sonst ist der ✏️-Stift eine Einbahnstraße.
     FK: „wenn sie aber die button felder nicht vollständig sehen dann
     werden diese nicht bearbeitet" — ein Weg **zurück** muss immer da sein.
     Gefüllt wird er von `secSheetKopf()` (App.jsx). */
  .sec-sheet-kopf{
    display:flex;align-items:center;gap:.5rem;flex:0 0 auto;
    padding:.1rem .6rem .45rem;border-bottom:1px solid var(--bg3);
  }
  .sec-sheet-kopf .sec-sheet-titel{font-size:.85rem;font-weight:700;flex:1 1 auto;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .sec-sheet-kopf .btn{flex:0 0 auto}

  /* Der Bereich, der scrollt: alles zwischen Kopf und Knöpfen. */
  .sec-sheet-body{overflow-y:auto;-webkit-overflow-scrolling:touch;
    padding:.5rem .6rem;flex:1 1 auto;min-height:0}
  /* ⛔ **`min-height:0` ist Pflicht** (kein Layoutwert zum Raten): in einem
     `flex`-Kind verhindert die automatische Mindesthöhe (= Inhalt) das
     Schrumpfen, und der Scrollbereich scrollt dann **nicht**. Ohne das
     wächst das Sheet über `max-height` hinaus (S69: Werte mit Herleitung). */
  /* a) Das Sheet. Werte aus der Messung, nicht geraten:
     · `max-height: 86vh` ⇒ 726 px bei 844 px Höhe — lässt 118 px für den
       Rest, das Sheet liegt über `.mobile-lang-bar` hinweg (z-index 200
       > 100, gemessen am col-picker: 120).
     · `padding-bottom` nimmt `env(safe-area-inset-bottom)` auf, sonst
       liegt der „Fertig"-Knopf auf der Home-Anzeige. Ohne die Variable
       (`--safeArea`, gemessen: **keine** definiert) greift der `0.5rem`. */
  .sec-edit-inhalt{
    position:fixed;left:0;right:0;bottom:0;top:auto;z-index:200;
    max-height:86vh;display:flex;flex-direction:column;
    background:var(--bg);border-top:2px solid var(--blue);
    border-radius:14px 14px 0 0;
    box-shadow:0 -6px 26px rgba(0,0,0,.45);
    padding-bottom:calc(.5rem + env(safe-area-inset-bottom,0px));
    animation:secSheetAuf .18s ease-out;
  }
  @keyframes secSheetAuf{from{transform:translateY(14px);opacity:.6}to{transform:none;opacity:1}}


  /* b) Die Tabelle bricht um. `display:block` auf den Zeilen macht aus
     jeder Zeile einen Block — die Zellen stapeln, und **jedes Feld
     bekommt die volle Breite**. Ohne das bleibt es bei 574 px. */
  .sec-edit-inhalt .table-wrap{overflow:visible}
  .sec-edit-inhalt table,
  .sec-edit-inhalt thead,
  .sec-edit-inhalt tbody,
  .sec-edit-inhalt tr,
  .sec-edit-inhalt td{display:block;width:100%}
  /* Der Kopf ist auf dem Handy **Dekoration**: die Felder haben eigene
     Beschriftungen (siehe unten). */
  .sec-edit-inhalt thead{display:none}
  .sec-edit-inhalt tr{
    border:1px solid var(--bg3);border-radius:var(--radius);
    background:var(--bg2);padding:.5rem;margin-bottom:.5rem;
  }
  .sec-edit-inhalt td{border:0;padding:.18rem 0}
  /* Jede Zelle bekommt ihre Beschriftung aus dem `data-label`, sonst
     steht nach dem Umbruch eine reihe Felder ohne Namen. */
  .sec-edit-inhalt td[data-label]::before{
    content:attr(data-label);
    display:block;font-size:.62rem;font-weight:600;color:var(--fg3);
    text-transform:uppercase;letter-spacing:.4px;margin-bottom:2px;
  }
  /* Der Material-Select: FK „im dropdown sehe ich nur den anfang".
     `min-width:100%` ist der eigentliche Fix — er stand als **eine** von
     sechs Spalten in 60 px. */
  .sec-edit-inhalt select,
  .sec-edit-inhalt input{width:100%;min-width:0;max-width:100%}
  /* Der Stift (✏️) in der Überschrift darf NICHT im Sheet kleben. */
  .sec-edit-inhalt .btn-sm{padding:.35rem .6rem}
}

/* ⛔ **Eine Kopie der Zeile ist auf dem Handy keine Zeile mehr** — das ist
   der Grund für `display:block`. Auf dem Desktop gilt **keine** dieser
   Regeln; dort bleibt alles unverändert (S69). */
@media (min-width:769px){
  /* Desktop: **kein** Sheet, **kein** Kopf. Der Kopf mit dem ✕ wäre dort
     ein Duplikat des Stift-Knopfes — zwei Wege zum selben Ziel (S69/D21). */
  .sec-sheet-kopf{display:none}
  .sec-sheet-body{overflow:visible;padding:0;min-height:0}
  .sec-edit-inhalt{position:static}
}
/* ══ S75/D30-b — Bericht-Tabellen bleiben in ihrem Rahmen ════════════════
   FK: „bei der mobile ansicht auf dem handy. ist die liste nicht sichtbar.
   beim ort ist es nicht mehr sichtbar. beim material ist die spalte
   bemerkung auch nicht sauber sichtbar. die reicht auch ueber den
   sichtbereich."

   **Gemessen** (mobile, 390 px Viewport, Karte 358 px):

   | Tabelle               | vorher | Ursache                        |
   |-----------------------|--------|--------------------------------|
   | Foto-Liste (Bericht)  | 777 px | `table-layout:auto`, 8 Spalten |
   | Material (Lesen)      | 396 px | `table-layout:auto`, 5 Spalten |
   | Material (Lesen, 2.)  | 398 px | dieselbe, zweite Gruppe        |

   `table-layout:auto` nimmt je Spalte `max(Wunsch, Text)` — die Tabelle
   wird **breiter als ihr Rahmen**, und `.main{overflow-x:clip}` schneidet
   sie ab. Der Inhalt landet im Nirgendwo; ein Scrollbereich würde den
   S49-Fehler (tote sticky-Köpfe) zurückbringen, also wird die **Ursache**
   behoben.

   `table-layout:fixed` verteilt die Breite nach den `th`-Breiten und lässt
   den Rest gleichmäßig teilen ⇒ die Tabelle ist **exakt** so breit wie ihr
   Rahmen. `td{overflow:hidden;text-overflow:ellipsis}` kürzt **innerhalb**
   der Spalte — das ist der Unterschied zwischen „nicht sichtbar"
   (abgeschnitten, kein Weg hinein) und „lesbar, mit …".

   Auf dem Handy wird jede Bericht-Tabelle zur **Karte**: eine Zeile je
   Feld, beschriftet aus `data-label` (S75/D30-c). Damit kann gar nichts
   mehr „über den Sichtbereich reichen" — es gibt keinen Seitenbereich
   mehr, den man verfehlen könnte. */
.bericht-tab table{width:100%;table-layout:fixed}
.bericht-tab td,.bericht-tab th{overflow:hidden;text-overflow:ellipsis}
/* Die Aktionen (✏️ ⊘ ⛶) dürfen **nicht** gekürzt werden — sonst bleiben
   von einem Knopf zwei Pixel. Sie bekommen die Restbreite und dürfen
   überlaufen. */
.bericht-foto-liste td:last-child,.bericht-foto-liste th:last-child{overflow:visible}
/* Die Trommel-Spalte braucht ihre volle Breite für die 14-stellige
   LOT-Nummer (`LOT00000124019`); gekürzt wäre sie unbrauchbar. */
.bericht-mat-lese td:nth-child(4),.bericht-mat-edit td:nth-child(5){overflow:visible}
/* ══ S76/D32-c — der LOT-Dropdown wurde „komplett verschluckt" ══════
   FK, wörtlich: „wenn man eine nummer für die autovervollständigung
   eingibt sieht man ganz leicht das eine art dropdown auswahl aufgeht aber
   man kann gar nichts erkennen. die verschwindet in der seite wird
   komplett verschluckt."

   **Gemessen** (mobile, `tests/weg/S76-d-rest.js`): die Liste ist 52 px
   hoch, **51 px** liegen ausserhalb der umgebenden `td` — und `td` hat
   `overflow:hidden/hidden`. `elementFromPoint` an **sechs** Punkten, an
   denen die Liste sein muss, liefert `TD` / `TR`, nie die Liste. Der
   Nutzer bekommt also einen **1-px-Streifen** und nichts sonst — genau
   „man kann gar nichts erkennen".

   **Ursache:** D30-b (`table-layout:fixed` + `td{overflow:hidden}`) ist
   die richtige Lösung für die *Tabelle* — sie hält Spalten im Rahmen. Die
   Trommel-Zelle trägt aber ein **absolutes** Kind (`.mat-trommel-liste-*`,
   `z-index:40`), und `overflow:hidden` ignoriert `z-index` **immer**: es
   ist ein Clip, keine Stapel-Ebene. Ein `z-index:9999` hätte nichts
   geholfen.

   ⚠⚠ **Die Regel `.bericht-mat-edit td:nth-child(5)` von oben hat genau
   das verhindert — sie ist ein toter Selektor.** Im ganzen Repo kommt
   `bericht-mat-lese` / `bericht-mat-edit` **einmal** vor: in dieser CSS
   Zeile. Kein JSX vergibt sie (S66/D12: eine Regel, deren Klasse nie
   gesetzt wird, ist eine Lüge über die Absicht — und sie hat den
   gemeldeten Fehler zwei Tage verdeckt).

   **Fix an der Quelle:** die Zelle, die das absolute Kind traegt, clippt
   nicht. Über `.sec-edit-inhalt` (der Wrapper des Stift-Sheets) statt
   über eine Klassen-Kette, die es nicht gibt — und damit **jede**
   Materialzeile, ohne sie zu nummerieren. */
.sec-edit-inhalt td:has(> div > div[style*="relative"]),
.sec-edit-inhalt td:has(> div > div > div[style*="relative"]){overflow:visible}

/* ── Karten-Modus auf dem Handy ──────────────────────────────────────────
   D30-c: die acht `nth-child`-Beschriftungen in `index.css` waren für die
   **Berichte**-Tabelle geschrieben. Die Upload-Tabelle trägt dieselbe
   Klasse `.berichte-tbl` und las deshalb deren Namen — gemessen: der
   Dateiname stand unter „Autor", das GPS unter „Status". Ab jetzt ist
   `data-label` (aus dem `thead` berechnet, siehe `tabellenLabels.js`) die
   einzige Beschriftung; die Klasse `n-labels` schaltet die `nth-child`-Namen
   ab, damit nicht zwei Regeln für dasselbe Feld konkurrieren. */
.berichte-tbl.n-labels tbody td:nth-child(1)::before,
.berichte-tbl.n-labels tbody td:nth-child(2)::before,
.berichte-tbl.n-labels tbody td:nth-child(3)::before,
.berichte-tbl.n-labels tbody td:nth-child(4)::before,
.berichte-tbl.n-labels tbody td:nth-child(5)::before,
.berichte-tbl.n-labels tbody td:nth-child(6)::before,
.berichte-tbl.n-labels tbody td:nth-child(7)::before,
.berichte-tbl.n-labels tbody td:nth-child(8)::before,
.berichte-tbl.n-labels tbody td:nth-child(9)::before{content:attr(data-label)}
.berichte-tbl.n-labels tbody td::before{min-width:0;font-size:.62rem}

@media(max-width:768px){
  /* Bericht-Tabellen → Karten. `display:block` löst die Zellen aus der
     Zeile; jede bekommt ihre Beschriftung **darüber** statt in einer
     eigenen Spalte, die es auf 390 px nicht gibt. */
  .bericht-tab thead{display:none}
  .bericht-tab tbody tr{display:block;padding:.5rem .1rem;border-bottom:1px solid var(--bg3)}
  .bericht-tab tbody td{
    display:block;text-align:left!important;padding:.12rem 0;border:none;
    font-size:.78rem;white-space:normal;max-width:none;
  }
  .bericht-tab tbody td[data-label]::before{
    content:attr(data-label);display:block;font-size:.62rem;font-weight:600;
    color:var(--fg3);text-transform:uppercase;letter-spacing:.4px;margin-bottom:1px;
  }
  /* Die Auswahl-/Trommelzellen: Inhalt darunter statt daneben. */
  .bericht-tab tbody td[data-label] > div{display:block}
  .bericht-tab tbody td:first-child:empty{display:none}
}
/* ══ S75/D30-d+e — Bericht-Galerie: Spaltenzahl + Bildinfos ══════════════
   FK: „in der mobilen ansicht stehen bei dem bericht unten bei den Bilder
   in der galerie ansicht keine Bild informationen. hier sollte das so wie
   bei dateien sein." + „hätte ich auch gerne in der desktop version die
   moeglichkeit das Grid anderst aufzuteilen."

   **Vorher gemessen:** `gridTemplateColumns` als **Inline-Style** am `div` —
   und ein Inline-Style schlägt **jedes** `@media` (S61b). Das Grid war damit
   grundsätzlich nicht anpassbar. Dieselbe Ursache wie S65, dort mit
   `--fv-spalten` gelöst; hier greift dieselbe Variable.

   ⚠ Die Mindestbreite ist hier **150 px**, nicht die 70 px aus S65: unter
   dem Bild steht eine Infobox (Aufnahme, Adresse, Koordinaten, Wetter …).
   70 px für beides zusammen heißt „Bild da, Information weg" — und genau
   das ist der gemeldete Fehler. Gemessen am Handy (390 px, 358 px Rahmen):
   3 Spalten ⇒ 110 px (unter der Grenze) ⇒ **2** Spalten mit ~160 px.

   `.ber-gal-kachel` ist bewusst **nicht** `.fv-kachel` (aspect-ratio 1/1,
   object-fit): ein Tagesbericht-Foto soll im Seitenverhältnis stehen, und
   darunter gehört Text — der dürfte nicht beschnitten werden. */
.ber-gal{margin-top:.4rem}
/* Die Picker-Leiste: `.fv-spalten` bringt `margin-left:auto` mit (S65), das
   steht hier falsch herum — der Picker gehört **links** über dem Raster. */
.ber-gal-leiste{margin-left:0;margin-bottom:.4rem}
.ber-gal-gitter{gap:14px;grid-template-columns:repeat(var(--fv-n,3),minmax(0,1fr))}
.ber-gal-kachel{display:flex;flex-direction:column;min-width:0;
  border:1px solid var(--bg3);border-radius:var(--radius);overflow:hidden;
  background:var(--bg2);cursor:pointer}
.ber-gal-kachel:hover{border-color:var(--fg3)}
.ber-gal-bild{width:100%;aspect-ratio:16/10;object-fit:cover;display:block}
/* Bei 1 Spalte ist die Kachel breit — dann darf das Bild höher sein,
   sonst wäre ein 1200-px-Foto ein 200-px-Band (S65, `data-spalten="1"`). */
.ber-gal-gitter[data-spalten="1"] .ber-gal-bild{aspect-ratio:21/9}
.ber-gal-info{padding:.4rem .5rem .5rem;display:flex;flex-direction:column;gap:2px;
  font-size:.7rem;min-width:0}
/* S76/D32-a — die kleine Karte in der Kachel (FK: „eine kliene minikarte
   mit einem pin wo sich das bild befindet").

   ⛔⚠ **Die Größe kommt aus dem JSX (`breite="100%" hoehe={86}`), nicht
   von hier** — `StandortKarte` setzt sie per Inline-Style, und Inline
   schlägt jede Klasse (S61b). Die folgende Regel ist deshalb **nur** die
   Form (Radius) und der Hinweis für den nächsten Umbau.

   ⚠ Und: `.gal-karte` wird in **zwei** Größen benutzt (Popup 244×150,
   Kachel 100 %×86). Wer die Größe hier festschreibt, baut die nächste
   Wahrheit — deshalb steht sie **beim Aufrufer** (AGENTS D12). */
.ber-gal-info .gal-karte{border-radius:6px;overflow:hidden;margin-bottom:2px}
.ber-gal-info .gal-karte .gal-karte-ohne{font-size:.62rem}
/* Der Dateiname ist weg (S76/D32-a) — die Regel bleibt für alte, noch
   nicht neu gebaute Kacheln im Bundle (S65: „ein stillschweigend
   gelöschter Check ist schlimmer als ein roter"). Sie wird an **einer**
   Stelle definiert und nicht wieder gebraucht. */
.ber-gal-name{font-weight:600;color:var(--fg);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-size:.74rem}
/* Beschriftung links, Wert rechts — und **beide** dürfen umbrechen bzw.
   kürzen. `min-width:0` ist Pflicht: ohne es schiebt der Wert die Beschriftung
   aus der Zeile (S68: `margin-right` gegen einen Nachbarn braucht
   `flex-shrink:0`; hier ist es die Umkehrung — der Nachbar soll kürzen). */
.ber-gal-zeile{display:flex;gap:.4rem;align-items:baseline;min-width:0}
.ber-gal-label{flex:0 0 auto;color:var(--fg3);font-size:.62rem;text-transform:uppercase;
  letter-spacing:.4px;font-weight:600}
.ber-gal-wert{flex:1 1 auto;min-width:0;color:var(--fg2);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
/* ⛔⚠ **S76 — diese drei Regeln sind jetzt FALSCH, und zwar gemessen.**
   Sie stapeln die Zeilen auf dem Handy und waren fuer **neun** Felder
   geschrieben (S75). Nach D32-a sind es **drei** (Tags, Baustelle,
   Groesse, ggf. Adresse) — und da passt nebeneinander alles.

   **Gemessen** (mobile, 390 px, 2 Spalten ⇒ 160-px-Kachel,
   `tests/weg/variante.js`):

   | Variante            | Text hoehe | gekuerzte Werte |
   |---------------------|-----------|-----------------|
   | gestapelt (vorher)  | **125 px** | 0 von 3          |
   | nebeneinander       | **89 px**  | 0 von 3          |

   Bei drei kurzen Werten ist der Stapel **reiner Verlust** — 36 px
   (das Doppelte einer Zeile) ohne einen einzigen gekuerzten Wert. Die
   alte Begruendung („zwei Zeilen nebeneinander sind zu eng") stammt aus
   der Zeit mit neun Feldern; sie gilt fuer drei nicht mehr.

   ⚠ Und: das Bild ist auf dem Handy nur **99 px** hoch (160 px Kachel ×
   16/10), der Text war **125 px** — der Auftrag „zu viele Informationen"
   ist damit auch **gemessen** erfuellt geblieben, obwohl die Zeilenzahl
   stimmt.

   ⇒ Das Stapeln faellt weg. Die Werte duerfen **kuerzen** (dann gibt es
   `title` und den vollen Text in der Lightbox) — sie duerfen nicht
   **umbrochen** werden, denn ein Umbruch macht aus einer Zeile zwei. */
@media(max-width:768px){
  .ber-gal-gitter{gap:10px}
  .ber-gal-zeile{display:flex}
  .ber-gal-label{display:inline;margin-bottom:0}
  .ber-gal-wert{display:block;white-space:nowrap;word-break:normal}
  .ber-gal-aktionen{display:flex;gap:.3rem;margin-top:.3rem;justify-content:flex-end}
}

/* ⛔ Lageplan-Schärfe (FK, 23.10.2026): ab 100 % wird das Blatt
   hochskaliert — dann HART statt weich, damit die kleine Schrift im
   Trassenblatt lesbar bleibt. Unter 100 % (Verkleinerung) bleibt die
   normale Glättung, sonst treppen die Linien. */
.lp-scharf { image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; image-rendering: pixelated; }
