/*
 * teccle group corporate identity - shared design tokens and base styles
 * for teccle.webinvoice. Source: teccle_ci repo (ci-vorgaben/grundlagen.md,
 * ci-vorgaben/web-app-design.md). Black is never used per the CI - text is
 * always teccle-blau-100 on light backgrounds, teccle-weiss on dark ones.
 */

@font-face {
  font-family: 'Montserrat';
  src: url('/fonts/montserrat/Montserrat-Regular.ttf') format('truetype');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/fonts/montserrat/Montserrat-Medium.ttf') format('truetype');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/fonts/montserrat/Montserrat-SemiBold.ttf') format('truetype');
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/fonts/montserrat/Montserrat-Bold.ttf') format('truetype');
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/fonts/montserrat/Montserrat-ExtraBold.ttf') format('truetype');
  font-weight: 800;
  font-display: swap;
}

:root {
  /* Primärfarben */
  --teccle-rot-100: #FF4221;
  --teccle-blau-100: #00005A;
  --teccle-rot-10: #FFE6E6;
  --teccle-blau-10: #E6E6F0;
  --teccle-gelb-100: #FFC821;

  /* Sekundärfarben */
  --teccle-rot-75: #FAA5A0;
  --teccle-rot-50: #FFC8C3;
  --teccle-blau-75: #9191BE;
  --teccle-blau-50: #BEBEDC;
  --teccle-gelb-50: #FFEBB2;
  --teccle-gelb-10: #FFF8E0;

  /* Struktur/Neutral */
  --teccle-grau-100: #D1D8DC;
  --teccle-grau-50: #ECEFF1;
  --teccle-weiss: #FFFFFF;

  /* Semantische Tokens */
  --color-text: var(--teccle-blau-100);
  --color-text-on-dark: var(--teccle-weiss);
  --color-brand-accent: var(--teccle-rot-100);
  --color-bg-group: var(--teccle-rot-10);
  --color-bg-products: var(--teccle-blau-10);
  --color-border: var(--teccle-grau-100);
  --color-surface: var(--teccle-weiss);
  --color-surface-muted: var(--teccle-grau-50);

  /*
   * Functional status colors - not part of the CI's brand palette (which
   * has no error/success semantics), chosen to stay clearly distinct from
   * teccle-rot-100 (a brand accent, not a "danger" signal) while never
   * using black.
   */
  --color-error-text: #8A1200;
  --color-error-bg: var(--teccle-rot-10);
  --color-error-border: var(--teccle-rot-75);
  --color-success-text: #0F5C1F;
  --color-success-bg: #E3F3E5;
  --color-warning-bg: var(--teccle-gelb-10);
  --color-warning-border: var(--teccle-gelb-100);
  --color-warning-text: #8A5A00;

  --font-heading: 'Montserrat', Verdana, sans-serif;
  --font-body: 'Montserrat', Verdana, sans-serif;

  /* Shape + depth (one consistent scale, applied everywhere) */
  --radius: 8px;
  --radius-sm: 4px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 90, 0.06);
  --shadow-md: 0 4px 16px rgba(0, 0, 90, 0.08);
  --transition: 150ms ease;
}

* {
  box-sizing: border-box;
}

/*
 * Sticky-Footer-Mechanismus (FIXLIST-03, Phase 26 Plan 3) - EIN Mechanismus fuer
 * alle Seitenfamilien statt der bisherigen drei Sonderloesungen (regulaere Seiten,
 * .admin-shell, .login-shell). body selbst ist bewusst der Flex-Container statt
 * eines zusaetzlichen Wrapper-Elements - so bleiben alle Templates unveraendert,
 * jedes bindet weiterhin nur Kopfbereichs-Fragment, Inhaltsbereich und
 * fragments/footer als direkte Body-Kinder ein. Der jeweilige Inhaltsbereich
 * (.content / .legal-content / .login-shell, siehe dort) traegt eine eigene
 * Flex-Grow-Deklaration und waechst auf den verbleibenden Raum, wodurch der Footer auf kurzen Seiten
 * an den unteren Rand gedrueckt wird statt in der Seitenmitte zu schweben, und
 * auf langen Seiten ganz normal im Fluss unterhalb des Inhalts steht.
 * .sidebar ist position: fixed und nimmt daher nicht am Flex-Layout teil - der
 * Mechanismus beeinflusst sie nicht. <script>-Elemente auf Body-Ebene tragen
 * per UA-Stylesheet display: none und erzeugen deshalb keine leeren Flex-Items.
 */
body {
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--teccle-grau-50);
  margin: 0;
  line-height: 1.5;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

h1, h2, h3 {
  font-family: var(--font-heading);
  font-weight: 700;
  color: var(--color-text);
  letter-spacing: -0.01em;
}

h1 {
  border-bottom: 3px solid var(--color-brand-accent);
  padding-bottom: 0.5rem;
  display: inline-block;
}

a {
  color: var(--color-text);
  text-decoration-color: var(--teccle-blau-50);
  transition: text-decoration-color var(--transition), color var(--transition);
}
a:hover {
  color: var(--color-brand-accent);
  text-decoration-color: var(--color-brand-accent);
}

.content {
  margin: 0;
  max-width: 1400px;
  padding: 2.5rem 2rem;
  flex: 1 0 auto;
}

/*
 * .legal-content (impressum.html, datenschutz.html) traegt hier ausschliesslich
 * die Flex-Grow-Deklaration darunter, damit sie am Sticky-Footer-Mechanismus
 * (siehe body oben) teilnimmt. max-width/margin/padding bleiben in den inline <style>-Bloecken
 * der beiden Templates definiert - dort wird flex nicht gesetzt, es entsteht
 * also kein Konflikt.
 */
.legal-content {
  flex: 1 0 auto;
}

/*
 * .login-shell traegt hier ebenfalls nur dieselbe Flex-Grow-Deklaration fuer
 * den Sticky-Footer-Mechanismus (siehe body oben). login.html setzt in seinem eigenen inline
 * <style> zusaetzlich min-height: 100vh auf dieselbe Klasse - das inline
 * <style> steht im Dokument nach diesem Stylesheet und gewinnt, hebelt den
 * Mechanismus dort also noch aus. Das ist hier bewusst nicht angefasst -
 * gehoert zu Plan 26-04 (Login-Screen-Layout).
 */
.login-shell {
  flex: 1 0 auto;
}

.brand-logo {
  height: 2rem;
  display: block;
  width: auto;
}

/*
 * teccle.webinvoice product logo. Two lockups, see docs/branding-logo.md:
 *   stapel    - two lines, no pictorial mark. Minimum height 28px, because
 *               below that the product line's x-height drops under 5px.
 *   signet    - pictorial mark + wordmark. Minimum height 32px.
 *   bildmarke - the mark on its own. Works down to 16px.
 * Never set the height inline - use one of these classes, so the minimums
 * stay enforceable in one place. Clear space is a quarter of the logo height,
 * which clears half the wordmark's x-height in both lockups.
 */
.brand-logo--header { height: 2.375rem; }   /* 38px - signet lockup in the app bar */
.brand-logo--login  { height: 2.5rem; }     /* 40px - stapel on the login screen */
.brand-logo--footer { height: 1.75rem; }    /* 28px - stapel, the documented minimum */
.brand-logo--icon   { height: 1.5rem; }     /* 24px - bildmarke solo */

/* Clear space: no other element may enter this margin. */
.brand-logo--clear { margin: 25%; }

@media (max-width: 640px) {
  /* Below the stapel minimum the product line stops being legible, so small
     screens switch to the mark instead of shrinking the lockup further. */
  .brand-logo--header { height: 2rem; }
  /* Login-Streifen (Plan 26-04) schrumpft an dieser Stufe mit - 2rem (32px)
     bleibt oberhalb der dokumentierten 28px-Mindesthoehe der stapel-Lockup. */
  .brand-logo--login { height: 2rem; }
}

/* A raised surface for grouping content - used sparingly, only where it
   communicates real hierarchy (per the CI's "don't decorate flatly" spirit). */
.card {
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 1.75rem;
}

/* Filter-Card vor einer Liste braucht sichtbaren Abstand zur Tabelle,
   sonst wirken beide Blöcke wie ein einziges verschmolzenes Element. */
.card + table,
.card + .table-scroll {
  margin-top: 1.5rem;
}

:focus-visible {
  outline: 2px solid var(--teccle-blau-75);
  outline-offset: 2px;
}

/* Thematic card grid for pages like Einstellungen - each section gets its
   own raised .card instead of being one long, undivided list. */
.settings-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
.settings-grid .card {
  flex: 1 1 320px;
}
.settings-grid .card h2 {
  margin-top: 0;
}
.settings-facts dt {
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--teccle-blau-75);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin-top: 0.7rem;
}
.settings-facts dt:first-child {
  margin-top: 0;
}
.settings-facts dd {
  margin: 0.15rem 0 0;
  color: var(--color-text);
}
.settings-hint {
  margin-top: 1rem;
  color: var(--teccle-blau-75);
}

/* Toggleable sidebar (fragments/sidebar.html). Closed by default, state
   persisted client-side (static/js/sidebar.js) since every navigation
   here is a real page load, not client-side routing. Overlaying +
   pushing the fixed top bars/content via margin, rather than a flex
   layout, so it doesn't require restructuring every page template. */
.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 220px;
  /*
   * Nutzerwunsch 2026-08-24: leichter Verlauf Richtung teccle-rot-100 zur
   * unteren rechten Ecke, Blau bleibt aber klar führend - bis 58% reines
   * teccle-blau-100, danach über ein gedecktes Navy-Lila zu einem
   * abgedunkelten Orangeton (nicht das reine teccle-rot-100, das wäre in
   * der Ecke zu laut und würde das Farbschema brechen).
   */
  background: linear-gradient(160deg, var(--teccle-blau-100) 0%, var(--teccle-blau-100) 58%, #170F55 72%, #4A2340 86%, #C6431F 100%);
  padding: 1.5rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  transform: translateX(-100%);
  transition: transform var(--transition);
  z-index: 100;
  overflow-y: auto;
}
html.sidebar-open .sidebar {
  transform: translateX(0);
}

/*
 * .sidebar-overlay (fragments/mandant-header.html, fragments/admin-bar.html) - halbtransparente
 * Blaeuflaeche, die bei geoeffneter Seitenleiste unterhalb 640px zwischen ihr und dem restlichen
 * Seiteninhalt liegt: z-index 90, also unter der Seitenleiste (100), aber ueber allem anderen.
 * Der Ausgangszustand hier ist nicht nur durchsichtig, sondern per opacity/visibility tatsaechlich
 * ausgeblendet - eine nur transparente, aber weiterhin sichtbare Flaeche wuerde jeden Klick der
 * gesamten Anwendung abfangen. Sichtbar wird sie ausschliesslich innerhalb der neuen 640px-
 * Medienabfrage weiter unten (html.sidebar-open .sidebar-overlay); oberhalb von 641px bleibt sie
 * dadurch konstruktionsbedingt immer ausgeblendet, und das Verschieben des Seiteninhalts (siehe
 * die 641px-Medienabfrage oben) ist dort weiterhin das einzige Verhalten.
 * Der Aussenklick zum Schliessen laeuft ausschliesslich ueber diese Flaeche (static/js/sidebar.js),
 * nicht ueber einen Klick-Listener auf Dokumentebene, der auch oberhalb von 641px feuern wuerde.
 */
.sidebar-overlay {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 90;
  background: rgba(0, 0, 90, 0.4);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition), visibility var(--transition);
  pointer-events: none;
}
.sidebar__link {
  color: var(--color-text-on-dark);
  text-decoration: none;
  padding: 0.6rem 1.5rem;
  font-weight: 600;
}
.sidebar__link:hover {
  background: var(--teccle-blau-75);
  color: var(--color-text-on-dark);
  text-decoration: none;
}
.sidebar__divider {
  border: none;
  border-top: 1px solid var(--teccle-blau-75);
  margin: 0.6rem 1.5rem;
}
.sidebar__group-label {
  padding: 0.6rem 1.5rem 0.2rem;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--teccle-blau-50);
}
.sidebar__link--sub {
  padding-left: 2.2rem;
}
.sidebar-toggle {
  background: none;
  border: none;
  box-shadow: none;
  color: inherit;
  font-size: 1.3rem;
  padding: 0.2rem 0.6rem;
  cursor: pointer;
}
.sidebar-toggle:hover {
  background: var(--teccle-grau-50);
  box-shadow: none;
}
.admin-bar .sidebar-toggle:hover {
  background: var(--teccle-blau-75);
}
@media (min-width: 641px) {
  /*
   * Shifting the whole body (rather than each visible chrome element
   * individually) means .content's own "margin: 0 auto" keeps centering
   * itself within the narrower remaining width instead of hugging the
   * sidebar with a lopsided gap on the far side - the sidebar (position:
   * fixed, 220px) still covers exactly the space this margin exposes.
   */
  html.sidebar-open body {
    margin-left: 220px;
    transition: margin-left var(--transition);
  }
}

/*
 * Mobiles Menue (FIXLIST-06, Phase 26 Plan 6). Bewusst kein neuer Breakpoint - 640px ist der in
 * dieser Datei bereits zweimal genutzte Wert (Logoverkleinerung oben, Tabellenumstellung weiter
 * unten). Macht die .sidebar-overlay-Flaeche sichtbar, sobald die Seitenleiste offen ist; die
 * Grundregel oben bleibt ausserhalb dieses Blocks tatsaechlich ausgeblendet.
 */
@media (max-width: 640px) {
  html.sidebar-open .sidebar-overlay {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }

  /*
   * Die Hamburger-Schaltflaeche bleibt auf jeder Breite bis zu dieser Medienabfrage in beiden
   * Kopfleisten sichtbar und bedienbar - der uebrige Kopfleisteninhalt weicht per Zeilenumbruch,
   * statt sie aus der Leiste zu draengen (UI-SPEC Punkt 6: "Hamburger icon stays visible"). Diese
   * Rangfolge stammt aus dem UI-Vertrag und ist nicht beliebig. Bewusst keine Flex-Grow-
   * Deklaration hier (der Konventionstest aus Plan 26-03 zaehlt deren Vorkommen exakt) - die
   * Schaltflaeche soll ohnehin nicht wachsen, sondern nur ihre eigene Groesse behalten.
   */
  .app-topbar,
  .admin-bar {
    flex-wrap: wrap;
  }
  .sidebar-toggle {
    flex-shrink: 0;
  }
  .app-topbar__user,
  .app-topbar__language,
  .admin-bar__user {
    flex-wrap: wrap;
  }
}

/* Persistent top bar (fragments/mandant-header.html) - always visible,
   independent of whether a Mandant/support-access banner is showing. */
.app-topbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.7rem 1.2rem;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}
.app-topbar__spacer {
  flex: 1;
}
.app-topbar__user {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  font-size: 0.9rem;
}
.logo-preview {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.logo-preview img {
  max-height: 60px;
  max-width: 200px;
  object-fit: contain;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.25rem;
  background: #fff;
}
.logo-preview p {
  margin: 0;
}
.mandant-logo-cell {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}
.mandant-logo-thumb {
  height: 28px;
  width: auto;
  max-width: 60px;
  object-fit: contain;
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 2px;
  background: #fff;
  flex: 0 0 auto;
}
.app-topbar__language {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}
.lang-flag {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  border: 1px solid transparent;
  border-radius: 4px;
  background: none;
  cursor: pointer;
  line-height: 0;
}
.lang-flag:hover:not(:disabled) {
  border-color: var(--color-border);
}
.lang-flag--active {
  border-color: var(--teccle-blau-100);
}
.lang-flag:disabled {
  cursor: default;
}
.role-badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  background: var(--teccle-blau-10);
  color: var(--teccle-blau-100);
}
.admin-bar .role-badge {
  background: var(--teccle-gelb-100);
  color: var(--teccle-blau-100);
}

/* Header bar (fragments/mandant-header.html) */
.app-banner {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.6rem 1.2rem;
}
.app-banner--support {
  background: var(--color-warning-bg);
  border-bottom: 1px solid var(--color-warning-border);
}
.app-banner--mandant {
  background: var(--teccle-blau-10);
  margin-bottom: 1.5rem;
}
.app-banner select {
  font-family: var(--font-body);
}
.app-banner .app-banner__spacer {
  margin-left: auto;
  font-weight: 600;
}

.top-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}

/* Buttons */
button, .btn {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--teccle-blau-100);
  background: var(--teccle-blau-100);
  color: var(--color-text-on-dark);
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background var(--transition), transform var(--transition), box-shadow var(--transition);
}
.btn:hover {
  color: var(--color-text-on-dark);
}
button:hover, .btn:hover {
  background: #000048;
  box-shadow: var(--shadow-md);
}
button:active, .btn:active {
  transform: scale(0.98);
  box-shadow: none;
}
.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
}
.btn-secondary:hover {
  background: var(--teccle-grau-50);
  /* Plan 46-05 (A-15): .btn:hover setzt weisse Schrift fuer den dunklen Grund; hier bleibt er hell. */
  color: var(--color-text);
}

/*
 * A second, still-important action next to a page's primary .btn (e.g.
 * "Importieren" beside "Neue Rechnung") - per feedback, plain .btn-secondary
 * (white fill) read as too unassuming/washed-out for something that's a
 * real primary action in its own right, not a minor "Filtern"/"Abmelden".
 * A tinted fill gives it real visual presence without fully tying with
 * the page's one true primary action (still filled navy).
 */
.btn-tinted {
  background: var(--color-bg-products);
  color: var(--teccle-blau-100);
}
.btn-tinted:hover {
  background: var(--teccle-blau-50);
  color: var(--teccle-blau-100);
}

/*
 * A "Löschen" action that sits below a form's primary Speichern button
 * used to be a same-size, same-weight .btn-secondary - reading as a
 * second, equally valid choice instead of a rare, destructive one. This
 * pares it down to a quiet text-style action (no fill, no border, no
 * shadow) and only hints at "danger" on hover, plus .danger-zone adds a
 * visible gap + divider so it doesn't sit right under Speichern as if
 * the two were a matched pair.
 */
.danger-zone {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--color-border);
}
.btn-subtle {
  background: none;
  border: none;
  box-shadow: none;
  color: var(--teccle-blau-75);
  font-weight: 400;
  font-size: 0.9rem;
  padding: 0.3rem 0.2rem;
}
.btn-subtle:hover {
  background: none;
  box-shadow: none;
  color: var(--color-error-text);
  text-decoration: underline;
}
.btn-subtle:active {
  transform: none;
}
.btn-subtle--disabled,
.btn-subtle--disabled:hover {
  color: var(--teccle-blau-50);
  cursor: not-allowed;
  text-decoration: none;
}
.logo-remove-btn {
  margin-left: auto;
  white-space: nowrap;
}
.top-bar__actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* Phase 37 Plan 01: Filterzeile ueber einer Liste (z.B. "Uebernommene Dokumente anzeigen"). */
.filter-bar {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1rem;
}
.filter-bar label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/*
 * Icon-only row actions (edit/delete in table rows) - per feedback, tables
 * should use an icon with a tooltip instead of a text link/button for
 * non-contextual actions ("Bearbeiten", "Löschen"), reserving text links
 * for genuinely contextual ones (e.g. an invoice number linking to itself).
 * Uses currentColor (see fragments/icons.html) so this is the only place
 * that sets color.
 */
.row-actions {
  display: flex;
  align-items: center;
  gap: 0.2rem;
}
/* Plan 46-04 (P-38, A-10): An einem <td> bleibt die Zelle eine Tabellenzelle - mit display:flex
   verliesse sie das Tabellenlayout und wuchs nicht mit der Zeilenhoehe (Versatz in zweizeiligen
   Zeilen). Die Kinder stehen nebeneinander; Abstand ueber margin, weil gap nur im Flex-Layout gilt.
   Die mobile Kartenansicht (.responsive-table td.row-actions, weiter unten) ist spezifischer und
   gewinnt unabhaengig von der Reihenfolge; das div.row-actions bleibt Flex. */
td.row-actions {
  display: table-cell;
  white-space: nowrap;
}
td.row-actions > * {
  vertical-align: middle;
}
td.row-actions > form {
  display: inline-block;
  margin: 0;
}
td.row-actions > * + * {
  margin-left: 0.2rem;
}
.icon-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  box-shadow: none;
  color: var(--teccle-blau-75);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}
.icon-action:hover {
  background: var(--teccle-blau-10);
  color: var(--color-text);
  box-shadow: none;
}
.icon-action--danger:hover {
  background: var(--color-error-bg);
  color: var(--color-error-text);
}
.icon-action:active {
  transform: none;
}
.icon-action--disabled,
.icon-action--disabled:hover {
  color: var(--teccle-blau-50);
  background: none;
  cursor: not-allowed;
}

/*
 * Full-size (non-icon-only) button with a leading icon, e.g. the "Aktuelle
 * Version herunterladen"-Button auf der Rechnungsdetailseite (Nutzerwunsch
 * 2026-08-24) - button/.btn is display:inline-block by default, das reicht
 * für Icon+Text nebeneinander nicht.
 */
.btn-icon {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.btn-icon--disabled,
.btn-icon--disabled:hover {
  background: var(--color-surface);
  color: var(--teccle-blau-50);
  cursor: not-allowed;
  box-shadow: none;
}

/*
 * Rechnungsformular (fragments/rechnung-formfields.html): the optional
 * EN16931 fields (references, Rabatte/Zuschläge, per-line delivery
 * date/notes) stay collapsed by default per Kunde (see Kunde.
 * showExtendedInvoiceFields) - toggling the <details> also reveals the
 * matching extra line-item columns via rechnung-erweiterte-angaben.js.
 */
.erweiterte-angaben summary {
  cursor: pointer;
  font-family: var(--font-heading);
  font-weight: 600;
  margin: 1.5rem 0 0.5rem;
}

/*
 * Kunde-Rückfrage-Hinweis (Nutzererweiterung 2026-08-25, fragments/rechnung-formfields.html):
 * bewusst KEIN .app-banner - das ist für die seitenweite Kopfleiste gedacht (volle Breite, große
 * Warnfarbe) und wirkte hier "auf Kopfebene eines Belegs" platziert, obwohl es inhaltlich zur
 * Kunde-Feldgruppe gehört (Nutzer-Feedback 2026-08-25). Sitzt daher direkt in der Fieldset, normale
 * Button-/Textgröße passend zu den Feldlabels statt der großen Banner-Optik.
 */
.kunde-resolution-hint {
  background: var(--color-warning-bg);
  border: 1px solid var(--color-warning-border);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.8rem;
  margin-bottom: 1rem;
}
.kunde-resolution-hint p {
  margin: 0 0 0.5rem;
  font-size: 0.9rem;
}
.kunde-resolution-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.kunde-resolution-actions button {
  margin-top: 0;
  padding: 0.4rem 0.8rem;
  font-size: 0.85rem;
}

/*
 * Positionstabelle (Nutzerwunsch 2026-08-24): table-layout:fixed mit expliziten <col>-Breiten
 * statt prozentualer/inhaltsabhängiger Spaltenbreiten - so bleiben die immer sichtbaren Spalten
 * (Beschreibung, Menge, ...) in "normaler" und "erweiterter" Ansicht PIXELGLEICH breit, nur die
 * beiden zusätzlichen Spalten (Leistungsdatum, Positions-Anmerkung) kommen dazu, statt dass sich
 * beim Auf-/Zuklappen alle Spalten neu verteilen. visibility:collapse auf <col> statt
 * display:none auf jede einzelne <td> - das ist der dafür vorgesehene CSS-Tabellen-Mechanismus:
 * eine kollabierte Spalte nimmt keinen Platz ein und verschiebt die übrigen Spaltenbreiten nicht,
 * ohne dass jede Zeile ihre extended-Zellen einzeln behandeln muss. .table-scroll fängt ab, falls
 * die Tabelle in der erweiterten Ansicht auf schmalen Viewports trotzdem breiter als der
 * verfügbare Platz wird - Layout "sprengen" (Nutzerformulierung) soll sie dabei nicht.
 */
.table-scroll {
  overflow-x: auto;
  margin-top: 1rem;
  /* Sichtbarer, duenner Scrollbalken statt des vom System automatisch ausgeblendeten -
     Nutzerfeedback 2026-09-15: auf schmalen Viewports war nicht erkennbar, dass eine Tabelle
     ueberhaupt horizontal weitergeht. Wirkt auf Firefox/Chrome/Edge; iOS Safari zeigt trotzdem nur
     einen Overlay-Balken waehrend des Wischens selbst - siehe die Randschatten-Regeln unten und
     table-scroll.js fuer die plattformuebergreifende Ergaenzung. */
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
  transition: box-shadow 0.15s ease;
}
.table-scroll::-webkit-scrollbar {
  height: 8px;
}
.table-scroll::-webkit-scrollbar-track {
  background: transparent;
}
.table-scroll::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 4px;
}

/*
 * Randschatten (Nutzerfeedback 2026-09-15, Ergaenzung zum Scrollbalken oben): table-scroll.js
 * setzt has-scroll-left/-right, sobald in die jeweilige Richtung noch ungesehener Inhalt folgt.
 * inset box-shadow statt eines zusaetzlichen Kind-Elements: er gehoert zur Box von .table-scroll
 * selbst, nicht zu ihrem gescrollten Inhalt, und bleibt deshalb unabhaengig von der Scroll-Position
 * immer exakt am Rand sichtbar - anders als ein Kind-Element mit position:absolute, das mit dem
 * Inhalt mitgescrollt haette. Ohne table-scroll.js bleiben beide Klassen aus, kein Schatten -
 * dasselbe Rueckfallverhalten wie bei hover-card-enhanced weiter unten.
 */
.table-scroll.has-scroll-left {
  box-shadow: inset 12px 0 12px -12px rgba(0, 0, 0, 0.3);
}
.table-scroll.has-scroll-right {
  box-shadow: inset -12px 0 12px -12px rgba(0, 0, 0, 0.3);
}
.table-scroll.has-scroll-left.has-scroll-right {
  box-shadow: inset 12px 0 12px -12px rgba(0, 0, 0, 0.3), inset -12px 0 12px -12px rgba(0, 0, 0, 0.3);
}

/*
 * Vertikaler Overflow (FIXLIST-02, Phase 26 Plan 5): .table-scroll setzte hier lange nur
 * overflow-x: auto. Laut CSS-Overflow-Spezifikation stuft der Browser dann automatisch auch
 * die Y-Achse auf auto hoch - und der .hover-card-Popover einer Zeile (siehe die
 * .hover-card-Familie weiter unten) zaehlt trotz opacity:0/visibility:hidden zum scrollbaren
 * Ueberlauf, was eine ueberfluessige vertikale Scrollleiste erzeugte. Ein simples
 * overflow-y: hidden/clip direkt auf der Basisregel oben wuerde die Scrollleiste zwar
 * entfernen, aber die Karte im selben Zug abschneiden - genau das vermeidet der Kommentar
 * ueber der table-Regel weiter unten ausdruecklich. Die Loesung steht deshalb NICHT in der
 * Basisregel, sondern hier: hover-card.js loest die geoeffnete Karte per position:fixed aus
 * dieser Box heraus, bevor die Y-Achse ueberhaupt geschlossen wird (siehe hover-card.js und
 * den Kommentar an der .hover-card-Familie unten). Nur wenn das Skript nachweislich lief -
 * erkennbar an der Markierungsklasse hover-card-enhanced auf <html> - wird die Y-Achse hier
 * geschlossen; ohne die Klasse bleibt sie offen und nichts wird abgeschnitten.
 */
html.hover-card-enhanced .table-scroll {
  overflow-y: clip;
  overflow-clip-margin: 0.5rem;
}
.line-items-table {
  /* table-layout:fixed mit den <col>-Breiten unten wird nur zuverlässig respektiert, wenn die
     Tabelle selbst eine explizite (nicht auto-)Breite hat - sonst fallen manche Browser bei
     Formularelementen (<select> etc.) in den Zellen auf eine inhaltsabhängige Breite zurück und
     die schön geplanten Spaltenbreiten brechen zusammen. width:100% statt fixer rem-Breite (Nutzer-
     Nachtrag 2026-08-24: die Tabelle füllte auf breiten Viewports nicht den verfügbaren Platz) -
     col-description bekommt bewusst KEINE explizite Breite (siehe unten) und wirkt dadurch als
     einzige "wachsende" Spalte, alle anderen Spalten bleiben exakt so breit wie unten angegeben.
     min-width sichert die Summe der fixen Spalten ab, damit bei schmalen Viewports .table-scroll
     scrollt statt die Spalten zu stauchen. */
  table-layout: fixed;
  width: 100%;
  min-width: 55rem;
}
.line-items-table.extended-columns-visible {
  min-width: 73rem;
}
.line-items-table .col-description { /* keine feste Breite - siehe Kommentar oben, wächst mit der Tabelle */ }
.line-items-table .col-quantity { width: 4.5rem; }
.line-items-table .col-unit { width: 7rem; }
.line-items-table .col-price { width: 7rem; }
.line-items-table .col-taxrate { width: 5rem; }
.line-items-table .col-taxcategory { width: 9rem; }
.line-items-table .col-delivery { width: 8rem; }
.line-items-table .col-notes { width: 10rem; }
.line-items-table .col-actions { width: 2.5rem; }
.line-items-table col.extended-column {
  visibility: collapse;
}
.line-items-table.extended-columns-visible col.extended-column {
  visibility: visible;
}
/*
 * Nutzerwunsch 2026-08-24: <select> in einer Positionszeile (Einheit, USt-Kategorie) hatte bisher
 * keine Breitenbeschränkung - nur input/textarea bekamen width:100% (jeweils lokal in
 * rechnung-form.html/rechnung-detail.html). Ein <select> rendert ohne width-Vorgabe in seiner
 * inhaltsabhängigen Breite (bei langen Optionstexten wie "AE – Reverse-Charge (...)" deutlich
 * breiter als die fixe Spalte), wodurch es sichtbar in die Nachbarspalte hineinragte - besonders
 * auffällig bei schmalem Viewport, sobald die Positionstabelle horizontal gescrollt werden muss.
 * table-layout:fixed allein verhindert das nicht, da überstehender Zellinhalt standardmäßig nicht
 * abgeschnitten wird (kein overflow:hidden auf Tabellenzellen, bewusst so - siehe oben).
 */
.line-items-table td select,
.line-items-table td .code-select-custom {
  width: 100%;
  min-width: 0;
}

/*
 * Responsive-Tabellen-Konvention (Nutzeranforderung 2026-08-25): "class=responsive-table" auf
 * eine <table> geben, dazu pro <td> ein th:attr="data-label=#{...}" mit der Spaltenüberschrift -
 * unter 640px wird die Tabelle automatisch zu einer Liste aus Karten (eine pro Zeile, Feldlabel
 * über jedem Wert statt Spaltenkopf), damit sich schmale Felder (Selects, Datumsfelder, kurze
 * Inputs) nie mit ihrer Nachbarspalte überlappen können - das eigentliche Problem war vorher NICHT
 * behebbar, weil eine Tabellenzeile bei table-layout:fixed unterhalb einer Mindestbreite pro Spalte
 * schlicht keinen Platz mehr hat, egal wie die einzelnen Felder gestylt sind. Diese Klasse ist der
 * Standard-Weg für JEDE Tabelle mit schmalen Formularfeldern in dieser Applikation, nicht nur für
 * die Positionstabelle - bei künftigen neuen Formular-Tabellen bitte übernehmen statt neu zu
 * erfinden. Reine Anzeige-Tabellen (nur Text/Icons, keine Formularfelder) sind von dem Problem
 * i.d.R. nicht betroffen und brauchen die Klasse nicht zwingend, können sie aber genauso nutzen.
 */
@media (max-width: 640px) {
  .responsive-table,
  .responsive-table thead,
  .responsive-table tbody,
  .responsive-table th,
  .responsive-table td,
  .responsive-table tr {
    display: block;
  }
  .responsive-table.line-items-table,
  .responsive-table.line-items-table.extended-columns-visible {
    width: auto;
    min-width: 0;
  }
  .responsive-table thead tr {
    position: absolute;
    top: -9999px;
    left: -9999px;
  }
  .responsive-table tbody tr {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: 0.6rem 0.7rem;
    margin-bottom: 0.75rem;
  }
  .responsive-table td {
    border: none;
    padding: 0.3rem 0;
  }
  .responsive-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-weight: 600;
    font-size: 0.8rem;
    color: var(--teccle-blau-75);
    margin-bottom: 0.15rem;
  }
  .responsive-table td select,
  .responsive-table td input,
  .responsive-table td textarea {
    width: 100%;
    min-width: 0;
  }
  .responsive-table td.row-actions {
    display: flex;
    justify-content: flex-end;
    padding-top: 0.4rem;
  }
  /* Die erweiterten Positions-Spalten (Leistungsdatum/Notizen) werden normalerweise über
     visibility:collapse auf <col> ein-/ausgeblendet (siehe .extended-column oben) - das greift bei
     display:block (Karten-Layout) nicht mehr, da <col>/<colgroup> dann keine Wirkung mehr hat, also
     hier direkt auf den <td>/<th> gespiegelt. */
  .line-items-table.responsive-table td.extended-column,
  .line-items-table.responsive-table th.extended-column {
    display: none;
  }
  .line-items-table.responsive-table.extended-columns-visible td.extended-column,
  .line-items-table.responsive-table.extended-columns-visible th.extended-column {
    display: block;
  }
  /* Im Kartenlayout ist wieder Platz fuer den vollen Text neben dem Feldlabel - siehe
     .origin-badge--compact oben. */
  .origin-badge--compact .visually-hidden {
    position: static;
    width: auto;
    height: auto;
    margin: 0 0 0 0.2rem;
    overflow: visible;
    clip: auto;
    white-space: nowrap;
  }
}
/*
 * Nutzer-Nachtrag 2026-08-24: Leistungsdatum (col-delivery, 8rem) und Positions-Anmerkung
 * überlappten sich bei schmalem Viewport bzw. wenn die Positionstabelle horizontal gescrollt
 * werden musste. Ursache: die globale input[type="date"]-Regel (min-width:11rem, siehe unten)
 * erzwang für JEDES Datumsfeld mindestens 11rem Breite - auch für das Leistungsdatum in seiner
 * nur 8rem breiten Spalte, wodurch das Eingabefeld sichtbar in die Notizen-Spalte danach hineinragte.
 * Hier gezielt überschrieben, damit sich das Feld an die Spaltenbreite hält wie select/input[text].
 */
.line-items-table td input[type="date"] {
  width: 100%;
  min-width: 0;
}

/*
 * Code dropdowns with a "Sonstige (manuell)" fallback (Phase 13 Punkt 21,
 * see static/js/code-select.js): the free-text input stays hidden until
 * "Sonstige" is picked in the paired select.
 */
.code-select-custom {
  display: none;
  margin-top: 0.35rem;
}
.code-select-custom.visible {
  display: block;
}

/*
 * Bezugsdokument-Feldgruppe (BG-3, Phase 27, static/js/rechnung-belegtyp.js):
 * nur bei Gutschrift/Rechnungskorrektur sichtbar, sonst bleibt sie im DOM
 * (Formular-Rücksprung nach Validierungsfehler behält den Wert), aber ausgeblendet.
 * Dieselbe Mechanik tragen seit Plan 28-12 Task 2 die Zahlungsgruppen BG-19/BG-18
 * (rechnung-zahlungsart.js) - deshalb dieselbe Regel statt einer zweiten Kopie.
 */
.field-row.preceding-invoice-fields,
.field-row.payment-group-fields {
  display: none;
}
.field-row.preceding-invoice-fields.visible,
.field-row.payment-group-fields.visible {
  display: flex;
}

/* Forms */
form {
  font-family: var(--font-body);
}
label {
  font-weight: 600;
  color: var(--color-text);
}
input, select, textarea {
  font-family: var(--font-body);
  padding: 0.5rem 0.6rem;
  font-size: 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  background: var(--color-surface);
  transition: border-color var(--transition), box-shadow var(--transition);
}
input:focus, select:focus, textarea:focus {
  border-color: var(--teccle-blau-75);
  box-shadow: 0 0 0 3px var(--teccle-blau-10);
  outline: none;
}
/*
 * Phase 13 Punkt 19: the three editable date fields (RechnungForm.issueDate/
 * dueDate, LineItemForm.deliveryDate) rely entirely on the browser's native
 * <input type="date"> picker - no JS enhancement layer. Without an explicit
 * width, Chrome renders it noticeably narrower than Firefox/Edge; this just
 * keeps it legible and consistent with the other fields it sits next to,
 * it doesn't touch the native picker/icon itself (not stylable cross-browser).
 */
input[type="date"] {
  min-width: 11rem;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 0.9rem;
}

/*
 * Field-row layout for forms grouped into fieldsets with several fields
 * per line (e.g. kunde-form.html) - .field-row lays its .field children
 * out with widths tailored to what they actually hold (a postal code
 * doesn't need as much room as a street), instead of every field
 * stacking full-width regardless of content.
 */
.field-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.field-row .field {
  flex: 1 1 200px;
  margin-bottom: 0;
}
.field-row .field--narrow {
  flex: 0 1 120px;
}
.field-row .field--wide {
  flex-basis: 100%;
}

/* Fieldsets - no rule existed before, so every form fell back to the
   browser's unstyled default (bare border, no legend width control),
   which is what made long legends (e.g. "Lizenz-Zugangsdaten (aus der
   Management-App)") wrap awkwardly against the form's narrow max-width. */
fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 1rem 1.25rem 1.25rem;
  margin: 1.25rem 0 0;
}
legend {
  padding: 0 0.4rem;
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--color-text);
}

/*
 * Tables. No "overflow: hidden" here on purpose - it used to clip the
 * table to its own rounded corners, but that also clips anything a row
 * positions outside the table's box (the hover-card popovers below rely
 * on escaping it), so the four corners are rounded individually instead.
 */
table {
  border-collapse: collapse;
  width: 100%;
  background: var(--color-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
thead tr:first-child th:first-child {
  border-top-left-radius: var(--radius);
}
thead tr:first-child th:last-child {
  border-top-right-radius: var(--radius);
}
tbody tr:last-child td:first-child {
  border-bottom-left-radius: var(--radius);
}
tbody tr:last-child td:last-child {
  border-bottom-right-radius: var(--radius);
}
th, td {
  text-align: left;
  padding: 0.65rem 0.9rem;
  border-bottom: 1px solid var(--color-border);
}
/* Geldbeträge in Tabellen und Detailkarten rechtsbündig darstellen. */
th.text-right, td.text-right, dd.text-right {
  text-align: right;
}
.history-icon, .format-icon {
  display: inline-flex;
  vertical-align: middle;
  margin-left: 0.35rem;
  color: var(--color-text);
  opacity: 0.6;
}
/* Info-Icon neben Pflichtfeld-Labels - title-Attribut traegt die BT-Referenz + Kurzbeschreibung,
   erscheint als nativer Browser-Tooltip bei Mouseover/Fokus, kein eigener CSS-Mechanismus noetig.
   Liegt bewusst INNERHALB des <label>, damit es im selben Flex-Item bleibt statt als eigener
   Flex-Child von .field in eine neue Zeile umzubrechen. */
label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}
.field-info {
  display: inline-flex;
  color: var(--color-text);
  opacity: 0.55;
  cursor: help;
  flex: 0 0 auto;
}
.field-info:hover, .field-info:focus {
  opacity: 1;
}
label sup {
  font-weight: 400;
}
/* Fussnoten-Erklaerung zu den <sup>-Markierungen an XRechnung-spezifischen Pflichtfeldern. */
.field-footnote {
  font-size: 0.85rem;
  color: var(--color-text);
  opacity: 0.75;
  margin-top: 0.75rem;
}
th {
  font-family: var(--font-heading);
  font-weight: 600;
  background: var(--teccle-grau-50);
}
tbody tr:hover {
  background: var(--teccle-blau-10);
}

/*
 * Hover-card: a structured detail popover for a list row's primary link
 * (Kunde/Rechnung/Mandant/Lizenznehmer name), so a quick overview doesn't
 * require navigating to a full detail page. Showing/hiding stays pure CSS
 * (:hover/:focus-within on the wrapping .hover-card-trigger span) - no JS
 * needed for that, and :focus-within makes it reachable via keyboard, not
 * just a mouse.
 *
 * Positioning is a different story (FIXLIST-02, Phase 26 Plan 5): hover-card.js
 * switches an opened card from this rule's position: absolute to position: fixed,
 * computed from the trigger's getBoundingClientRect(), lifting it out of
 * .table-scroll's clipping box entirely - that is what allows the conditional
 * y-axis clip on .table-scroll above without cutting the card off. If the
 * script fails to load or is blocked, the card simply keeps this rule's
 * position: absolute - and .table-scroll's overflow-y then also stays open (see
 * the hover-card-enhanced marker class comment above), so nothing gets clipped
 * either way.
 */
.hover-card-trigger {
  position: relative;
  display: inline-block;
}
.hover-card {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 60;
  margin-top: 0.5rem;
  min-width: 260px;
  max-width: 340px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 0.9rem 1.1rem;
  font-size: 0.85rem;
  font-weight: 400;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
  pointer-events: none;
}
.hover-card-trigger:hover .hover-card,
.hover-card-trigger:focus-within .hover-card {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
}
.hover-card dt {
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--teccle-blau-75);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin-top: 0.7rem;
}
.hover-card dt:first-child {
  margin-top: 0;
}
.hover-card dd {
  margin: 0.15rem 0 0;
  color: var(--color-text);
}
.hover-card__empty {
  color: var(--teccle-blau-75);
  font-style: italic;
}

/* Status banners / inline messages */
.banner, .error {
  border-radius: 4px;
  padding: 0.6rem 0.9rem;
  font-size: 0.9rem;
}
.error {
  color: var(--color-error-text);
  background: var(--color-error-bg);
  border: 1px solid var(--color-error-border);
}
.success {
  color: var(--color-success-text);
  background: var(--color-success-bg);
}
.banner--warning {
  background: var(--color-warning-bg);
  border: 1px solid var(--color-warning-border);
  color: var(--color-text);
}

/* Inline status labels (import preview/result, etc.) */
.status-ok, .status-created { color: var(--color-success-text); font-weight: 600; }
.status-warn, .status-skipped { color: var(--color-warning-text); font-weight: 600; }
.status-error, .status-failed, .row-errors { color: var(--color-error-text); font-weight: 600; }
.row-errors { font-weight: 400; font-size: 0.85rem; }

/* Kunde-Statusflag (aktiv/gesperrt) - clickable badge that toggles the status */
.status-toggle { display: inline; }
.status-badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  border: none;
  cursor: pointer;
}
.status-badge--aktiv {
  color: var(--color-success-text);
  background: var(--color-success-bg);
}
.status-badge--gesperrt {
  color: var(--color-error-text);
  background: var(--color-error-bg);
}
.status-badge--bearbeitet {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
  cursor: help;
}

/* Rechnungsstatus-Spalte (Entwurf/Unvollständig/Erzeugt) - dieselbe Farblogik wie
   Aktiv/Gesperrt/Bearbeitet oben, nur mit eigenen Klassennamen für die eigene Bedeutung. */
.status-badge--erzeugt {
  color: var(--color-success-text);
  background: var(--color-success-bg);
  cursor: default;
}
.status-badge--entwurf {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
  cursor: default;
}
.status-badge--unvollstaendig {
  color: var(--color-error-text);
  background: var(--color-error-bg);
  cursor: default;
}

/* Versandkennzeichen (Plan 30-01, D-13/D-14) - eigenes Merkmal neben dem Rechnungsstatus, kein
   vierter Statuswert. Warnfarbe, wenn versendet wurde, aber nicht die aktuelle Version - genau die
   Unterscheidung, die die Warnung bei einer Neugenerierung nach Versand braucht (D-07). */
.status-badge--versendet {
  color: var(--color-success-text);
  background: var(--color-success-bg);
  cursor: help;
}
.status-badge--versendet-veraltet {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
  cursor: help;
}

/* ELO-Ablagezustand (Plan 31-06 Task 1) - eigenes Merkmal neben Status/Versand, kein vierter
   Statuswert. ABGELEGT ist die Fundstelle im Archiv (Erfolg), AUSSTEHEND/IN_ARBEIT ist neutral im
   Ablauf, FEHLGESCHLAGEN ist der einzige Zustand, der ein Eingreifen verlangt (kein Endzustand). */
.status-badge--elo-abgelegt {
  color: var(--color-success-text);
  background: var(--color-success-bg);
  cursor: help;
}
.status-badge--elo-ausstehend {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
  cursor: help;
}
.status-badge--elo-fehlgeschlagen {
  color: var(--color-error-text);
  background: var(--color-error-bg);
  cursor: help;
}

/* Stapel und Einzelbelege aus einem Stapel (Plan 46-03, K2-9). BEREIT wartet auf die Uebergabe an
   DXR (Warnfarbe, wie "Entwurf": es ist etwas zu tun); GETRENNT ist das gute Ende, NICHT_TRENNBAR
   und FEHLGESCHLAGEN verlangen ein Eingreifen. --fehlgeschlagen gilt zugleich fuer Vorgaenge im
   Status FEHLGESCHLAGEN, deren Badge bisher keine eigene Farbe hatte. */
.status-badge--bereit,
.status-badge--in-trennung {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
  cursor: default;
}
.status-badge--getrennt {
  color: var(--color-success-text);
  background: var(--color-success-bg);
  cursor: default;
}
.status-badge--nicht-trennbar,
.status-badge--fehlgeschlagen,
.status-badge--zeitueberschreitung {
  color: var(--color-error-text);
  background: var(--color-error-bg);
  cursor: default;
}
/* Plan 46-05 (A-14): die uebrigen Werte von PdfExtraktionStatus. Wartendes in Warnfarbe, "Uebernommen"
   als ruhiges Ende ohne Signalfarbe. Der Klassenname ist der Statusname klein, "_" zu "-" (wie das Skript). */
.status-badge--hochgeladen,
.status-badge--in-extraktion,
.status-badge--ergebnis-vorhanden {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
  cursor: default;
}
.status-badge--uebernommen {
  color: var(--color-text);
  background: var(--color-surface-muted);
  cursor: default;
}
/*
 * Herkunftsmarkierung je Feld im Beleg-Formular (Phase 28, D-13). Sitzt IM <label> neben dem
 * Feldnamen - dieselbe Konvention wie das (i)-Icon: als Geschwister-Element ausserhalb des Labels
 * bricht es auf eine eigene Zeile um.
 *
 * Bewusst mit Symbol UND Text, nicht nur farblich unterschieden: in Graustufen und fuer
 * farbfehlsichtige Nutzer muss "aus PDF uebernommen" von "zu pruefen" unterscheidbar bleiben.
 * Farben sind dieselben Zustandsfarben wie bei den vorhandenen Status-Badges, keine neue Farbwelt.
 */
.origin-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  margin-left: 0.35rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  line-height: 1.4;
  vertical-align: middle;
  white-space: nowrap;
}
.origin-badge--belegt {
  color: var(--color-success-text);
  background: var(--color-success-bg);
}
.origin-badge--nicht_belegt {
  color: var(--color-warning-text);
  background: var(--color-warning-bg);
}
/*
 * Kompakte Variante fuer die Positionstabelle (Phase 28, Task 2): die Spalten sind zu schmal fuer
 * den vollen Text ("aus PDF" / "zu pruefen") neben Menge, Einheit, Steuersatz & Co. - hier nur das
 * Symbol sichtbar, der Text bleibt fuer Screenreader/Tooltip erhalten (.visually-hidden), damit D-13
 * (nicht nur Farbe) weiter erfuellt ist. Unter 640px (Kartenlayout) ist wieder Platz - dort blendet
 * der responsive-table-Block unten den Text neben dem Feldlabel wieder ein.
 */
.origin-badge--compact {
  padding: 0.1rem 0.3rem;
}
/*
 * Projektweite Hilfsklasse fuer nur-Screenreader-Text (heute nur hier verwendet, bei Bedarf
 * andernorts wiederverwenden statt neu zu erfinden) - Inhalt bleibt fuer Screenreader und den Text-
 * Kopiervorgang erreichbar, nimmt aber visuell keinen Platz ein.
 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Kopfbereich der Pruefansicht - alle Befunde, bevor der Nutzer uebernimmt. */
.review-summary {
  margin-bottom: 1.5rem;
}
.review-summary .banner,
.review-summary .error {
  margin-bottom: 0.8rem;
}
.review-summary ul {
  margin: 0.3rem 0 0;
  padding-left: 1.2rem;
}

.kunde-gesperrt-hinweis {
  font-style: italic;
  color: var(--color-error-text);
}

/*
 * Formatauswahl im Beleg-Formular (Phase 32, Plan 32-03). Die Optionen tragen seit dieser Phase den
 * vollen Anzeigenamen samt Version ("ZUGFeRD 2.5.2 (Factur-X 1.09.2), Profil EN 16931 – PDF +
 * eingebettetes XML"). Ein <select> hat die Breite seiner längsten Option als Mindestbreite, und ein
 * Flex-Element darf per Default (min-width:auto) nicht darunter schrumpfen - die ganze Zeile
 * "Abwicklung" wurde dadurch bei 375px breiter als der Bildschirm (im Checkpoint dieses Plans
 * gemessen: scrollWidth 703 bei clientWidth 375). min-width:0 gibt das Schrumpfen frei; der Browser
 * kürzt den sichtbaren Text dann selbst, ohne dass die Auswahl etwas verliert.
 */
.field--format {
  min-width: 0;
}
.field--format select {
  min-width: 0;
  width: 100%;
}

/*
 * Stand der Formatliste (Phase 32, Plan 32-03): erscheint nur, wenn die Liste NICHT aus einem
 * Abruf dieser Laufzeit stammt. Bewusst kein Banner und keine Fehlerfarbe - der Beleg laesst sich
 * trotzdem erfassen, und die Liste ist mit hoher Wahrscheinlichkeit richtig; falsch waere nur,
 * ihr Alter zu verschweigen. Sitzt direkt unter der Auswahl, damit der Bezug eindeutig ist, und
 * bricht in der schmalen Ansicht mit dem Feld um, statt es zu verbreitern.
 */
.format-stand-hinweis {
  margin: 0.35rem 0 0;
  font-size: 0.8rem;
  line-height: 1.35;
  color: var(--color-warning-text);
}

/*
 * SYSTEMADMIN admin area. Used to flip the entire page to a dark navy
 * theme, which meant clicking any admin link in the sidebar made the
 * whole screen jump from the light dashboard to dark with no visual
 * continuity. The admin area now shares the normal light theme (body's
 * default background/text/table/card/button rules apply unchanged) -
 * only the top .admin-bar strip keeps a distinct navy accent, the same
 * role .admin-bar plays as .app-topbar's counterpart on regular pages,
 * so "you're in Systemadministration" is still visible at a glance
 * without recoloring the whole page.
 *
 * .admin-shell used to carry its own min-height: 100vh here (its Sticky-
 * Footer-Sonderfall vor FIXLIST-03) - das ist inzwischen redundant, weil
 * body selbst die Mindesthoehe traegt (siehe Sticky-Footer-Mechanismus-
 * Kommentar bei body oben) und .admin-shell genau diese Body-Klasse ist.
 */
.admin-bar {
  background: var(--teccle-blau-100);
  color: var(--color-text-on-dark);
  padding: 0.6rem 1.2rem;
  font-family: var(--font-heading);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}
.admin-bar a {
  color: var(--color-text-on-dark);
}
.admin-bar__user {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  font-weight: 400;
  font-family: var(--font-body);
}
.admin-bar .btn-secondary {
  background: transparent;
  border-color: var(--teccle-blau-75);
  color: var(--color-text-on-dark);
}
.admin-bar .btn-secondary:hover {
  background: var(--teccle-blau-75);
}

/*
 * Soft page-to-page transition (Phase 21 Punkt 2, Nutzerentscheidung: CSS View
 * Transitions API statt AJAX-Partial-Reload) - every navigation here is a full
 * server round-trip (Thymeleaf, kein SPA), das macht jeden Menüklick zu einem
 * kompletten Dokumentwechsel ohne jedes Übergangs-Handling ("Rucker"). Chrome/
 * Edge unterstützen cross-document View Transitions nativ über die @view-transition
 * Regel; Firefox/Safari ignorieren sie ersatzlos (kein Fallback-Code nötig, nur
 * dort keine Animation). app-topbar/admin-bar/sidebar bekommen einen eigenen
 * view-transition-name, damit sie NICHT im Root-Crossfade mitblenden (sie ändern
 * sich zwischen zwei Seiten ohnehin nicht) und visuell stabil stehen bleiben -
 * nur .content blendet über.
 */
@view-transition {
  navigation: auto;
}
.app-topbar {
  view-transition-name: app-topbar;
}
.admin-bar {
  view-transition-name: admin-bar;
}
.sidebar {
  view-transition-name: sidebar;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 180ms;
  animation-timing-function: ease-out;
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/*
 * Phase 14 - rechtlich nötiger Footer, auf jeder Seite. Dezent, keine eigene Farbfläche.
 *
 * margin-top: 2rem bleibt unveraendert und ist mit dem Sticky-Footer-Mechanismus
 * (siehe body-Kommentar oben) vertraeglich: in einem Spaltenflex-Container werden
 * die Aussenabstaende der Flex-Items bei der Verteilung des freien Raums
 * beruecksichtigt - der Abstand geht also von der Wachstumsflaeche des
 * Inhaltsbereichs ab und erzeugt keinen Ueberlauf ueber 100vh hinaus. Ohne diese
 * Begruendung ist der Abstand ein naheliegender Verdaechtiger fuer "kommt der
 * Ueberlauf davon?" - er ist es nicht.
 */
.app-footer {
  display: flex;
  gap: 1.2rem;
  justify-content: center;
  padding: 1.5rem 1rem;
  margin-top: 2rem;
  font-size: 0.85rem;
  color: var(--teccle-blau-75);
}
.app-footer a {
  color: inherit;
}

/*
 * Datumsbereichs-Picker (Nutzerwunsch 2026-08-24, ersetzt das Zeitraum-<select> im
 * Rechnungsfilter) - eigenständiges Kalender-Widget, keine externe Library (CSP script-src
 * 'self'). Kalender-Grid links, vordefinierte Zeiträume rechts, analog zum vom Nutzer gezeigten
 * TimeBuzzer-Referenzbild.
 */
.date-range-field {
  position: relative;
}
.date-range-input {
  cursor: pointer;
  background: var(--color-surface);
}
.date-range-popover {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 60;
  display: flex;
  gap: 1.2rem;
  margin-top: 0.35rem;
  padding: 1rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 90, 0.18);
}
.date-range-popover[hidden] {
  display: none;
}
.drp-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  font-weight: 600;
  color: var(--color-text);
}
.drp-nav button {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  color: var(--color-text);
  padding: 0.1rem 0.5rem;
}
.drp-nav button:hover {
  color: var(--color-brand-accent);
}
.drp-grid {
  border-collapse: collapse;
}
.drp-grid th,
.drp-grid td {
  width: 2.1rem;
  height: 2.1rem;
  text-align: center;
  font-size: 0.82rem;
  padding: 0;
}
.drp-grid th {
  color: var(--teccle-blau-75);
  font-weight: 600;
}
.drp-kw {
  color: var(--teccle-blau-75);
  font-weight: 600;
  font-size: 0.78rem;
}
.drp-day {
  cursor: pointer;
  border-radius: 50%;
  color: var(--color-text);
}
.drp-day:hover {
  background: var(--teccle-blau-10);
}
.drp-day--other-month {
  opacity: 0.35;
}
.drp-day--in-range {
  background: var(--teccle-blau-10);
  border-radius: 0;
}
.drp-day--start,
.drp-day--end {
  background: var(--color-brand-accent);
  color: var(--color-text-on-dark);
}
.drp-day--start.drp-day--in-range {
  border-radius: 50% 0 0 50%;
}
.drp-day--end.drp-day--in-range {
  border-radius: 0 50% 50% 0;
}
.drp-presets {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 150px;
  border-left: 1px solid var(--color-border);
  padding-left: 1rem;
}
.drp-presets button {
  text-align: left;
  background: none;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.35rem 0.6rem;
  cursor: pointer;
  font-size: 0.82rem;
  color: var(--color-text);
}
.drp-presets button:hover {
  border-color: var(--color-brand-accent);
}
.drp-presets button.active {
  background: var(--color-brand-accent);
  color: var(--color-text-on-dark);
  border-color: var(--color-brand-accent);
}

/* Belegtyp-Auswahl als Dropdown mit Checkboxen (Nutzerwunsch 2026-08-24, ersetzt die vorherige
   immer sichtbare Checkbox-Reihe - skaliert besser, sobald weitere Belegtypen dazukommen). */
.multiselect-field {
  position: relative;
}
.multiselect-toggle {
  width: 100%;
  text-align: left;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.45rem 0.6rem;
  cursor: pointer;
  color: var(--color-text);
}
.multiselect-panel {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 60;
  min-width: 220px;
  margin-top: 0.35rem;
  padding: 0.6rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 90, 0.18);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.multiselect-panel[hidden] {
  display: none;
}
.multiselect-option {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 400;
}
.multiselect-option-count {
  color: var(--teccle-blau-75);
  font-size: 0.82rem;
}
.multiselect-toggle:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

/*
 * Tab-Leiste ueber der Belegliste (Plan 30-07, D-22) - Entwurf/Generiert/Versendet/Alle. Ein Tab
 * ist eine Kombination aus Status-/Versandfilter (rechnung-filter.js), kein eigenes Panel; deshalb
 * einfache Schaltflaechen statt eines echten Tab-Widgets mit ARIA role="tablist". flex-wrap haelt
 * die Leiste auf schmalen Geraeten bedienbar (Konvention aus Phase 24) - vier Schaltflaechen
 * brechen dort einfach in eine zweite Zeile um, statt sich zu ueberlappen oder abgeschnitten zu
 * werden.
 */
.tab-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}
.tab-bar__tab {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  color: var(--color-text);
  font-weight: 400;
}
.tab-bar__tab[aria-pressed="true"] {
  background: var(--teccle-blau-100);
  border-color: var(--teccle-blau-100);
  color: var(--color-surface);
  font-weight: 600;
}
.tab-bar__count {
  color: var(--teccle-blau-75);
  font-size: 0.82rem;
}
.tab-bar__tab[aria-pressed="true"] .tab-bar__count {
  color: var(--teccle-blau-50);
}

/*
 * Clientseitige Listen-Paginierung (Nutzerwunsch 2026-08-24, static/js/pagination.js) - dieselbe
 * Pill-Button-Optik wie die Zeitraum-Presets (.drp-presets button) für die Seitengrößen-Auswahl,
 * die Zurück/Weiter-Navigation lehnt sich an .btn-secondary an. Bleibt komplett unsichtbar
 * (container[hidden]), solange die aktuelle Ergebnisliste die kleinste Seitengröße nicht
 * übersteigt.
 */
.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.75rem;
  padding: 0.6rem 0.1rem 0;
}
.pagination[hidden] {
  display: none;
}
.pagination-sizes {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--teccle-blau-75);
}
.pagination-sizes-label {
  margin-right: 0.1rem;
}
.pagination-size-btn {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  padding: 0.25rem 0.6rem;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--color-text);
  cursor: pointer;
  box-shadow: none;
}
.pagination-size-btn:hover {
  border-color: var(--color-brand-accent);
  box-shadow: none;
}
.pagination-size-btn.active {
  background: var(--color-brand-accent);
  color: var(--color-text-on-dark);
  border-color: var(--color-brand-accent);
}
.pagination-nav {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.pagination-nav-btn {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  padding: 0.35rem 0.8rem;
  font-size: 0.85rem;
  font-weight: 600;
  border-radius: var(--radius-sm);
  box-shadow: none;
}
.pagination-nav-btn:hover:not(:disabled) {
  background: var(--teccle-grau-50);
  box-shadow: none;
}
.pagination-nav-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.pagination-info {
  font-size: 0.85rem;
  color: var(--teccle-blau-75);
  white-space: nowrap;
}

/*
 * Modal-Muster (Phase 30 Plan 06 Task 1, D-20) - das erste Dialogmuster des Portals; jeder
 * weitere Dialog benutzt dieselben Klassen. Getragen wird es vom nativen <dialog>-Element,
 * das Fokusfalle, Escape und die Sperre der Hintergrundbedienung selbst mitbringt (siehe
 * static/js/modal.js). Hier steht nur das Aussehen - und die eine Sache, die das Element
 * nicht selbst leistet: der Hintergrund darf nicht mitscrollen.
 *
 * html.modal-open setzt static/js/modal.js beim Oeffnen; dieselbe Bauform wie
 * html.sidebar-open beim mobilen Menue, damit es nur EINE Art gibt, den Dokumentzustand
 * eines geoeffneten Overlays auszudruecken.
 */
html.modal-open {
  overflow: hidden;
}

/*
 * Ohne <dialog>-Unterstuetzung gibt es keine UA-Regel, die einen nicht geoeffneten Dialog
 * verbirgt - ohne diese Zeile stuende der Inhalt dort dauerhaft mitten auf der Seite.
 */
dialog.app-modal:not([open]) {
  display: none;
}

dialog.app-modal {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  background: var(--color-surface);
  color: var(--color-text);
  padding: 1.5rem;
  width: min(36rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
}
dialog.app-modal::backdrop {
  /* Dieselbe Blaeuflaeche wie .sidebar-overlay - ein Dialog verdunkelt nicht anders als das
     mobile Menue. */
  background: rgba(0, 0, 90, 0.4);
}
.app-modal__title {
  margin: 0 0 1rem;
  font-family: var(--font-heading);
  font-size: 1.25rem;
}
.app-modal__hint {
  font-size: 0.85rem;
  color: var(--teccle-blau-75);
  margin: 0.2rem 0 0;
}
/*
 * Vorschaufelder (Betreff, Text, Anhang): bewusst kein deaktiviertes Eingabefeld, sondern
 * eine Flaeche, die sichtbar keine Eingabe ist. Was hier steht, kommt aus den Einstellungen
 * des Mandanten und wird im Dialog nicht geaendert (D-05 macht nur die Empfaenger aenderbar).
 */
.app-modal__preview {
  margin: 0;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-muted);
  font-family: var(--font-body);
  font-size: 0.95rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.app-modal__actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  flex-wrap: wrap;
  margin-top: 1.5rem;
}

/*
 * Auf einem schmalen Geraet nimmt der Dialog die volle Breite ein und die Schaltflaechen
 * stehen untereinander - sonst reicht die Zeile fuer zwei Knoepfe nebeneinander nicht, und
 * der bestaetigende Knopf rutscht aus dem sichtbaren Bereich.
 */
@media (max-width: 640px) {
  dialog.app-modal {
    width: calc(100vw - 1rem);
    padding: 1rem;
  }
  .app-modal__actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }
}

/*
 * Zeilenauswahl und Sammeldialog der Belegliste (Phase 30 Plan 09, D-22/D-25/D-26).
 *
 * Die Leiste steht zwischen Filterkarte und Tabelle und ist voreingestellt unsichtbar
 * (hidden) - sichtbar macht sie versand-sammelauswahl.js genau in den Tabs, in denen es
 * eine Versandaktion gibt. Sie traegt keine eigene Flaeche wie eine Karte: sie gehoert
 * sichtbar zur Tabelle darunter, nicht zum Filter darueber.
 */
.bulk-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-bottom: 0.75rem;
}
.bulk-bar[hidden] {
  display: none;
}
.bulk-bar__alle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
}
.bulk-bar__zaehler {
  color: var(--teccle-blau-75);
  font-size: 0.9rem;
}

/*
 * Die Auswahlspalte bleibt schmal und zentriert - sie traegt nur ein Kaestchen. Die
 * hidden-Regeln stehen ausdruecklich da: fuer Tabellenzellen setzt die Browser-Vorgabe
 * display: table-cell, und auf die soll sich hier nichts verlassen muessen.
 */
.selection-col,
.selection-cell {
  width: 2.5rem;
  text-align: center;
}
.selection-col[hidden],
.selection-cell[hidden] {
  display: none;
}

/*
 * Der Sammeldialog zeigt eine Tabelle statt weniger Felder und braucht dafuer mehr Breite
 * als der Sendedialog am einzelnen Beleg - sonst umbricht jede Empfaengeradresse.
 */
dialog.app-modal--breit {
  width: min(52rem, calc(100vw - 2rem));
}

/*
 * Die Belegliste im Dialog: eigener Rollbereich, damit der Dialog bei 62 Belegen nicht
 * beliebig hoch wird und die Schaltflaechen unten erreichbar bleiben.
 */
.sammelversand-liste {
  max-height: 16rem;
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.sammelversand-tabelle {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.sammelversand-tabelle th,
.sammelversand-tabelle td {
  text-align: left;
  padding: 0.35rem 0.6rem;
  border-bottom: 1px solid var(--color-border);
  overflow-wrap: anywhere;
}
.sammelversand-tabelle thead th {
  position: sticky;
  top: 0;
  background: var(--color-surface-muted);
}
/* Ein uebersprungener Beleg: er steht in der Liste, geht aber nicht mit (SammelversandErgebnis). */
.sammelversand-zeile--uebersprungen {
  color: var(--teccle-blau-75);
  text-decoration: line-through;
}
.sammelversand-zeile--uebersprungen td:last-child {
  text-decoration: none;
  color: var(--color-warning-border, #b45309);
}
/*
 * Die Bestaetigung nach D-26 - bewusst kein unauffaelliges Kaestchen am Rand: sie ist die
 * einzige Stelle, an der ein Doppelversand an viele Kunden noch aufzuhalten ist.
 */
.sammelversand-bestaetigung {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-weight: 600;
  cursor: pointer;
}

/*
 * Statusfenster des Sammelversands (Phase 30 Plan 09, Task 3). Unten rechts, ueber allem
 * anderen (z-index wie die Seitenleiste) - aber ausdruecklich KEIN Modal: kein Hintergrund-
 * Overlay, keine Sperre der Seite, siehe versand-statusfenster.js und die Klarstellung zu D-20.
 */
.status-fenster {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 100;
  width: min(22rem, calc(100vw - 2rem));
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 0.9rem 1rem;
}
.status-fenster[hidden] {
  display: none;
}
.status-fenster--fehler {
  border-color: var(--color-error-border);
}
.status-fenster__kopf {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.status-fenster__text {
  flex: 1;
  font-size: 0.9rem;
}
.status-fenster__schliessen {
  border: none;
  background: none;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  color: var(--teccle-blau-75);
  padding: 0 0.2rem;
}
.status-fenster__symbol {
  width: 1rem;
  height: 1rem;
  flex: none;
  border: 2px solid var(--color-border);
  border-top-color: var(--teccle-blau-100, var(--color-border));
  border-radius: 50%;
  animation: status-fenster-dreh 0.8s linear infinite;
}
.status-fenster__symbol[hidden] {
  display: none;
}
.status-fenster__symbol--erfolg {
  border: none;
  animation: none;
  color: var(--color-success-text);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
@keyframes status-fenster-dreh {
  to {
    transform: rotate(360deg);
  }
}
.status-fenster__fehler {
  margin-top: 0.6rem;
  color: var(--color-error-text);
  font-size: 0.85rem;
}
.status-fenster__fehler[hidden] {
  display: none;
}
.status-fenster__fehler ul {
  margin: 0.3rem 0 0;
  padding-left: 1.1rem;
}
