/* ==================================================================
   LotzApp B2B — Sortiment (Shortcode [lotzwoo_b2b_shop])
   Work block E. Target picture: docs/mockups/prototype/.

   Every rule is scoped to .lotzwoo-b2b-shop and every custom property
   is prefixed --lwb-. The shop is a shortcode dropped into somebody
   else's theme: it may not leak a single global, and a theme that
   defines --brand-500 for its own purposes must not repaint it.

   The tokens are the prototype's, renamed. Where a theme should be
   able to take over — the accent colour above all — the fallback is
   written so a site can override just the token.
   ================================================================== */

.lotzwoo-b2b-shop .lwb-muted { color: var(--lwb-ink-500); }
.lotzwoo-b2b-shop .lwb-small { font-size: var(--lwb-fs-sm); }
.lotzwoo-b2b-shop .lwb-tiny { display: block; font-size: var(--lwb-fs-2xs); }
.lotzwoo-b2b-shop .lwb-spacer { flex: 1; }
.lotzwoo-b2b-shop .lwb-num { font-variant-numeric: tabular-nums; }
.lotzwoo-b2b-shop .lwb-right { text-align: right; }

/* ---------------- Buttons, fields ---------------- */

.lotzwoo-b2b-shop .lwb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--lwb-sp-2);
  padding: 9px 16px;
  border: 1px solid transparent;
  border-radius: var(--lwb-r-md);
  background: var(--lwb-ink-100);
  color: var(--lwb-ink-700);
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background 110ms ease, border-color 110ms ease;
}

.lotzwoo-b2b-shop .lwb-btn:hover { background: var(--lwb-ink-200); }
/* **Die Flaechenregel: was Fokus bekommen kann, zeigt ihn auch.**
   Bis zum 2026-08-16 gab es Fokusregeln fuer genau vier Selektoren — `.lwb-btn`,
   `.lwb-input`, `.lwb-select`, `.lwb-nameopen`. Ohne Regel blieben unter anderem
   die Gebinde-Pillen, der Favoritenstern, die Facetten-Umschalter, die
   Mengen-Stepper, die Linkknoepfe und beide Schliessen-Knoepfe. Wer mit Tab
   durch die Erfassung geht, sah nicht, wo er steht — am Lager und am Telefon
   kostet jeder Fehlgriff Sekunden oder eine falsche Menge.

   Eine Flaeche statt neun Einzelregeln, weil die zehnte sonst wieder vergessen
   wird. `--lwb-focus` ist ein box-shadow-Wert, KEIN outline-Wert: `outline:
   var(--lwb-focus)` ergibt `outline: 0 0 0 3px rgba(...)` und wird vom Browser
   verworfen. Genau dieser Fehler stand in `.lwb-nameopen` und in der
   Empfehlung, die diesen Auftrag ausgeloest hat. */
.lotzwoo-b2b-shop :is(button, a[href], select, input, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
  outline: none;
  box-shadow: var(--lwb-focus);
  border-radius: var(--lwb-r-sm);
}

.lotzwoo-b2b-shop .lwb-btn:focus-visible { outline: none; box-shadow: var(--lwb-focus); }
.lotzwoo-b2b-shop .lwb-btn[disabled] { opacity: .55; cursor: not-allowed; }

.lotzwoo-b2b-shop .lwb-btn--primary { background: var(--lwb-brand-500); color: var(--lwb-surface); }
.lotzwoo-b2b-shop .lwb-btn--primary:hover { background: var(--lwb-brand-600); }
.lotzwoo-b2b-shop .lwb-btn--secondary { background: var(--lwb-surface); border-color: var(--lwb-ink-200); }
.lotzwoo-b2b-shop .lwb-btn--secondary:hover { background: var(--lwb-ink-50); }
.lotzwoo-b2b-shop .lwb-btn--onbar { background: rgba(255, 255, 255, .16); color: var(--lwb-surface); border-color: rgba(255, 255, 255, .32); }
.lotzwoo-b2b-shop .lwb-btn--onbar:hover { background: rgba(255, 255, 255, .26); }
.lotzwoo-b2b-shop .lwb-btn--sm { padding: 6px 11px; font-size: var(--lwb-fs-sm); }
.lotzwoo-b2b-shop .lwb-btn--lg { padding: 12px 20px; font-size: var(--lwb-fs-base); }
.lotzwoo-b2b-shop .lwb-btn--block { width: 100%; }

.lotzwoo-b2b-shop .lwb-linkbtn {
  border: 0;
  background: none;
  padding: 0;
  color: var(--lwb-brand-600);
  font: inherit;
  font-size: var(--lwb-fs-sm);
  text-decoration: underline;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-input,
.lotzwoo-b2b-shop .lwb-select {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-surface);
  color: var(--lwb-ink-900);
  font: inherit;
  font-size: var(--lwb-fs-md);
}

.lotzwoo-b2b-shop .lwb-input:focus,
.lotzwoo-b2b-shop .lwb-select:focus { outline: none; border-color: var(--lwb-brand-300); box-shadow: var(--lwb-focus); }
.lotzwoo-b2b-shop .lwb-input--lg { padding: 12px 14px; font-size: var(--lwb-fs-base); }
.lotzwoo-b2b-shop .lwb-select { width: auto; }

.lotzwoo-b2b-shop .lwb-field-label {
  display: block;
  margin-bottom: var(--lwb-sp-1);
  font-size: var(--lwb-fs-xs);
  font-weight: 600;
  color: var(--lwb-ink-600);
}

.lotzwoo-b2b-shop .lwb-checkline {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: flex-start;
  margin-top: var(--lwb-sp-3);
  font-size: var(--lwb-fs-sm);
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-checkline input { margin-top: 2px; flex: 0 0 auto; }

/* Die Favoritenliste in der Seitenspalte ist ein `fieldset` — und hatte bis
   zum 2026-08-20 **keine einzige eigene Regel**: `lwb-radioline` kam im
   ganzen Arbeitsbaum genau einmal vor, naemlich in der Zeile, die sie setzt
   (`templates/shortcodes/b2b-shop.php`). Rahmen und Polster, die dort zu
   sehen waren, waren der Browser-Default des Elements, nichts Entschiedenes.

   `fieldset` und `legend` **bleiben**: die Gruppierung ist das, was einem
   Screenreader sagt, dass diese Radios zusammengehoeren. Nur der Kasten geht.

   `min-width: 0` ist kein Zierrat, sondern der Punkt: ein `fieldset` traegt
   ab Werk `min-width: min-content` und sprengt sonst die schmale
   Seitenspalte, sobald ein Listenname lang wird. */
.lotzwoo-b2b-shop .lwb-radioline {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}

/* Die Checkline selbst bleibt oben ausgerichtet: ihre Beschriftungen sind
   teils zweizeilig, und ein mittig sitzendes Kaestchen neben zwei Zeilen
   liest sich verrutscht. Zentriert wird die Zeile aus Icon und Text darin. */
.lotzwoo-b2b-shop .lwb-checkline > span:has(.lwb-ico) {
  display: inline-flex;
  align-items: center;
  gap: var(--lwb-sp-1);
}

/* ---------------- Badges, alerts, panels ---------------- */

.lotzwoo-b2b-shop .lwb-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--lwb-r-full);
  background: var(--lwb-ink-100);
  color: var(--lwb-ink-600);
  font-size: var(--lwb-fs-2xs);
  font-weight: 600;
  white-space: nowrap;
}

.lotzwoo-b2b-shop .lwb-badge--ok { background: var(--lwb-ok-50); color: var(--lwb-ok-500); }
.lotzwoo-b2b-shop .lwb-badge--warn { background: var(--lwb-warn-50); color: var(--lwb-warn-500); }
.lotzwoo-b2b-shop .lwb-badge--err { background: var(--lwb-err-50); color: var(--lwb-err-500); }
.lotzwoo-b2b-shop .lwb-badge--info { background: var(--lwb-info-50); color: var(--lwb-info-500); }
.lotzwoo-b2b-shop .lwb-badge--brand { background: var(--lwb-brand-50); color: var(--lwb-brand-700); }

.lotzwoo-b2b-shop .lwb-alert {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: center;
  flex-wrap: wrap;
  margin: var(--lwb-sp-4) 0;
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-ink-50);
  font-size: var(--lwb-fs-sm);
}

.lotzwoo-b2b-shop .lwb-alert--warn { background: var(--lwb-warn-50); border-color: #f4d9a4; color: var(--lwb-warn-500); }
.lotzwoo-b2b-shop .lwb-alert--err { background: var(--lwb-err-50); border-color: #f4b9b9; color: var(--lwb-err-700); }
.lotzwoo-b2b-shop .lwb-alert--info { background: var(--lwb-info-50); border-color: #b9cff2; color: var(--lwb-info-500); }

/* ---------------- Shophinweis ----------------

   Der Satz des Betreibers, direkt unter der Kontextleiste und vor allem
   anderen (`Shop_Notice`). Gemeint sind Auskünfte wie „Am 03.09.
   geschlossen" oder „Bestellannahme bis 16 Uhr".

   **Info-Blau und nicht die Markenfarbe.** Die Fläche steht als erstes
   Element unter einer dunklen Leiste und über dem Sortiment; in Brand-Rot
   läse sie wie eine Störung, in Grau wie Kleingedrucktes. `--lwb-info-*`
   ist die Rolle, die es meint — dieselbe, die `.lwb-alert--info` trägt.

   **Kein `.lwb-alert`, obwohl es fast so aussieht.** Ein Alert ist die
   Antwort des Shops auf einen Zustand und verschwindet mit ihm; dies ist
   eine redaktionelle Auskunft mit Titel, Absätzen und einem Knopf, der sie
   für diesen Kunden wegräumt. Zwei verschiedene Sachen unter einer Klasse
   hätten den Alert um Dinge erweitert, die kein Alert braucht. */
.lotzwoo-b2b-shop .lwb-shopnotice {
  display: flex;
  gap: var(--lwb-sp-3);
  align-items: flex-start;
  margin: var(--lwb-sp-4) 0;
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
  border: 1px solid #b9cff2;
  border-radius: var(--lwb-r-lg);
  background: var(--lwb-info-50);
  color: var(--lwb-ink-700);
  font-size: var(--lwb-fs-sm);
}

/* Das Symbol sitzt auf der Höhe der ersten Zeile und schrumpft nicht: ein
   gequetschtes Icon liest sich wie ein Fehler. */
.lotzwoo-b2b-shop .lwb-shopnotice__ico {
  flex: none;
  display: flex;
  padding-top: 1px;
  color: var(--lwb-info-500);
}

.lotzwoo-b2b-shop .lwb-shopnotice__body { flex: 1; min-width: 0; }
.lotzwoo-b2b-shop .lwb-shopnotice__body p { margin: 0; }
.lotzwoo-b2b-shop .lwb-shopnotice__body p + p { margin-top: var(--lwb-sp-2); }

.lotzwoo-b2b-shop .lwb-shopnotice__title {
  font-weight: 700;
  color: var(--lwb-ink-900);
}

/* Der Knopf ist quadratisch und trägt seinen Namen nur für Vorlesewerkzeuge
   (`aria-label`): daneben steht der Satz, den er wegräumt, und ein Wort
   „Schließen" davor nähme ihm die Breite. */
.lotzwoo-b2b-shop .lwb-shopnotice__close {
  flex: none;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  margin: -2px -4px 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--lwb-r-md);
  background: none;
  color: var(--lwb-ink-500);
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-shopnotice__close:hover {
  background: rgba(20, 15, 10, .06);
  color: var(--lwb-ink-900);
}

.lotzwoo-b2b-shop .lwb-panel {
  margin: var(--lwb-sp-6) 0;
  padding: var(--lwb-sp-8);
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-lg);
  background: var(--lwb-surface);
  box-shadow: var(--lwb-sh-sm);
}

.lotzwoo-b2b-shop .lwb-panel--center { max-width: 640px; margin-inline: auto; text-align: center; }
.lotzwoo-b2b-shop .lwb-panel--center p { max-width: 52ch; margin-inline: auto; }

/* ---------------- Context bar (AD-3) ---------------- */

/* Die Kontextleiste wird hier **nicht** mehr gestaltet.

   Bis zum 2026-08-15 standen an dieser Stelle rund siebzig Zeilen fuer
   `.lwb-contextbar` und `.lwb-ctx-*` — die dunkle Flaeche, die Symbole, das
   Abzeichen, der Trenner. Daneben lagen im Basis-Theme rund hundertfuenfzig
   Zeilen fuer `.lotzwoo-contextbar`, die dieselbe Leiste auf Warenkorb und
   Konto anders aussehen liessen.

   Seit AP-32 gibt es eine Vorlage (`templates/context-bar.php`, gezeichnet von
   `Context_Bar::markup()`) und eine Gestaltung, und die liegt im Basis-Theme:
   `.lotzwoo-contextbar` in dessen `style.css`. Der Grund ist derselbe wie bei
   `.lotzwoo-conflicts` und den Kopfflaechen — das Plugin entscheidet, *was*
   dasteht, das Theme, *wie* es aussieht — und er hat hier eine zweite Haelfte,
   die schwerer wiegt: die Leiste steht auf Seiten, die `b2b-shop.css`
   ausdruecklich **nicht** laden (177.602 Bytes, die auf einer Kontoseite
   nichts zu suchen haben). Eine Gestaltung in dieser Datei erreichte drei der
   vier Flaechen nicht.

   Was hier bleibt, ist das, was nur das Sortiment hat: der
   Netto/Brutto-Umschalter weiter unten. Er wird der Leiste als `actions`
   uebergeben und steht deshalb in ihrem Markup, gehoert aber dem Kurzcode. */

/* Ein Icon steht nie allein: jedes sitzt neben seiner eigenen Beschriftung,
   ist deshalb aria-hidden und traegt keine Bedeutung, die der Text nicht
   schon traegt. flex: none, damit es bei knappem Platz nicht schmaler wird
   als sein viewBox — ein gequetschtes Icon liest sich wie ein Fehler.

   Strichbreite und Farbe stehen hier und nicht als Attribute am <svg>: die
   Icons kommen aus einem Sprite, PHP und Skript bauen beide nur noch ein
   <use>, und eine Regel ist billiger als sieben Attribute an jeder Stelle.
   stroke-width: 2 im 24er-viewBox ist Lucides eigenes Mass — bei 14px
   gezeichnet sind das 1,17px, genau wie im Prototyp. */
.lotzwoo-b2b-shop .lwb-ico {
  flex: none;
  display: inline-block;
  vertical-align: -0.145em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Der gesetzte Favorit ist ein gefuellter Stern. Der Zustand steht schon in
   aria-pressed — ihn ein zweites Mal in eine Klasse zu schreiben hiesse, zwei
   Wahrheiten zu pflegen. */
.lotzwoo-b2b-shop .lwb-favstar[aria-pressed="true"] .lwb-ico { fill: currentColor; }

.lotzwoo-b2b-shop .lwb-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }


.lotzwoo-b2b-shop .lwb-taxtoggle {
  display: inline-flex;
  padding: 2px;
  border-radius: var(--lwb-r-full);
  background: rgba(255, 255, 255, .14);
}

.lotzwoo-b2b-shop .lwb-taxtoggle button {
  border: 0;
  padding: 4px 12px;
  border-radius: var(--lwb-r-full);
  background: none;
  color: rgba(255, 255, 255, .78);
  font: inherit;
  font-size: var(--lwb-fs-xs);
  font-weight: 600;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-taxtoggle button[aria-pressed="true"] { background: var(--lwb-surface); color: var(--lwb-ink-900); }

/* ----------- Suche und bestellen (AP-64: ein Feld) ------------- */

/* Das Feld in der Werkzeugleiste. Es trägt `data-lwb-search` — dasselbe
   Attribut, das das Spaltenfeld trug: dasselbe Feld mit derselben Aufgabe,
   nur an einem anderen Ort (AP-64, Auftrag 1). Die Lupe sitzt im Feld;
   pointer-events: none, damit ein Klick auf das Icon im Eingabefeld
   landet. */
.lotzwoo-b2b-shop .lwb-searchfield {
  position: relative;
  flex: 1 1 260px;
  min-width: 0;
}

.lotzwoo-b2b-shop .lwb-searchfield__ico {
  position: absolute;
  top: 50%;
  left: 12px;
  transform: translateY(-50%);
  color: var(--lwb-ink-400);
  pointer-events: none;
}

/* Links die Lupe (dekorativ, sie sagt „hier wird gesucht"), rechts der Knopf
   (er sagt „jetzt suchen"). Dazwischen Chromes eigenes Kreuz von
   `type="search"`, und genau darum geht dieses Polster:

   **Das native Kreuz sitzt an der inneren rechten Kante des Feldes und
   respektiert `padding-right`.** Ein grosszuegiges Polster schiebt es also
   nach links, aus dem Weg des Knopfes — ohne es wegzuformatieren. Das war die
   Vorgabe des Auftraggebers, und sie ist die bessere: `-webkit-search-cancel-button`
   auf `display: none` naehme dem Kunden eine Schaltflaeche, die er kennt. */
/* Rechts in `em` und nicht in Pixeln (2026-08-29): das Polster haelt den
   Suchknopf frei, und dessen Breite ist die seines Wortes — es waechst und
   schrumpft mit der Schrift des Themes und mit der Uebersetzung. Eine feste
   Zahl stimmt nur fuer eine Kombination. */
.lotzwoo-b2b-shop .lwb-searchfield .lwb-input { padding-left: 38px; padding-right: 7em; }

/* ---------------- Der Suchknopf (AP-80, C) ---------------- */

/* **Warum ueberhaupt ein Knopf.** Bis AP-80 filterte das Tippen selbst; es gab
   nichts auszuloesen. Seit die Suche eine Bestaetigung hat, braucht sie eine
   sichtbare — Enter allein ist eine Geste, die man kennen muss.

   Er sitzt absolut im Feld statt daneben in der Leiste: daneben waere er ein
   fuenftes Bedienelement in einer Reihe, die Teil B gerade auf eine Hoehe
   gebracht hat, und das Feld verloere die Breite, die es fuer lange Begriffe
   braucht. */
.lotzwoo-b2b-shop .lwb-searchgo {
  position: absolute;
  top: 50%;
  right: 3px;
  transform: translateY(-50%);
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: var(--lwb-sp-1);
  box-sizing: border-box;
  height: calc(var(--lwb-control-h) - 6px);
  padding: 0 10px;
  border: 0;
  border-radius: var(--lwb-r-sm);
  background: var(--lwb-brand-600);
  color: var(--lwb-surface);
  font: inherit;
  font-size: var(--lwb-fs-sm);
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-searchgo:hover { background: var(--lwb-brand-700); }
.lotzwoo-b2b-shop .lwb-searchgo:focus-visible { box-shadow: var(--lwb-focus); outline: none; }

/* Unter 560 px traegt der Knopf nur den Pfeil: das Feld ist dort die schmalste
   Flaeche der Seite, und ein Wort darin kostet Begriffsbreite. Der zugaengliche
   Name bleibt — das Wort wird verborgen, nicht entfernt. */
@media (max-width: 560px) {
  .lotzwoo-b2b-shop .lwb-searchfield .lwb-input { padding-right: 56px; }

  .lotzwoo-b2b-shop .lwb-searchgo__wort {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* Das Vorschlagsblatt: die ersten fünf Zeilen derselben Antwort, die
   die Liste füllt — keine zweite Abfrage je Tastenpause (AP-64). Es hängt
   absolut am Feld und reißt die Werkzeugleiste nicht aus ihrem Fluss. */
.lotzwoo-b2b-shop .lwb-searchsheet {
  position: absolute;
  z-index: calc(var(--lwb-z-sticky) + 1);
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 380px;
  overflow: auto;
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-surface);
  box-shadow: var(--lwb-sh-lg);
}

.lotzwoo-b2b-shop .lwb-sheet__cap {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: center;
  padding: var(--lwb-sp-2) var(--lwb-sp-3);
  border-bottom: 1px solid var(--lwb-ink-100);
  font-size: var(--lwb-fs-2xs);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--lwb-ink-500);
}

/* Die Flagge am aufgelösten Barcode — ein Fakt, kein Urteil: der exakte
   Treffer steht oben, weil die Zahl ihn dorthin gestellt hat. */
.lotzwoo-b2b-shop .lwb-bcflag {
  border-radius: 999px;
  padding: 2px 8px;
  background: var(--lwb-ok-50);
  color: var(--lwb-ok-500);
  font-size: var(--lwb-fs-2xs);
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
}

.lotzwoo-b2b-shop .lwb-sheet__empty {
  padding: var(--lwb-sp-4);
  text-align: center;
  font-size: var(--lwb-fs-sm);
  color: var(--lwb-ink-500);
}

/* Die Auswegzeile: der Filter meldet sich, statt übergangen zu werden.
   Warm statt rot — der Zustand ist eine Auskunft, kein Fehler. */
.lotzwoo-b2b-shop .lwb-sheet__fallback {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  padding: var(--lwb-sp-2) var(--lwb-sp-3);
  background: var(--lwb-warn-50);
  font-size: var(--lwb-fs-sm);
  color: var(--lwb-ink-700);
}

.lotzwoo-b2b-shop .lwb-sheet__fallback .lwb-linkbtn { color: var(--lwb-warn-500); }

/* Eine Blattzeile: Name/Meta/Pillen links, Preis und Menge rechts —
   das Layout der Listenzeile, enger getaktet. */
.lotzwoo-b2b-shop .lwb-sheetline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: var(--lwb-sp-3);
  align-items: center;
  padding: var(--lwb-sp-3);
  border-bottom: 1px solid var(--lwb-ink-100);
}

.lotzwoo-b2b-shop .lwb-sheetline:last-child { border-bottom: 0; }
.lotzwoo-b2b-shop .lwb-sheetline.is-active { background: var(--lwb-brand-50); }

/* Der exakte Barcode-Treffer ist kein normaler Vorschlag: ein schmaler
   Akzent links nennt, warum er oben steht. */
.lotzwoo-b2b-shop .lwb-sheetline.is-barcoded {
  box-shadow: inset 3px 0 0 var(--lwb-ok-500);
}

.lotzwoo-b2b-shop .lwb-sheetline__name { font-weight: 600; color: var(--lwb-ink-900); }
.lotzwoo-b2b-shop .lwb-sheetline__meta { font-size: var(--lwb-fs-xs); color: var(--lwb-ink-500); }
.lotzwoo-b2b-shop .lwb-sheetline__pills { margin-top: var(--lwb-sp-1); }

.lotzwoo-b2b-shop .lwb-sheetline__price {
  font-weight: 600;
  white-space: nowrap;
  text-align: right;
}

.lotzwoo-b2b-shop .lwb-sheetline__act {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: center;
}

/* Am Telefon wird die Zeile zum Stapel: der Platz für drei Spalten ist
   nicht da, und eine gequetschte Zeile ist schlechter als zwei. */
@media (max-width: 640px) {
  .lotzwoo-b2b-shop .lwb-sheetline {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .lotzwoo-b2b-shop .lwb-sheetline__price { grid-column: 1; text-align: left; }
  .lotzwoo-b2b-shop .lwb-sheetline__act { grid-column: 2; grid-row: 1 / span 2; }
}

/* ---------------- Layout ---------------- */

.lotzwoo-b2b-shop .lwb-head {
  display: flex;
  gap: var(--lwb-sp-3);
  /* Zwei Zeilen links, ein Knopf rechts: zentriert stuende der Knopf auf
     Hoehe des Satzes statt auf Hoehe der Ueberschrift, zu der er gehoert. */
  align-items: flex-start;
  /* **Und wer wegen der Tabellen-Kopfzeile hier landet, ist falsch abgebogen.**
     `.lwb-head` heisst in dieser Datei zweierlei — hier der Seitenkopf, weiter
     unten die Spaltenueberschrift —, und dieser Aussenrand traf lange beide.
     Die Ruecknahme steht dort, wo sie hingehoert: bei `.lwb-table__head`. */
  margin: var(--lwb-sp-6) 0 var(--lwb-sp-3);
}

/* min-width:0, damit ein langer Ortsname die Spalte nicht aufzieht und den
   Filter-Knopf aus der Zeile draengt — Flex-Kinder wachsen sonst ueber ihre
   Spalte hinaus. */
.lotzwoo-b2b-shop .lwb-head__main { min-width: 0; }

/* Zaehler auf der Grundlinie der Ueberschrift, nicht auf deren Mitte: beide
   sind Text, und `baseline` ist das, was das Auge als eine Zeile liest. */
.lotzwoo-b2b-shop .lwb-head__title {
  display: flex;
  align-items: baseline;
  gap: var(--lwb-sp-3);
  flex-wrap: wrap;
}

.lotzwoo-b2b-shop .lwb-head__title h1 {
  margin: 0;
  font-size: var(--lwb-fs-2xl);
  line-height: 1.25;
  color: var(--lwb-ink-900);
}

.lotzwoo-b2b-shop .lwb-head__hint { margin: 2px 0 0; }

/* Der Zaehler ist eine Angabe, kein Bedienelement. Deshalb `.lwb-badge` und
   nicht `.lwb-pill` oder `.lwb-chip`: beide runden Formen sind in diesem Shop
   anklickbar — die eine waehlt das Gebinde, die andere entfernt einen Filter.
   Eine dritte, die gleich aussieht und nichts tut, verspricht einen Klick, den
   es nicht gibt. Die neutrale Variante der Plakette ist die einzige der fuenf
   ohne Semantik; gruen oder rot hiesse hier "gut" oder "kaputt", und 24 ist
   weder das eine noch das andere.

   Zahl und Wort tragen dieselbe Schrift. Das <b> bleibt als Knoten stehen,
   weil `renderRows()` hineinschreibt, tritt aus der Plakette aber nicht mehr
   in eigener Groesse und Farbe heraus. */
.lotzwoo-b2b-shop .lwb-resultcount { font-size: var(--lwb-fs-xs); }
.lotzwoo-b2b-shop .lwb-resultcount b { font: inherit; }

.lotzwoo-b2b-shop .lwb-layout {
  display: grid;
  grid-template-columns: var(--lwb-sidebar-w) minmax(0, 1fr);
  gap: var(--lwb-sp-5);
  align-items: start;
}

/* Das `margin-left: auto` ist mit dem Umzug entfallen (2026-08-28): der Knopf
   stand oben im Kopf und musste sich selbst nach rechts schieben. In der
   Werkzeugleiste tut das jetzt das Suchfeld, das links davon waechst. */
.lotzwoo-b2b-shop .lwb-only-mobile { display: none; }

/* **Das Ausweichfach steht in der Filterspalte** (2026-08-28, zweite Runde).

   Der erste Anlauf stellte es oben in den Kopf, an die Stelle des
   Filter-Knopfes. Der Auftraggeber hat das am selben Tag verworfen, und die
   Begruendung traegt weiter als der Ort: Sortierung und Ansichtsumschalter
   sind „verwandt genug mit den Filtern, um dort gesucht und gefunden zu
   werden" — und der Kopf bekommt keine zweite Reihe Bedienelemente neben der
   Werkzeugleiste.

   Damit hat der Filter-Knopf unter 900 px eine zweite Aufgabe, ohne eine
   zweite Geste zu brauchen: er oeffnet die Schublade, in der beides steht.

   Es sieht aus wie eine Filtergruppe, weil es an deren Stelle steht: dieselbe
   Trennlinie, dasselbe Polster. `:empty` haelt es ganz aus dem Layout, solange
   die Leiste nichts abgegeben hat — sonst begaenne die Spalte mit einer Linie
   ohne Gegenueber. */
.lotzwoo-b2b-shop .lwb-sidebar__aus {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: center;
  flex-wrap: wrap;
  padding-bottom: var(--lwb-sp-4);
  margin-bottom: var(--lwb-sp-4);
  border-bottom: 1px solid var(--lwb-ink-100);
}

.lotzwoo-b2b-shop .lwb-sidebar__aus:empty { display: none; }

/* In der Spalte ist Platz in der Breite, aber nicht viel: das Sortierfeld
   nimmt sie ganz, der Umschalter steht darueber. Beide behalten die eine
   Bedienelementhoehe aus AP-80 (B), die sie in der Leiste hatten — sie steht
   dort unter `.lwb-toolbar .lwb-select` und greift hier nicht mehr. */
.lotzwoo-b2b-shop .lwb-sidebar__aus .lwb-select {
  box-sizing: border-box;
  width: 100%;
  height: var(--lwb-control-h);
  min-height: var(--lwb-control-h);
}

/* **Sprosse D: einzeilig und mit Beschriftung** (2026-08-29, angefordert).

   Am 2026-08-28 stand hier `flex-wrap: wrap`, weil der Umschalter mit drei
   beschrifteten Reitern rund 303 px braucht und die Spalte auf dem
   Schreibtisch nur 248 nutzbare hat. Das war die Antwort auf ein Problem, das
   die Leiter nicht mehr hat: **auf jenen Breiten kommt der Umschalter gar
   nicht mehr hierher.** Sprosse B nimmt ihm dort die Beschriftung, und
   symbollos passt er weiter in die Leiste. Hier landet er erst, wenn auch das
   nicht reicht — und dann ist die Spalte eine Schublade von rund 327 px, in
   der die drei nebeneinander stehen.

   Deshalb einzeilig und mit der einen Hoehe aus AP-80 (B), die er in der
   Leiste hatte. `min-width: 0` und `overflow: hidden` sind der Riegel fuer den
   Fall, dass eine Uebersetzung laenger ist als die deutschen Woerter: dann
   schneidet der Reiter ab, statt seinen Kasten zu sprengen. */
.lotzwoo-b2b-shop .lwb-sidebar__aus .lwb-viewswitch { width: 100%; }

.lotzwoo-b2b-shop .lwb-sidebar__aus .lwb-viewswitch button {
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  justify-content: center;
}

@media (max-width: 900px) {
  .lotzwoo-b2b-shop .lwb-layout { grid-template-columns: minmax(0, 1fr); }
  .lotzwoo-b2b-shop .lwb-only-mobile { display: inline-flex; }
  .lotzwoo-b2b-shop .lwb-sidebar:not(.is-drawer) { display: none; }
}

/* ---------------- Filter sidebar ---------------- */

.lotzwoo-b2b-shop .lwb-sidebar {
  position: sticky;
  /* AP-48: die gemessene Hoehe der Leiste statt 68px. `b2b-ctxheight.js`
     schreibt `--lwb-ctx-h` aus einem ResizeObserver; der Vorgabewert hier ist
     der alte Stand, damit ein Ausfall des Skripts nicht schlechter aussieht
     als vorher. Die 16px sind der Abstand darunter, nicht Teil der Leiste. */
  top: calc(var(--lwb-sticky-top) + var(--lwb-ctx-h, 52px) + 16px);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - var(--lwb-sticky-top) - var(--lwb-ctx-h, 52px) - 36px);
  /* Vordergrund-Rolle, siehe b2b-tokens.css: die Filterspalte steht auf dem
     Grund der Seite und soll das zeigen. Alle drei Token zusammen, nicht nur
     die Farbe. */
  border: 1px solid var(--lwb-front-border);
  border-radius: var(--lwb-r-lg);
  background: var(--lwb-front);
  box-shadow: var(--lwb-front-shadow);
}

.lotzwoo-b2b-shop .lwb-sidebar__scroll { flex: 1; overflow: auto; padding: var(--lwb-sp-4); }

/* Der Zustand, wenn kein Filter gesetzt ist. Er steht an der Stelle des
   Griffs und sieht bewusst nicht danach aus: gleiche Zeile, gleiche
   Schriftgroesse, aber gedaempft und ohne Unterstreichung. Der Griff daneben
   ist `--lwb-brand-600` und unterstrichen — wer den Unterschied nicht liest,
   sieht ihn. */
.lotzwoo-b2b-shop .lwb-sidebar__nofilters {
  font-size: var(--lwb-fs-sm);
  color: var(--lwb-ink-400);
}

.lotzwoo-b2b-shop .lwb-sidebar__foot {
  display: flex;
  justify-content: flex-end;
  padding: var(--lwb-sp-2) var(--lwb-sp-4);
  border-top: 1px solid var(--lwb-ink-150, var(--lwb-ink-200));
}

.lotzwoo-b2b-shop .lwb-filtergroup { padding-bottom: var(--lwb-sp-4); margin-bottom: var(--lwb-sp-4); border-bottom: 1px solid var(--lwb-ink-100); }
.lotzwoo-b2b-shop .lwb-filtergroup__title { font-size: var(--lwb-fs-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--lwb-ink-500); margin-bottom: var(--lwb-sp-2); }

.lotzwoo-b2b-shop .lwb-facet { padding-bottom: var(--lwb-sp-3); margin-bottom: var(--lwb-sp-3); border-bottom: 1px solid var(--lwb-ink-100); }
/* Die letzte Facette trennt nichts mehr ab — darunter kommt nur noch der Fuß
   der Spalte. Trennlinie und Abstand fallen deshalb weg, sonst steht eine
   Linie ohne Gegenüber und die Spalte endet mit einer Lücke. */
.lotzwoo-b2b-shop .lwb-facet:last-of-type {
  border-bottom: none;
  padding-bottom: 0;
  margin-bottom: 0;
}
.lotzwoo-b2b-shop .lwb-facet__head { display: flex; gap: var(--lwb-sp-2); align-items: center; }

.lotzwoo-b2b-shop .lwb-facet__toggle {
  flex: 1;
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: center;
  padding: 2px 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--lwb-ink-900);
  text-align: left;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-facet__chev { transition: transform 110ms ease; }
.lotzwoo-b2b-shop .lwb-facet__toggle[aria-expanded="true"] .lwb-facet__chev { transform: rotate(90deg); }
.lotzwoo-b2b-shop .lwb-facet__count { font-size: var(--lwb-fs-2xs); font-weight: 500; color: var(--lwb-ink-400); }
.lotzwoo-b2b-shop .lwb-facet__active { margin-left: auto; padding: 1px 7px; border-radius: var(--lwb-r-full); background: var(--lwb-brand-50); color: var(--lwb-brand-700); font-size: var(--lwb-fs-2xs); }
.lotzwoo-b2b-shop .lwb-facet__panel { margin-top: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-facet__items .lwb-checkline { margin-top: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-facet__items .lwb-checkline.is-child { padding-left: var(--lwb-sp-4); }

/* Gruppen mit Ober- und Untergruppen (seit 2026-09-15, bis zu drei Ebenen).
   Eine Zeile ist dort Zweig-Knopf plus Label; eingerueckt wird die Zeile,
   nicht das Label, damit Knopf und Kaestchen einer Ebene untereinander stehen.
   Flache Gruppen zeichnen weiter nur das Label und beruehren keine Regel hier.

   Der Knopf ist 24 px gross (WCAG 2.2, 2.5.8) und ragt oben und unten je 2 px
   aus der Textzeile, statt sie zu strecken. */
.lotzwoo-b2b-shop .lwb-facet__line { display: flex; gap: var(--lwb-sp-1); align-items: flex-start; margin-top: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-facet__line.is-depth-1 { padding-left: var(--lwb-sp-4); }
.lotzwoo-b2b-shop .lwb-facet__line.is-depth-2 { padding-left: calc(2 * var(--lwb-sp-4)); }
.lotzwoo-b2b-shop .lwb-facet__items .lwb-facet__line > .lwb-checkline { flex: 1 1 auto; min-width: 0; margin-top: 0; padding-left: 0; }
.lotzwoo-b2b-shop .lwb-facet__branch {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin-block: -2px;
  padding: 0;
  border: 0;
  border-radius: var(--lwb-r-sm);
  background: none;
  color: var(--lwb-ink-500);
  cursor: pointer;
}
.lotzwoo-b2b-shop .lwb-facet__branch:hover { color: var(--lwb-ink-900); }
.lotzwoo-b2b-shop .lwb-facet__branch.is-leaf { cursor: default; }
.lotzwoo-b2b-shop .lwb-facet__branch .lwb-ico { transition: transform 110ms ease; }
.lotzwoo-b2b-shop .lwb-facet__branch[aria-expanded="true"] .lwb-ico { transform: rotate(90deg); }
/* Unter einer gewaehlten Obergruppe: angehakt, aber nicht bedienbar. */
.lotzwoo-b2b-shop .lwb-facet__items .lwb-checkline:has(input:disabled) { cursor: default; color: var(--lwb-ink-500); }
.lotzwoo-b2b-shop .lwb-facet__more { margin-top: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-facet__empty { font-size: var(--lwb-fs-xs); color: var(--lwb-ink-400); padding: var(--lwb-sp-2) 0; }
.lotzwoo-b2b-shop .lwb-facet__searchbtn { border: 0; background: none; padding: 2px 6px; color: var(--lwb-ink-500); cursor: pointer; display: flex; align-items: center; }
.lotzwoo-b2b-shop .lwb-facet__search { margin-bottom: var(--lwb-sp-2); }

.lotzwoo-b2b-shop .lwb-chips { display: flex; gap: var(--lwb-sp-2); flex-wrap: wrap; }

.lotzwoo-b2b-shop .lwb-chip {
  display: inline-flex;
  gap: var(--lwb-sp-1);
  align-items: center;
  padding: 3px 4px 3px 10px;
  border-radius: var(--lwb-r-full);
  background: var(--lwb-ink-100);
  font-size: var(--lwb-fs-xs);
}

/* Das Kreuz ist jetzt das Lucide-x aus dem Sprite, nicht mehr aus zwei
   gedrehten Balken gebaut. Der Grund fuer die Balken war, dass das Zeichen
   "×" an den Metriken der Theme-Schrift haengt und rund einen Pixel zu tief
   sass; ein <svg> mit eigenem viewBox hat dieses Problem nicht, und mit dem
   Sprite kostet es keine zweite Pfadkopie. Die Zentrierung macht jetzt der
   Grid-Container, nicht mehr absolute Positionierung. */
.lotzwoo-b2b-shop .lwb-chip button {
  display: grid;
  place-items: center;
  border: 0;
  width: 18px;
  height: 18px;
  padding: 0;
  border-radius: var(--lwb-r-full);
  background: var(--lwb-ink-200);
  color: var(--lwb-ink-600);
  cursor: pointer;
}

/* ---------------- Toolbar ---------------- */

/* AP-64: die Werkzeugleiste klebt unter der Kontextleiste — dasselbe
   `--lwb-ctx-h`, das die Filterspalte liest (aus `b2b-ctxheight.js`,
   ResizeObserver; der Vorgabewert hier ist der Ausfallwert). Kein zweiter
   Zahlenwert für dieselbe Höhe. Der Schatten nennt die Kante, wenn sie
   über der Liste steht; der Hintergrund ist notwendig, sobald Zeilen
   darunter durchlaufen.

   **Die 8 px darueber sind kein Zierrat, sondern die Fuge** (2026-08-29,
   angefordert). Ohne sie stiess die Oberkante des Suchfeldes an die Unterkante
   der dunklen Kontextleiste, sobald die Leiste klebte — und der Streifen
   dahinter (`::before`, der geklebt 8 px nach oben tritt) legte sich
   stellenweise **ueber** sie. Der Klebeabstand traegt die Fuge jetzt, und der
   Streifen fuellt sie: er endet genau dort, wo die dunkle Leiste aufhoert.

   Unter 900 px ist es andersherum — dort ist der Abstand `0` und die Fuge
   steht als Polster **in** der Leiste (siehe die 900er-Stufe weiter unten).
   Der Grund ist der Streifen: unter 900 px laeuft er bis an die
   Fensterraender und beginnt bei `top: 0`, tritt also nicht heraus. Eine Fuge
   ueber ihm waere dort ein Streifen Seite zwischen zwei Leisten, die
   aneinanderstehen sollen. */
.lotzwoo-b2b-shop .lwb-toolbar {
  position: sticky;
  top: calc(var(--lwb-sticky-top) + var(--lwb-ctx-h, 52px) + var(--lwb-sp-2));
  z-index: var(--lwb-z-sticky);
  display: flex;
  gap: var(--lwb-sp-3);
  align-items: center;
  /* **Die Leiste bleibt einzeilig — auf jeder Breite** (2026-08-28,
     angefordert). Hier stand `wrap`, und unter 900 px war das Ergebnis eine
     zweite und stellenweise dritte Zeile, die mit der Leiste zusammen
     klebte und die halbe Liste verdeckte.

     `nowrap` allein waere nur die halbe Antwort: es macht aus dem Umbruch
     einen Ueberlauf. Die andere Haelfte ist `b2b-toolbarfit.js` — es gibt
     ab, was nicht mehr hineinpasst, an `.lwb-sidebar__aus` in der
     Filterspalte. Ohne das Skript schrumpfen die Elemente stattdessen; eng,
     aber in einer Zeile und ohne waagrechten Ueberlauf, weil das Suchfeld
     `min-width: 0` traegt und als einziges wachsen und schrumpfen darf. */
  flex-wrap: nowrap;
  margin-bottom: var(--lwb-sp-3);
  /* Oben kein Polster: im Ruhezustand steht die Leiste direkt unter der
     Kontextleiste, und ein Streifen Weiss dazwischen liest sich als Fuge, die
     es nicht gibt. Unten bleibt es — es traegt den Abstand zur ersten Zeile.

     **Und es bleibt in jedem Zustand dasselbe.** Bis zum 2026-08-29 kam es
     geklebt auf allen vier Seiten zurueck; seither traegt das der gemalte
     Streifen dahinter (`::before`, siehe unten), und dieser Kasten aendert
     seine Masse nie. */
  padding: 0 0 var(--lwb-sp-2) 0;
  background: var(--lwb-surface);
  box-shadow: 0 8px 12px -10px rgba(20, 15, 10, .3);
  transition: box-shadow .3s ease;
}

/* **Geklebt bekommt sie ein Polster ringsum** (2026-08-26, angefordert) —
   **und seit dem 2026-08-29 bewegt sich dabei kein Kind.**

   Ungeklebt steht die Leiste in der Inhaltsspalte und fluchtet links mit den
   Zeilen darunter. Sobald sie klebt, ist ihr Grund eine eigene Flaeche vor der
   durchlaufenden Liste, und dann klebte der Inhalt an deren Kante. Die 8 px
   ringsum sind die Antwort darauf, und sie bleiben.

   **Was sich geaendert hat, ist der Weg dorthin.** Bis zum 2026-08-29 war es
   `padding`, und Polster ist eine Layout-Eigenschaft: die fuenf Bedienelemente
   rueckten beim Andocken um 8 px nach innen und beim Loesen wieder heraus. Der
   Auftraggeber hat es als Springen gemeldet, und das war es auch — eine
   Ueberblendung darauf macht aus dem Sprung nur eine Bewegung, die waehrend
   des Scrollens ruckelt, weil sie in jedem Bild neu umbricht.

   Jetzt waechst die **Flaeche**, nicht der Kasten: `::before` liegt hinter dem
   Inhalt (`z-index: -1`), traegt Grund und Schatten und tritt im Klebezustand
   8 px nach oben und zur Seite heraus. Dasselbe Bild, dieselben 8 px — und
   kein einziger Layoutwert, der sich aendert. Dieselbe Bauart wie die dunkle
   Flaeche der Kontextleiste im Basis-Theme: was der Kunde als Flaeche liest,
   muss nicht der Kasten sein, in dem der Inhalt steht.

   Unten tritt der Streifen **nicht** heraus (`bottom: 0`): die 8 px stehen
   dort schon als Polster der Leiste selbst, das sie auch ungeklebt traegt.

   `is-stuck` setzt `b2b-stickystate.js`. `position: sticky` hat keinen
   Zustand, den CSS abfragen koennte; die Begruendung, warum es nicht
   `@container scroll-state(stuck: top)` ist, steht dort. */
.lotzwoo-b2b-shop .lwb-toolbar::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background: var(--lwb-surface);
  box-shadow: 0 8px 12px -10px rgba(20, 15, 10, .3);
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s ease, inset .3s ease;
}

.lotzwoo-b2b-shop .lwb-toolbar.is-stuck::before {
  opacity: 1;
  inset: calc(-1 * var(--lwb-sp-2)) calc(-1 * var(--lwb-sp-2)) 0;
}

/* Der eigene Schatten der Leiste weicht dem des Streifens — sonst stuenden
   zwei uebereinander, und die Kante unter der Leiste waere doppelt so dunkel
   wie ueberall sonst. */
.lotzwoo-b2b-shop .lwb-toolbar.is-stuck { box-shadow: none; }

/* Wer Bewegung abbestellt hat, bekommt den Zustandswechsel ohne sie. Die
   Flaeche bleibt; es ist die Aussage, die Ueberblendung nur ihr Weg. */
@media (prefers-reduced-motion: reduce) {
  .lotzwoo-b2b-shop .lwb-toolbar,
  .lotzwoo-b2b-shop .lwb-toolbar::before { transition: none; }
}

/* ---------------- Die enge Leiste (2026-08-28) ----------------

   Unter 900 px verschwindet die Filterspalte aus dem Layout und der
   Filter-Knopf tritt an ihre Stelle. Das war bis hierher der ganze Umbau —
   und er reichte nicht: dieselben fuenf Bedienelemente standen weiter in einer
   Leiste, die auf 390 px ein Drittel so breit ist.

   **Wer bei knappem Platz nachgibt, ist eine Leiter mit vier Sprossen**, und
   `b2b-toolbarfit.js` steigt sie herunter, bis es passt:

     A  alles in der Leiste, mit Beschriftung
     B  Beschriftungen weg — Umschalter und Scan-Knopf tragen nur ihr Symbol
     C  die Sortierung geht in die Filterspalte
     D  der Umschalter geht hinterher, dort wieder **mit** Beschriftung

   **Die Reihenfolge ist der Auftrag vom 2026-08-29**, und sie ist eine
   Korrektur: bis dahin haing die Beschriftung an einer Medienstufe (900 px)
   und die Verdraengung an der Messung. Beim Schmalerziehen kam damit erst der
   Umschalter zweizeilig in die Spalte, dann sprang er als Symbolreihe in die
   Leiste zurueck, dann wieder in die Spalte. Drei Wechsel fuer eine Richtung.

   Eine Leiter kann das nicht: jede Sprosse gibt Breite frei, keine nimmt
   welche, und gestiegen wird nur, solange es noetig ist. Deshalb steht
   **Sprosse B nicht mehr in einer Medienstufe**, sondern in der Klasse
   `is-kompakt`, die dasselbe Skript setzt, das misst.

   Was das Skript **nicht** anfasst: das Suchfeld waechst und drueckt alles
   nach rechts (unten in der 900er-Stufe), und der Scan-Knopf bleibt in der
   Leiste — „den wuerde man nicht hinter ‚Filter' vermuten".

   Ohne Skript bleibt es bei Sprosse A: beschriftet, alles in der Leiste, und
   das Suchfeld schrumpft. Eng, aber einzeilig und ohne Ueberlauf.

   **Die Zahl, an der die Sprossen C und D haengen, steht hier.** `--lwb-suche-min` ist die
   Breite, unter die das Suchfeld nicht fallen soll — das Skript liest sie aus
   dem berechneten Stil und rechnet damit. Ein zweiter Zahlenwert im Skript
   waere die Zahl, die driftet. 200 px, weil darunter der Platzhalter
   („Artikel, Nummer oder Barcode …") nicht mehr genug Zeichen zeigt, um zu
   sagen, wonach hier gesucht wird. */
.lotzwoo-b2b-shop { --lwb-suche-min: 200px; }

/* **Und alles ausser dem Suchfeld gibt keine Breite her — auf jeder Breite.**
   Was schrumpfen darf, schrumpft, statt dass die Leiste abgibt: gemessen am
   2026-08-28 stand das Suchfeld bei 1000 px Fenster auf **33 px** und bei
   901 px lief das Dokument **50 px** waagrecht ueber. Mit `flex-wrap: wrap`
   war das ein Umbruch und fiel nicht auf; mit `nowrap` ist es ein Ueberlauf,
   und mit dieser Zeile ist es die Frage, die das Skript beantwortet.

   Der Abstandshalter ist ausgenommen: er *ist* die Elastizitaet der Leiste
   und traegt oberhalb 900 px das Suchfeld auf seine Breite. `b2b-toolbarfit.js`
   rechnet ihn deshalb mit null Breite, aber mit seiner Fuge. */
.lotzwoo-b2b-shop .lwb-toolbar > *:not(.lwb-searchfield):not(.lwb-spacer) { flex: none; }

/* **Und keine eigenen Aussenraender in der Leiste.**

   `.lwb-scantoggle` trug bis zum 2026-08-29 `margin-left: 8px` aus der Zeit
   vor der Fuge. Das war zweimal falsch: der Knopf stand 20 px von seinem
   linken Nachbarn und 12 px von seinem rechten, und — teurer —
   `b2b-toolbarfit.js` misst Kastenbreiten, in denen Aussenraender nicht
   stecken. Am 2026-08-28 bei 1200 px gemessen war das der Unterschied
   zwischen „passt" (856 von 858) und dem, was dastand: ein Suchfeld von
   **194 px** unter einer Mindestbreite von 200.

   Der Rand ist seit dem 2026-08-29 aus der Klasse selbst entfernt (vom
   Auftraggeber angefordert), und das Skript zaehlt Raender ohnehin mit. Diese
   Zeile bleibt als Riegel: der Abstand in dieser Reihe ist die Fuge des
   Flex-Behaelters, und zwar nur sie. Wer hier den naechsten Aussenrand setzt,
   bekommt ihn nicht — und muss nicht erst eine Zahl messen, um zu merken,
   dass er falsch war. */
.lotzwoo-b2b-shop .lwb-toolbar > * { margin-inline: 0; }

/* **Sprosse B: die Beschriftungen gehen, die Symbole bleiben.**

   Derselbe Griff wie an `.lwb-searchgo__wort` unter 560 px: verborgen, nicht
   entfernt — der zugaengliche Name bleibt vollstaendig, und wer mit der
   Tastatur oder einem Screenreader arbeitet, merkt von dieser Sprosse nichts.

   **`is-kompakt` und keine Medienstufe.** Die Sprosse gehoert zur Leiter, und
   die Leiter gehoert dem Skript, das misst — eine Breitengrenze daneben ergibt
   die Sprungfolge, die der Auftraggeber am 2026-08-29 gemeldet hat.

   Und **nur in der Leiste**: im Ausweichfach steht der Umschalter mit
   Beschriftung, weil dort die Breite da ist und weil in einer Schublade voller
   beschrifteter Filter drei nackte Symbole der Fremdkoerper waeren. Genau das
   ist Sprosse D. */
.lotzwoo-b2b-shop .lwb-toolbar.is-kompakt .lwb-ctlwort {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Ohne Wort ist die Fuge zwischen Symbol und Wort eine Fuge zu nichts. */
.lotzwoo-b2b-shop .lwb-toolbar.is-kompakt .lwb-viewswitch button,
.lotzwoo-b2b-shop .lwb-toolbar.is-kompakt .lwb-scantoggle { gap: 0; }

@media (max-width: 900px) {
  /* Der Klebeabstand ohne die Fuge, dafuer als Polster **in** der Leiste —
     die Begruendung steht oben bei `top`. Waagrecht bleibt es `0`: dort
     fluchtet der Inhalt mit den Zeilen darunter. */
  .lotzwoo-b2b-shop .lwb-toolbar {
    top: calc(var(--lwb-sticky-top) + var(--lwb-ctx-h, 52px));
    padding: var(--lwb-sp-2) 0;
  }

  /* Das Suchfeld waechst. Der Abstandshalter hat ausgedient: solange er und das
     Suchfeld beide `flex-grow: 1` tragen, teilen sie sich den freien Platz
     und das Feld bekommt die Haelfte. Gefordert ist, dass es waechst und
     alles andere nach rechts geht — also waechst genau eines. */
  .lotzwoo-b2b-shop .lwb-toolbar .lwb-spacer { display: none; }

  .lotzwoo-b2b-shop .lwb-toolbar .lwb-searchfield {
    flex: 1 1 var(--lwb-suche-min);
  }

  /* **Geklebt laeuft die Leiste bis an beide Fensterraender** (2026-08-28,
     angefordert). Ueber 900 px ist das Andocken ein Polsterwechsel (siehe
     oben); hier waere derselbe Wechsel kaum zu sehen — die Leiste ist ohnehin
     fast so breit wie das Fenster. Sichtbar ist das andere: sie loest sich
     von der Inhaltsspalte, wird zur Flaeche des Geraets und gibt dabei ihre
     Rundungen auf. Eine gerundete Ecke am Fensterrand zeigt einen Streifen
     Seite, unter dem nichts liegt — dasselbe Argument wie an der
     Bestellleiste unten, und deshalb dieselbe Antwort.

     `margin-inline` zieht die Leiste aus ihrer Spalte
     heraus, ohne dass ein Vorfahr etwas davon wissen muss. Das Polster
     ersetzt danach die Seitenraender der Spalte, damit der Inhalt nicht an
     der Geraetekante klebt.

     **Die Breite ist `--lwb-vw` und ausdruecklich nicht `100vw`.** `100vw`
     misst den Anzeigebereich einschliesslich eines klassischen Scrollbalkens;
     was eine Flaeche einnehmen darf, ist `documentElement.clientWidth`. Am
     2026-08-28 gemessen: Fenster 390, davon 375 nutzbar — die volle Breite
     ergab 15 px waagrechten Ueberlauf am Dokument, und drei Nachweise haben
     ihn gemeldet. `b2b-stickystate.js` schreibt die Zahl bei jedem
     Groessenwechsel; der Rueckfall `100vw` ist der Zustand ohne Skript, und
     ohne Skript gibt es auch kein `is-stuck`.

     `is-stuck` setzt `b2b-stickystate.js`; faellt es aus, bleibt die Leiste
     in ihrer Spalte — der Zustand von vorher. */
  /* **Hier laeuft der Streifen bis an beide Fensterraender** (2026-08-28,
     angefordert). Ueber 900 px tritt er 8 px heraus (siehe oben); unter 900 px
     waere derselbe Wechsel kaum zu sehen — die Leiste ist ohnehin fast so
     breit wie das Fenster. Sichtbar ist das andere: sie loest sich von der
     Inhaltsspalte und wird zur Flaeche des Geraets.

     Es ist derselbe Streifen und derselbe Zustand, nur mit anderen Massen.
     Der Kasten bleibt auch hier unberuehrt, und genau darum geht es: bis zum
     2026-08-29 stand hier `width: 100vw` **an der Leiste selbst**, mit
     negativem Aussenrand und eigenem Polster — und ihr Inhalt sprang beim
     Andocken um die halbe Fensterbreite nach aussen.

     **Die Breite ist `--lwb-vw` und ausdruecklich nicht `100vw`.** `100vw`
     misst den Anzeigebereich einschliesslich eines klassischen Scrollbalkens;
     was eine Flaeche einnehmen darf, ist `documentElement.clientWidth`. Am
     2026-08-28 gemessen: Fenster 390, davon 375 nutzbar — die volle Breite
     ergab 15 px waagrechten Ueberlauf am Dokument, und drei Nachweise haben
     ihn gemeldet. `b2b-stickystate.js` schreibt die Zahl bei jedem
     Groessenwechsel; der Rueckfall `100vw` ist der Zustand ohne Skript, und
     ohne Skript gibt es auch kein `is-stuck`. */
  .lotzwoo-b2b-shop .lwb-toolbar.is-stuck::before {
    inset: 0 auto 0 50%;
    width: var(--lwb-vw, 100vw);
    transform: translateX(-50%);
  }
}

/* ---------------- Eine Hoehe fuer die Werkzeugleiste (AP-80, B) ----------------

   **Vier Elemente trugen vier Hoehen.** Am 2026-08-24 gemessen, an Klon und
   Bank zeichengleich, und auf 1440 wie auf 390 px dieselben Zahlen:

     Suchfeld              39,0    Polster 8/8    14 px / 21 px
     Ansichtsumschalter    37,5    Polster 2/2    14 px / 21 px  (Knopf 6/6, 13 px)
     Scan-Knopf            33,5    Polster 6/6    13 px / 19,5 px
     Sortier-Select        36,0    Polster 8/8    14 px / **normal**

   Spanne 5,5 px, dazu zwei Schriftgroessen nebeneinander in einer Reihe. Weil
   die Leiste zentriert ausrichtet, stimmt weder Ober- noch Unterkante.

   **Warum eine gesetzte Hoehe und keine Polsterrechnung.** Das Select traegt
   `line-height: normal` — der Browser bestimmt seine Innenhoehe. Genau deshalb
   stand es bei 36 und nicht bei 38, obwohl es dieselbe Regel wie das Suchfeld
   trug (`.lwb-input, .lwb-select` weiter oben). Polster holt das nicht ein;
   es waere Raten mit Nachkommastellen an einer Zahl, die dem Browser gehoert.

   **Warum unter `.lwb-toolbar` und nicht an `.lwb-input`.** Dieselbe Klasse
   traegt das Facettenfeld in der Seitenspalte (`b2b-shop.js`); 40 px waeren
   dort eine fremde Entscheidung dieses Auftrags.

   `--lwb-control-h` steht in `b2b-tokens.css` und sagt dort, warum es 40 ist. */
/* **Der Filter-Knopf ist seit dem 2026-08-29 der fuenfte** (angefordert). Er
   stand bis dahin oben im Kopf und war deshalb nicht in dieser Liste; seit er
   in der Leiste neben dem Suchfeld sitzt, ist er Teil derselben Reihe und
   traegt dieselbe Zahl. Gemessen brachte er 38,5 px mit — sein Polster von
   9/9 plus Schrift, also fast, aber nicht ganz.

   `.lwb-toolbar .lwb-btn` und nicht sein Datenattribut: die Regel gilt der
   **Reihe**, nicht diesem einen Knopf. Wer morgen einen zweiten dort
   hinstellt, soll ihn nicht suchen muessen. Der Suchknopf im Feld
   (`.lwb-searchgo`) traegt `.lwb-btn` ausdruecklich nicht — er ist kleiner als
   das Feld, in dem er sitzt, und das ist so gewollt. */
.lotzwoo-b2b-shop .lwb-toolbar .lwb-input,
.lotzwoo-b2b-shop .lwb-toolbar .lwb-select,
.lotzwoo-b2b-shop .lwb-toolbar .lwb-btn,
.lotzwoo-b2b-shop .lwb-viewswitch,
.lotzwoo-b2b-shop .lwb-scantoggle {
  box-sizing: border-box;
  height: var(--lwb-control-h);
  min-height: var(--lwb-control-h);
}

/* Der Umschalter ist ein Rahmen um Knoepfe: die Hoehe sitzt aussen, die
   Knoepfe fuellen sie. Ohne `stretch` schwimmen sie darin, und der Grund des
   gedrueckten Reiters bekommt eine Kante, die niemand gezeichnet hat. */
.lotzwoo-b2b-shop .lwb-viewswitch button { align-self: stretch; }

.lotzwoo-b2b-shop .lwb-viewswitch { display: inline-flex; padding: 2px; border: 1px solid var(--lwb-ink-200); border-radius: var(--lwb-r-md); background: var(--lwb-surface); }

/* Icon und Beschriftung stehen nebeneinander und werden zueinander
   zentriert — nicht auf der Schriftlinie ausgerichtet. Ein Icon auf der
   Grundlinie sitzt bei jeder Schriftgroesse anders. */
.lotzwoo-b2b-shop .lwb-viewswitch button {
  display: inline-flex;
  align-items: center;
  gap: var(--lwb-sp-2);
  border: 0;
  padding: 6px 12px;
  border-radius: var(--lwb-r-sm);
  background: none;
  font: inherit;
  /* `md` statt `sm` seit AP-80 (B): in einer Reihe standen 13 px neben den
     14 px des Suchfeldes. Fluchtende Kanten mit zwei Schriftgroessen darin
     bleiben optisch uneinheitlich — die Hoehe allein reicht nicht. */
  font-size: var(--lwb-fs-md);
  font-weight: 600;
  color: var(--lwb-ink-500);
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-viewswitch button[aria-pressed="true"] { background: var(--lwb-ink-900); color: var(--lwb-surface); }
/* `lwb-sortfield` entfiel mit AP-64 — das sichtbare Label „Sortierung“
   weicht dem Platz des Suchfeldes; der Name des Selects lebt als
   `aria-label` weiter. */

/* ---------------- Table view (FR-PROD-04 default) ---------------- */

/* Vordergrund-Rolle: die Tabelle ist die Arbeitsfläche der Seite.

   **Ohne Schlagschatten** (2026-08-29, angefordert). Rahmen, Rundung und
   Vordergrundfarbe bleiben — sie sagen dasselbe, ohne die Flaeche vom Grund
   abzuheben. Die Filterspalte behaelt ihren: sie steht **neben** der Liste und
   nicht darin, und dort ist das Abheben die Aussage. */
.lotzwoo-b2b-shop .lwb-table {
  border: 1px solid var(--lwb-front-border);
  border-radius: var(--lwb-r-lg);
  background: var(--lwb-front);
  overflow: hidden;
}

/* Stepper (100) + Fuge (8) + Knopf (120), am 2026-08-27 bei 1440 px gemessen.
   Sie steht hier und nicht in `b2b-tokens.css`, weil sie kein Entwurfswert ist,
   sondern die Summe zweier Bedienelemente — wer eines davon aendert, aendert
   sie mit, und dann soll sie in Sichtweite stehen. */
.lotzwoo-b2b-shop { --lwb-akt-breite: 228px; }

.lotzwoo-b2b-shop .lwb-table__head,
.lotzwoo-b2b-shop .lwb-row {
  display: grid;
  /* **Die letzte Spalte ist so breit wie Stepper und Knopf nebeneinander.**
     Bis zum 2026-08-27 stand hier `200px`, fest. Stepper (100) und Knopf (120)
     brauchen mit der Fuge 228 — die Zelle war also auf **jeder** Desktop-Breite
     zu schmal, und `flex-wrap` unten hat brav gestapelt: bei 2560 px, wo rechts
     620 px leer standen. Umgekehrt sass das Paar bei 640 px nebeneinander, weil
     die Zeile dort auf zwei Spalten faellt und die Zelle 474 px bekommt.
     Gemessen an genau diesen Breiten.
     `minmax` mit einem Boden laesst die Spalte wieder schrumpfen, wenn die
     Zeile eng wird — und **dann** stapelt `flex-wrap`, weil dann wirklich kein
     Platz ist. Der Boden ist die Breite des Knopfes allein: schmaler duerfte
     die Spalte ihn abschneiden.

     **Eine feste Zahl und ausdruecklich nicht `max-content`.** Bis zum
     2026-08-27 stand hier `max-content`, und das war falsch: die Kopfzeile und
     jede Datenzeile sind **eigene Grid-Container**. `max-content` rechnet also
     je Container — im Kopf ueber „Menge" (unter dem Boden, also 120), in der
     Zeile ueber Stepper und Knopf (228). Die 1fr-Spalte schluckt die Differenz,
     und damit standen im Kopf alle Spalten dahinter **107 px weiter rechts** als
     ihr Inhalt. Vor AP-88 stand dort `200px`, inhaltsunabhaengig, deshalb ist es
     nie aufgefallen. Eine Zahl rechnet in beiden Containern gleich.

     Der Preis dafuer steht in `--lwb-akt-breite`: wird der Knopf beschriftet
     umbenannt oder uebersetzt, muss die Zahl mit. Deshalb misst
     `ap70-flaechen` seit dem 2026-08-27, dass Kopf und Zeile fluchten. */
  grid-template-columns: 56px 44px minmax(150px, 1fr) 120px 150px 140px minmax(120px, var(--lwb-akt-breite));
  gap: var(--lwb-sp-3);
  align-items: start;
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
}

.lotzwoo-b2b-shop .lwb-table__head {
  background: var(--lwb-ink-50);
  border-bottom: 1px solid var(--lwb-ink-200);
  font-size: var(--lwb-fs-2xs);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--lwb-ink-500);
  font-weight: 600;
}

.lotzwoo-b2b-shop .lwb-row { border-bottom: 1px solid var(--lwb-ink-100); }
.lotzwoo-b2b-shop .lwb-row:last-child { border-bottom: 0; }
.lotzwoo-b2b-shop .lwb-row:hover { background: var(--lwb-ink-50); }
.lotzwoo-b2b-shop .lwb-row.is-blocked { background: repeating-linear-gradient(135deg, transparent, transparent 8px, rgba(180, 35, 24, .035) 8px, rgba(180, 35, 24, .035) 16px); }
.lotzwoo-b2b-shop .lwb-row__name { font-weight: 600; color: var(--lwb-ink-900); }
.lotzwoo-b2b-shop .lwb-row__variant { margin-left: 6px; padding: 1px 6px; border-radius: var(--lwb-r-sm); background: var(--lwb-ink-100); font-size: var(--lwb-fs-2xs); font-weight: 600; color: var(--lwb-ink-600); }
.lotzwoo-b2b-shop .lwb-row__sku { font-size: var(--lwb-fs-xs); color: var(--lwb-ink-500); font-variant-numeric: tabular-nums; }
.lotzwoo-b2b-shop .lwb-row__meta { font-size: var(--lwb-fs-2xs); color: var(--lwb-ink-400); }

/* Der Daumennagel der Zeile.
   `aspect-ratio` statt einer festen Hoehe: die Zeile waechst mit ihrem
   Textblock, das Bild soll ihr dabei nicht folgen. Es bleibt quadratisch und
   oben, und `cover` beschneidet — ein Lieferantenfoto im Querformat wird
   damit zum Ausschnitt statt zum Streifen mit Rand. */
.lotzwoo-b2b-shop .lwb-row__img {
  width: 56px;
  aspect-ratio: 1 / 1;
  border-radius: var(--lwb-r-sm);
  border: 1px solid var(--lwb-ink-100);
  background: var(--lwb-ink-50);
  overflow: hidden;
}

.lotzwoo-b2b-shop .lwb-row__img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Die Kopfzeile trägt fünf Zellen über sieben Spalten — Bild, Stern und
   Artikel teilen sich eine Überschrift. Gezählt wird von der ersten Spalte,
   nicht von der ersten Zelle: `grid-column` setzt die Zelle dorthin, wo ihre
   Spalte steht, und die vier danach folgen von selbst. */
.lotzwoo-b2b-shop .lwb-table__head .lwb-head--artikel { grid-column: 1 / 4; }

/* **`.lwb-head` heisst in dieser Datei zweierlei, und das hat gekostet.**

   Oben im Dokument ist `.lwb-head` der Seitenkopf — Ueberschrift, Zaehler,
   Kontextsatz — und traegt `margin: var(--lwb-sp-6) 0 var(--lwb-sp-3)`. Hier
   unten ist `.lwb-head` eine **Spaltenueberschrift** der Tabelle
   (`b2b-shop.js:1757`), und dieselbe Regel traf sie mit: 48 px ueber und 12 px
   unter jeder der fuenf Zellen, in einem Grid, das seine Zeilenhoehe daraus
   zieht. Am 2026-08-29 vom Auftraggeber gemeldet und hier zurueckgenommen.

   Die Ruecknahme ist die kleine Loesung. Die grosse hiesse, eine der beiden
   Klassen umzubenennen — der Seitenkopf ist der aeltere Name, die
   Spaltenueberschrift die haeufigere —, und das ist ein eigener Auftrag: die
   Klasse steht in `b2b-shop.js`, in dieser Datei und in drei Browser-Nachweisen.
   Solange sie beides heisst, gehoert diese Zeile hierher.

   Und die Ausrichtung darunter ist eine Spaltenfrage, keine Zellenfrage: Kopf
   und Inhalt tragen dieselbe Kante, sonst steht die Ueberschrift woanders als
   das, was sie benennt. Preis rechts, alles andere links. */
.lotzwoo-b2b-shop .lwb-table__head.lwb-row .lwb-head { margin: 0; }
.lotzwoo-b2b-shop .lwb-table__head .lwb-head { text-align: left; }
/* `justify-content` neben `text-align`, weil die Zelle beides sein kann: eine
   Textzelle im Grid (dann traegt `text-align`) und ein Flex-Kasten, sobald
   etwas neben dem Wort steht (dann traegt es nicht). Zwei Zeilen fuer eine
   Kante, damit sie nicht davon abhaengt, was gerade in der Zelle liegt. */
.lotzwoo-b2b-shop .lwb-table__head .lwb-head--price {
  text-align: right;
  justify-content: right;
}

.lotzwoo-b2b-shop .lwb-row__price { text-align: right; }
.lotzwoo-b2b-shop .lwb-row__pack,
.lotzwoo-b2b-shop .lwb-row__avail { text-align: left; }

/* Links wie die Überschrift darüber. Sichtbar wird das erst, wo die Spalte
   breiter ist als ihr Inhalt — auf den Desktop-Breiten ist sie seit AP-88
   genau so breit wie Stepper und Knopf zusammen, dort bewegt sich nichts. */
.lotzwoo-b2b-shop .lwb-row__actions { display: flex; gap: var(--lwb-sp-2); align-items: center; justify-content: flex-start; flex-wrap: wrap; }
.lotzwoo-b2b-shop .lwb-pack__unit { font-size: var(--lwb-fs-sm); font-weight: 600; }

/* `position: relative` ist seit AP-70 kein Zierrat, sondern die Messung A1:
   der Kreis (`.lwb-favstar__count`) ist absolut positioniert, und ohne diese
   Zeile war sein naechster positionierter Vorfahr `.lwb-favctl` — Stern (30)
   + Fuge (2) + Griff (24). `right: -6px` bezog sich damit auf die rechte
   obere Ecke des **Paares**, und der Kreis sass ueber dem Chevron. Faellt der
   Griff weg, saesse er zufaellig richtig; wer danach etwas neben den Stern
   stellt, haette den Befund zurueck. */
.lotzwoo-b2b-shop .lwb-favstar {
  position: relative;
  border: 0;
  width: 30px;
  height: 30px;
  border-radius: var(--lwb-r-full);
  background: none;
  color: var(--lwb-ink-300);
  display: grid;
  place-items: center;
  padding: 0;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-favstar:hover { background: var(--lwb-ink-100); color: var(--lwb-warn-500); }
/* Zwei Schreibweisen fuer denselben Zustand, und das ist Absicht: im Modus
   `single` traegt der Stern weiter `aria-pressed` (er schaltet), im Modus
   `lists` seit AP-70 nur noch `is-on` (er oeffnet). Wer die Farbe allein am
   Attribut haengen laesst, verliert sie im Listenmodus — und keine Pruefung
   wird davon rot. */
.lotzwoo-b2b-shop .lwb-favstar[aria-pressed="true"],
.lotzwoo-b2b-shop .lwb-favstar.is-on { color: #e0a800; }
.lotzwoo-b2b-shop .lwb-favstar[disabled] { opacity: .5; cursor: progress; }

/* =========================================================================
   AP-57 · Stern mit Griff und Aufklapper (nur Modus `lists`)
   ========================================================================= */

/* Der Bedienelement-Container haelt nur noch **einen** Knopf: AP-70 hat den
   Griff genommen, der Stern oeffnet selbst. Er ist ausdruecklich **kein**
   Bezugsrahmen mehr — der Kreis ankert am Stern (siehe oben), der Aufklapper
   steht `fixed`. Bis zum 2026-08-20 stand hier `position: relative` mit der
   Begruendung, das loese das Abschneiden in der letzten Zeile. Das war
   falsch: `overflow: hidden` an `.lwb-table` beschneidet jeden absolut
   positionierten Nachkommen, gleich woran er ankert. */
.lotzwoo-b2b-shop .lwb-favctl {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
}

/* Die Zahl am Stern: kein eigenes Ziel, sie reitet auf der Sternflaeche —
   seit AP-70 auch tatsaechlich, nicht nur laut Kommentar. */
.lotzwoo-b2b-shop .lwb-favstar__count {
  position: absolute;
  top: -4px;
  right: -6px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: var(--lwb-r-full);
  background: var(--lwb-warn-500, #e0a800);
  color: var(--lwb-paper, #fff);
  font-size: 10px;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
  pointer-events: none;
}

/* Der Aufklapper steht `fixed`, und die Koordinaten rechnet das Skript beim
   Oeffnen (`positionMenu()`).

   **Messprotokoll, 2026-08-20 (AP-70, A2).** Hier stand bis dahin
   `position: absolute` mit der Begruendung, die Verankerung am Container
   halte ihn aus dem Zeilenueberlauf heraus. Sie tut es nicht.
   `.lwb-table` (`overflow: hidden`) und `.lwb-card` (dito) beschneiden
   **jeden** absolut positionierten Nachkommen, gleich woran er ankert — der
   Anker entscheidet, *wo* er landet, nicht *ob* er sichtbar ist. In der
   letzten Zeile lag er unter der Unterkante der Tabelle und wurde genau dort
   geschnitten.

   `fixed` entkommt, solange kein Vorfahre `transform`, `filter`, `contain`
   oder `container-type` setzt — am 2026-08-20 fuer diese Flaeche
   gegengezaehlt. `top`/`left` setzt das Skript; die Werte hier sind nur der
   Ausgangspunkt, damit die Breite messbar ist, bevor gerechnet wird. */
.lotzwoo-b2b-shop .lwb-favmenu {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 40;
  min-width: 180px;
  padding: 4px;
  border-radius: var(--lwb-r-md, 8px);
  background: var(--lwb-paper, #fff);
  box-shadow: var(--lwb-shadow-3, 0 8px 24px rgba(15, 23, 42, .18));
  border: 1px solid var(--lwb-line-200, #e2e8f0);
  display: flex;
  flex-direction: column;
}

/* Die Sonderregel fuer die Kachel entfiel mit AP-70: `top` kommt jetzt aus
   der gerechneten Position und nicht mehr aus dem Stylesheet, in beiden
   Ansichten aus derselben Zeile Code. */

.lotzwoo-b2b-shop .lwb-favmenu__item {
  border: 0;
  background: none;
  padding: 7px 10px;
  display: flex;
  align-items: center;
  gap: 9px;
  border-radius: var(--lwb-r-sm, 6px);
  color: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-favmenu__item:hover { background: var(--lwb-ink-100); }
.lotzwoo-b2b-shop .lwb-favmenu__item:focus-visible { box-shadow: var(--lwb-focus); outline: none; }

/* Die Kästchen der Menüeinträge — checkbox-optisch, ohne eigene Fläche zu
   sein: die 24 px gehören dem Eintrag als ganzem. */
.lotzwoo-b2b-shop .lwb-favmenu__box {
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  border: 1.5px solid var(--lwb-ink-300, #94a3b8);
  border-radius: 4px;
  position: relative;
}

.lotzwoo-b2b-shop .lwb-favmenu__item[aria-checked="true"] .lwb-favmenu__box {
  background: var(--lwb-warn-500, #e0a800);
  border-color: var(--lwb-warn-500, #e0a800);
}

.lotzwoo-b2b-shop .lwb-favmenu__item[aria-checked="true"] .lwb-favmenu__box::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--lwb-paper, #fff);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* ---------------- Prices, stock ---------------- */

.lotzwoo-b2b-shop .lwb-price { font-size: var(--lwb-fs-base); font-weight: 700; color: var(--lwb-ink-900); font-variant-numeric: tabular-nums; }
.lotzwoo-b2b-shop .lwb-price__unit { font-size: var(--lwb-fs-2xs); font-weight: 500; color: var(--lwb-ink-500); }
.lotzwoo-b2b-shop .lwb-price__base { font-size: var(--lwb-fs-2xs); color: var(--lwb-ink-500); }
.lotzwoo-b2b-shop .lwb-price__list { font-size: var(--lwb-fs-2xs); color: var(--lwb-ink-400); text-decoration: line-through; }
.lotzwoo-b2b-shop .lwb-tiers { margin: var(--lwb-sp-1) 0 0; padding: 0; list-style: none; font-size: var(--lwb-fs-2xs); color: var(--lwb-ink-500); }

.lotzwoo-b2b-shop .lwb-stock { display: inline-flex; gap: 6px; align-items: center; font-size: var(--lwb-fs-xs); }
.lotzwoo-b2b-shop .lwb-dot { width: 8px; height: 8px; border-radius: var(--lwb-r-full); background: var(--lwb-ink-300); }
.lotzwoo-b2b-shop .lwb-dot--ok { background: var(--lwb-ok-500); }
.lotzwoo-b2b-shop .lwb-dot--warn { background: var(--lwb-warn-500); }
.lotzwoo-b2b-shop .lwb-dot--err { background: var(--lwb-err-500); }
.lotzwoo-b2b-shop .lwb-reason { margin-top: 2px; font-size: var(--lwb-fs-2xs); color: var(--lwb-err-700); }

/* ---------------- Pills (FR-PROD-10) ---------------- */

.lotzwoo-b2b-shop .lwb-pills { display: flex; gap: var(--lwb-sp-1); align-items: center; flex-wrap: wrap; margin-top: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-pills__label { font-size: var(--lwb-fs-2xs); color: var(--lwb-ink-400); margin-right: 2px; }

/* **Die Pillen brechen gemeinsam um** (2026-08-29, angefordert).

   Vorher lagen Beschriftung und Pillen als Geschwister in einem Flex-Kasten,
   und `flex-wrap` sieht nur Kaesten, keine Zusammengehoerigkeit: bei knapper
   Zeile blieb „Gebindegroesse 1x" stehen und „6x" rutschte allein in die
   naechste — zwei Zeilen fuer eine Auswahl, und die Beschriftung stand neben
   der Haelfte dessen, was sie benennt.

   Ein Kasten um die Knoepfe macht sie zu **einem** Flex-Kind: passt er nicht
   neben die Beschriftung, geht er ganz in die naechste Zeile. Umbrechen darf
   er darin weiterhin — bei sechs Gebinden auf 320 px muss er. */
.lotzwoo-b2b-shop .lwb-pills__gruppe {
  display: flex;
  gap: var(--lwb-sp-1);
  align-items: center;
  flex-wrap: wrap;
}

.lotzwoo-b2b-shop .lwb-pill {
  border: 1px solid var(--lwb-ink-200);
  padding: 3px 10px;
  border-radius: var(--lwb-r-full);
  background: var(--lwb-surface);
  font: inherit;
  font-size: var(--lwb-fs-xs);
  font-weight: 600;
  color: var(--lwb-ink-600);
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-pill:hover { border-color: var(--lwb-brand-300); }
.lotzwoo-b2b-shop .lwb-pill[aria-pressed="true"] { background: var(--lwb-brand-500); border-color: var(--lwb-brand-500); color: var(--lwb-surface); }
.lotzwoo-b2b-shop .lwb-pill[disabled] { opacity: .45; cursor: not-allowed; text-decoration: line-through; }

/* ---------------- Quantity stepper ---------------- */

.lotzwoo-b2b-shop .lwb-qty { display: inline-flex; border: 1px solid var(--lwb-ink-200); border-radius: var(--lwb-r-md); background: var(--lwb-surface); overflow: hidden; }

.lotzwoo-b2b-shop .lwb-qty button {
  border: 0;
  width: 32px;
  background: var(--lwb-ink-50);
  color: var(--lwb-ink-700);
  font: inherit;
  font-size: var(--lwb-fs-base);
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-qty button:hover { background: var(--lwb-ink-100); }

.lotzwoo-b2b-shop .lwb-qty input {
  width: 54px;
  border: 0;
  border-inline: 1px solid var(--lwb-ink-200);
  padding: 7px 4px;
  text-align: center;
  font: inherit;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
}

.lotzwoo-b2b-shop .lwb-qty input::-webkit-outer-spin-button,
.lotzwoo-b2b-shop .lwb-qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.lotzwoo-b2b-shop .lwb-qty--sm input { width: 46px; padding: 4px 2px; font-size: var(--lwb-fs-sm); }
.lotzwoo-b2b-shop .lwb-qty--sm button { width: 26px; font-size: var(--lwb-fs-sm); }

/* ---------------- Grid view ---------------- */

.lotzwoo-b2b-shop .lwb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--lwb-sp-4); }

/* **Ohne Schlagschatten** (2026-08-29, angefordert) — dieselbe Entscheidung
   wie an der Tabelle, und aus demselben Grund: die Karte ist die Zeile in
   einer anderen Form, nicht eine Flaeche vor der Seite. Der Rahmen traegt die
   Abgrenzung.

   **Grund `--lwb-front`** (2026-09-11, angefordert). Hier stand
   `--lwb-surface` — auf Bersta Creme, derselbe Ton wie der Seitengrund. Nur
   die Farbe der Rolle, nicht ihr Schatten: der bleibt aus dem Grund oben weg. */
.lotzwoo-b2b-shop .lwb-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-lg);
  background: var(--lwb-front);
  overflow: hidden;
}

.lotzwoo-b2b-shop .lwb-card.is-blocked { opacity: .82; }
.lotzwoo-b2b-shop .lwb-card__head { display: flex; gap: var(--lwb-sp-2); align-items: flex-start; padding: var(--lwb-sp-3) var(--lwb-sp-3) 0; }
.lotzwoo-b2b-shop .lwb-card__flags { display: flex; gap: var(--lwb-sp-1); flex-wrap: wrap; }

/* Die Kachel der Karte — klassisch oben, quadratisch, beschnitten.
   Die Karte traegt `overflow: hidden`, die Kachel bekommt ihre obere Rundung
   also von der Karte und braucht keine eigene. */
.lotzwoo-b2b-shop .lwb-card__media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--lwb-ink-50);
  border-bottom: 1px solid var(--lwb-ink-100);
}

.lotzwoo-b2b-shop .lwb-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Der Kopf sitzt im Bild statt darueber: Stern links unten, Abzeichen rechts
   daneben. `bottom` und nicht `top`, weil die obere Kante die Stelle ist, an
   der ein Produktfoto am ehesten etwas zeigt. */
.lotzwoo-b2b-shop .lwb-card__media .lwb-card__head {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--lwb-sp-2);
  align-items: flex-end;
  justify-content: space-between;
}

/* Der feine Rand ist der Punkt: auf dem WooCommerce-Platzhalter — hellgrau
   auf hellgrau — verschwand die weisse Scheibe sonst vollstaendig. Die Kette
   ist eine Klasse laenger als `.lwb-favstar` weiter oben, die `border: 0`
   setzt; deshalb gewinnt sie ohne `!important`. */
.lotzwoo-b2b-shop .lwb-card__media .lwb-favstar {
  width: 34px;
  height: 34px;
  background: rgba(255, 255, 255, .92);
  border: 1px solid var(--lwb-ink-200);
  box-shadow: var(--lwb-sh-sm);
}

.lotzwoo-b2b-shop .lwb-card__media .lwb-favstar:hover { background: #fff; }
.lotzwoo-b2b-shop .lwb-card__body { flex: 1; padding: var(--lwb-sp-3); display: flex; flex-direction: column; gap: var(--lwb-sp-1); }
.lotzwoo-b2b-shop .lwb-card__name { font-weight: 600; color: var(--lwb-ink-900); }
.lotzwoo-b2b-shop .lwb-card__foot { display: flex; gap: var(--lwb-sp-2); align-items: center; padding: var(--lwb-sp-3); border-top: 1px solid var(--lwb-ink-100); background: var(--lwb-ink-50); }
.lotzwoo-b2b-shop .lwb-card__foot .lwb-btn { flex: 1; }

/* ---------------- Matrix view ---------------- */

/* Kein `overflow` in der Grundregel — das ist der Kern.
   `overflow-x: auto` macht ein Element in **beiden** Achsen zum
   Scroll-Container: sobald eine Achse nicht `visible` ist, rechnet die
   andere `visible` zu `auto` um. Ein `position: sticky` darin klebt dann
   am Wrapper statt am Viewport, und ein Viewport-Versatz wie
   `top: contextbar-höhe` schiebt den Kopf um genau diesen Betrag nach
   unten — die erste Datenzeile erscheint darüber. Genau so sah der Fehler
   aus. Der Prototyp schaltet den Scroll-Container deshalb erst schmal ein
   und setzt den Versatz dort zurück; die Portierung hatte beide Hälften
   verloren. */
.lotzwoo-b2b-shop .lwb-matrixwrap { border: 1px solid var(--lwb-ink-200); border-radius: var(--lwb-r-lg); background: var(--lwb-surface); }

/* `separate` statt `collapse`, wie im Prototyp: bei `border-collapse:
   collapse` gehören die Rahmen der Tabelle und nicht der Zelle, und ein
   klebender Kopf nimmt sie beim Scrollen nicht mit — die Kopfzeile
   verliert unterwegs ihre Unterkante. Deshalb zeichnet sie unten einen
   `inset`-Schatten statt eines Rahmens. */
.lotzwoo-b2b-shop .lwb-matrix { width: 100%; border-collapse: separate; border-spacing: 0; min-width: 640px; font-size: var(--lwb-fs-sm); }
.lotzwoo-b2b-shop .lwb-matrix th,
.lotzwoo-b2b-shop .lwb-matrix td { padding: var(--lwb-sp-2) var(--lwb-sp-3); border-bottom: 1px solid var(--lwb-ink-100); text-align: left; vertical-align: top; }

.lotzwoo-b2b-shop .lwb-matrix thead th {
  position: sticky;
  /* AP-48: gemessen statt geraten. Hier ohne Abstand — der Spaltenkopf sitzt
     buendig unter der Leiste, und eine Fuge waere sichtbar. */
  top: calc(var(--lwb-sticky-top) + var(--lwb-ctx-h, 52px));
  z-index: 2;
  background: var(--lwb-ink-50);
  font-size: var(--lwb-fs-2xs);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--lwb-ink-500);
  border-bottom: 0;
  box-shadow: inset 0 -1px 0 var(--lwb-ink-200);
}

/* Schmal: jetzt darf der Wrapper waagrecht scrollen — und weil er damit
   zum Scroll-Container wird, klebt der Kopf an ihm. Der Viewport-Versatz
   muss hier weg, sonst kehrt der Fehler zurück. */
@media (max-width: 1180px) {
  .lotzwoo-b2b-shop .lwb-matrixwrap { overflow-x: auto; }
  .lotzwoo-b2b-shop .lwb-matrix thead th { top: 0; }
}

/* Der Zeilenkopf der Matrix ist ein `th` — er benennt die Zeile fuer einen
   Screenreader und bleibt eins. Sein Browser-Default `font-weight: bold`
   erbte sich aber auf `.lwb-row__sku`, die selbst keins setzt: dieselbe
   Artikelnummer stand in Tabelle und Kachel normal und in der Matrix fett.
   Gesetzt wird deshalb hier, an der Stelle, die es meint — **nicht** global
   an `.lwb-row__sku`, die in vier Ansichten steht und in dreien richtig ist.
   Der Name daneben (`lwb-card__name`, 600) bleibt, wie er ist. (AP-70, A4) */
.lotzwoo-b2b-shop .lwb-matrix tbody th .lwb-row__sku { font-weight: 400; }

/* ---------------- Die vier Ecken der Matrix ----------------

   **Gemeldet am 2026-08-26:** „th/td stehen über die Eckenrundung und Border
   drüber". Am Klon nachgemessen — der Wrapper trägt `border-radius: 12px`
   und `border: 1px`, die Tabelle sitzt bündig darin (327…1423 gegen
   326…1424), und die erste Kopfzelle hat `border-radius: 0` bei
   **deckendem** Grund (`--lwb-ink-50`). Sie malt ihre eckige Ecke also in
   die Rundung hinein, und dasselbe tut unten links die Sticky-Spalte mit
   ihrem `--lwb-surface`.

   **`overflow: hidden` am Wrapper ist hier verboten** und der Grund steht
   ausführlich weiter oben: es macht ihn in beiden Achsen zum
   Scroll-Container, und der klebende Spaltenkopf klebt dann an ihm statt am
   Viewport. Der Fehler, den dieser Auftrag reparieren soll, wäre gegen einen
   schlimmeren getauscht.

   Gerundet werden deshalb die **Zellen**, und zwar genau die vier in den
   Ecken. `calc(… - 1px)`, weil sie innerhalb des 1-px-Rahmens sitzen: ein
   voller 12er-Radius stünde einen Pixel neben der Kurve, die er nachzeichnen
   soll.

   **Die letzte Zeile gibt ihre Unterkante ab.** Sie zeichnete eine Linie
   einen Pixel über dem Rahmen des Wrappers — zwei Striche übereinander, und
   der obere lief durch die Rundung. Der Rahmen unten gehört dem Wrapper.

   **Der Spaltenkopf behält seine Rundung auch geklebt.** Über ihm steht dann
   die Werkzeugleiste, und in den zwei oberen Ecken zeigt sich der Grund des
   Wrappers als schmale Kerbe. Das ist gemessen und in Kauf genommen: die
   Alternative wäre ein dritter Klebezustand in JavaScript für zwei Pixel, die
   man suchen muss. */
.lotzwoo-b2b-shop .lwb-matrix thead tr:first-child th:first-child {
  border-top-left-radius: calc(var(--lwb-r-lg) - 1px);
}

.lotzwoo-b2b-shop .lwb-matrix thead tr:first-child th:last-child {
  border-top-right-radius: calc(var(--lwb-r-lg) - 1px);
}

.lotzwoo-b2b-shop .lwb-matrix tbody tr:last-child > :first-child {
  border-bottom-left-radius: calc(var(--lwb-r-lg) - 1px);
}

.lotzwoo-b2b-shop .lwb-matrix tbody tr:last-child > :last-child {
  border-bottom-right-radius: calc(var(--lwb-r-lg) - 1px);
}

.lotzwoo-b2b-shop .lwb-matrix tbody tr:last-child > * {
  border-bottom: 0;
}

/* **Die Artikelspalte ist gedeckelt, nicht garantiert** (2026-08-29,
   angefordert). Hier stand `min-width: 260px` — eine Untergrenze, und die ist
   am Telefon die falsche Richtung: auf 390 px nahm die klebende Spalte zwei
   Drittel des Fensters, und von der Matrix daneben blieb ein Streifen.

   `min(50vw, 260px)` dreht es um: nie breiter als 260 px und nie breiter als
   das halbe Fenster. Auf dem Schreibtisch aendert sich damit nichts, auf
   390 px sind es 195 px.

   Die Trennlinie rechts sagt, wo die klebende Spalte aufhoert. Sie ist ohne
   die Deckelung nicht noetig gewesen — solange die Spalte breit war, sah man
   die Kante an ihrem Inhalt; geschoben und schmal braucht sie einen Strich.

   **Der Koerper steht auf `--lwb-front`** (2026-09-11, angefordert), wie die
   Karte. Die klebende Spalte muss denselben Ton **selbst** tragen: sie braucht
   einen deckenden Grund, sonst scheinen beim waagrechten Schieben die Zellen
   darunter durch — und ein eigener Grund verdeckt den des `tbody`. Mit
   `--lwb-surface` stuende sie auf Bersta als cremefarbener Streifen im weissen
   Koerper. */
.lotzwoo-b2b-shop .lwb-matrix tbody { background: var(--lwb-front); }

.lotzwoo-b2b-shop .lwb-matrix .lwb-sticky-col {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--lwb-front);
  width: min(50vw, 260px);
  border-right: 1px solid var(--lwb-ink-200);
}
.lotzwoo-b2b-shop .lwb-matrix thead .lwb-sticky-col { z-index: 3; background: var(--lwb-ink-50); }
.lotzwoo-b2b-shop .lwb-matrix tr.is-filled { background: var(--lwb-brand-50); }
.lotzwoo-b2b-shop .lwb-matrix tr.is-filled .lwb-sticky-col { background: var(--lwb-brand-50); }

/* ---------------- Order dock, capture panel, load more, empty ---------------- */

/* Die Klebrigkeit sitzt am Dock, nicht an der Leiste. Das Panel öffnet nach
   oben aus der Leiste heraus und muss an ihr hängen bleiben; zwei klebende
   Geschwister lösen sich voneinander, sobald die Liste lang genug wird, um in
   sich selbst zu scrollen. */
.lotzwoo-b2b-shop .lwb-orderdock {
  position: sticky;
  bottom: 0;
  z-index: calc(var(--lwb-z-sticky) - 1);
  margin-top: var(--lwb-sp-4);
}

.lotzwoo-b2b-shop .lwb-orderbar {
  display: flex;
  gap: var(--lwb-sp-4);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-lg);
  /* **Weiss wie die Filterspalte** (2026-08-26, angefordert). Hier stand
     `--lwb-ink-50`, der getoente Grund der Seite — die Leiste liegt aber
     **vor** der Liste, nicht darin, und war damit die einzige klebende
     Flaeche des Sortiments ohne Vordergrundfarbe.
     `--lwb-front` und nicht `--lwb-white-pure`: es ist dasselbe Token, das
     `.lwb-sidebar` liest, und auf einem getoenten Kundentheme sollen die zwei
     zusammen wandern statt getrennt. */
  background: var(--lwb-front);
  box-shadow: var(--lwb-sh-md);
}

/* **Am Bildschirmrand hat die Leiste keine unteren Ecken** (2026-08-26,
   angefordert). Solange sie unten klebt, endet sie am Rand des Fensters —
   und eine Rundung dort zeigt einen Streifen Seite, der unter ihr
   durchläuft, obwohl darunter nichts mehr kommt. Löst sie sich am Ende der
   Liste, ist sie wieder eine Karte im Fluss und bekommt ihre Ecken zurück.

   `is-docked` setzt `b2b-stickystate.js` am Dock, nicht an der Leiste: die
   Klebrigkeit sitzt am Dock (siehe dort), und die Leiste ist das, was man
   davon sieht. Gemessen wird gegen `window.innerHeight` minus dem gesetzten
   `bottom` — genau die Frage „berührt sie den unteren Bildschirmrand".

   Ohne das Skript bleiben die Ecken rund. Das ist der Zustand von gestern,
   also kein Rückschritt. */
.lotzwoo-b2b-shop .lwb-orderdock.is-docked .lwb-orderbar {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

/* **Unter 900 px gibt sie am Rand alle vier Ecken auf und laeuft bis an beide
   Fensterraender** (2026-08-28, angefordert — derselbe Effekt wie an der
   Werkzeugleiste oben, nur von unten gemessen).

   Der Grund ist derselbe und hier noch etwas staerker: am Telefon ist die
   Bestellleiste die untere Kante des Geraets, nicht eine Karte im Fluss. Zwei
   gerundete Ecken links und rechts davon zeigen einen Streifen Seite, unter
   dem nichts mehr liegt.

   Sie ist Geschwister des Erfassungspanels, und das steht **ueber** ihr in
   derselben Karte — es geht mit, sonst stuenden zwei verschieden breite
   Flaechen uebereinander. */
@media (max-width: 900px) {
  .lotzwoo-b2b-shop .lwb-orderdock.is-docked .lwb-orderbar,
  .lotzwoo-b2b-shop .lwb-orderdock.is-docked .lwb-capture {
    box-sizing: border-box;
    /* `--lwb-vw` und nicht `100vw` — die Begruendung steht bei der
       Werkzeugleiste, und der Fehler waere hier derselbe. */
    width: var(--lwb-vw, 100vw);
    margin-inline: calc(50% - var(--lwb-vw, 100vw) / 2);
    border-radius: 0;
  }

  /* Ein senkrechter Rahmen an einer Kante, die es nicht mehr gibt: die
     Leiste endet jetzt am Fensterrand, nicht an einer Karte. */
  .lotzwoo-b2b-shop .lwb-orderdock.is-docked .lwb-orderbar,
  .lotzwoo-b2b-shop .lwb-orderdock.is-docked .lwb-capture {
    border-inline: 0;
  }
}

/* Offenes Panel und Leiste sind eine Karte: die Ecken zwischen ihnen werden
   gerade, damit nicht zwei Kästen übereinander stehen. */
.lotzwoo-b2b-shop .lwb-capture:not([hidden]) + .lwb-orderbar {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  border-top-color: var(--lwb-ink-100);
}

.lotzwoo-b2b-shop .lwb-capture {
  /* Die Höhe ist gedeckelt und die Liste scrollt in sich. Vierzig gescannte
     Zeilen dürfen die Leiste nicht aus dem Bild schieben — sie ist der einzige
     Weg in den Warenkorb. */
  max-height: min(42vh, 420px);
  overflow-y: auto;
  border: 1px solid var(--lwb-ink-200);
  border-bottom: 0;
  border-radius: var(--lwb-r-lg) var(--lwb-r-lg) 0 0;
  background: var(--lwb-surface);
  box-shadow: var(--lwb-sh-md);
}

.lotzwoo-b2b-shop .lwb-capture__head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  gap: var(--lwb-sp-3);
  align-items: center;
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
  background: var(--lwb-ink-50);
  border-bottom: 1px solid var(--lwb-ink-200);
  font-size: var(--lwb-fs-xs);
  color: var(--lwb-ink-500);
}

.lotzwoo-b2b-shop .lwb-capture__title { font-weight: 700; color: var(--lwb-ink-900); }

.lotzwoo-b2b-shop .lwb-capture__line {
  display: flex;
  gap: var(--lwb-sp-3);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
  border-bottom: 1px solid var(--lwb-ink-100);
}

.lotzwoo-b2b-shop .lwb-capture__line:last-child { border-bottom: 0; }
.lotzwoo-b2b-shop .lwb-capture__line.is-bad { background: var(--lwb-err-50); }
.lotzwoo-b2b-shop .lwb-capture__what { flex: 1 1 240px; min-width: 0; }
.lotzwoo-b2b-shop .lwb-capture__name { font-weight: 600; color: var(--lwb-ink-900); }
.lotzwoo-b2b-shop .lwb-capture__meta { font-size: var(--lwb-fs-2xs); color: var(--lwb-ink-500); }
.lotzwoo-b2b-shop .lwb-capture__why { font-size: var(--lwb-fs-2xs); color: var(--lwb-err-700); }
.lotzwoo-b2b-shop .lwb-capture__sum {
  min-width: 88px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--lwb-ink-900);
}

/* Die Zahl hinter dem Scanner: wie oft dieselbe Packung durchgezogen wurde.
   Sie steht neben der Menge, weil beide dasselbe erklären — die eine, was
   bestellt wird, die andere, wie sie zustande kam. */
.lotzwoo-b2b-shop .lwb-capture__scans {
  font-size: var(--lwb-fs-2xs);
  color: var(--lwb-ink-500);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  .lotzwoo-b2b-shop .lwb-capture { max-height: 50vh; }
  .lotzwoo-b2b-shop .lwb-capture__sum { min-width: 0; }
}

/* Die Erfassungsleiste, sichtbar als andere Leiste — nicht als dieselbe mit
   anderen Zahlen. Sie stellt eine offene Frage („was passiert mit dem hier?"),
   die Bestellleiste nicht; wenn beide gleich aussehen, merkt niemand, dass die
   Frage gewechselt hat. Die Kante links trägt es, weil sie in der Höhe der
   Leiste liegt und nicht erst beim Lesen auffällt. */
/* **Der Scan-Zustand faerbt die Leiste nicht mehr** (2026-08-26,
   angefordert). Hier standen ein 4-px-Balken in `--lwb-brand-500` links und
   `--lwb-brand-50` als Grund. Beides ist weg: der Balken, weil er als
   einziges Element des Sortiments eine Kante in Markenrot trug und damit wie
   eine Fehlermeldung las, und der Grund, weil die Leiste weiss sein soll wie
   die Filterspalte — dieselbe Entscheidung wie eine Regel weiter oben.

   **Der Zustand geht dabei nicht verloren, er steht im Wort.** Die Leiste
   traegt in diesem Fall `.lwb-orderbar__state` mit `captureUncommitted`, und
   darueber steht das offene Erfassungspanel. Farbe allein war hier ohnehin
   nie die Auskunft.

   Die Klasse bleibt am Element (`b2b-shop.js` setzt sie) und traegt jetzt
   keine Gestaltung mehr. Das ist Absicht und keine Leiche: sie ist der
   Anfasser fuer den naechsten, der den Zustand doch wieder zeichnen will,
   und ihn aus dem Skript zu nehmen waere eine Aenderung an einer Stelle, die
   niemand angefragt hat. */

.lotzwoo-b2b-shop .lwb-orderbar__state {
  color: var(--lwb-ink-900);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: var(--lwb-fs-2xs);
}

/* Kurz nach der Übernahme steht die Kasse dort, wo eben noch „Übernehmen"
   stand. So lange sieht sie unbenutzbar aus und ist es auch — ohne `href`
   führt der zweite Druck nirgendwohin. */
.lotzwoo-b2b-shop .lwb-btn.is-guarded {
  opacity: .5;
  pointer-events: none;
  cursor: default;
}

.lotzwoo-b2b-shop .lwb-orderbar__total { font-size: var(--lwb-fs-lg); font-weight: 700; color: var(--lwb-ink-900); font-variant-numeric: tabular-nums; }
.lotzwoo-b2b-shop .lwb-orderbar__meta { font-size: var(--lwb-fs-xs); color: var(--lwb-ink-500); }

/* Die Rücknahmezeile ist eine volle Zeile der Leiste. `flex: 1 0 100%`
   erzwingt im umbrechenden Flex-Container einen eigenen Umbruch — sie steht
   damit über den Zahlen und nicht zwischen Summe und Knöpfen. */
.lotzwoo-b2b-shop .lwb-orderbar__last {
  flex: 1 0 100%;
  display: flex;
  gap: var(--lwb-sp-3);
  align-items: center;
  justify-content: flex-start;
  font-size: var(--lwb-fs-sm);
}

/* Die Meldung, die früher ein Toast war. Sie steht als eigene Karte über dem
   Panel, weil sie eine stehende Live-Region ist und nicht bei jedem Rendern
   neu gebaut werden darf. Farbe trägt den Ausgang, weil der Text ihn nicht
   immer trägt: „2 von 3 übernommen" ist für sich weder gut noch schlecht. */
.lotzwoo-b2b-shop .lwb-orderbar__notice {
  margin-bottom: var(--lwb-sp-2);
  padding: var(--lwb-sp-3) var(--lwb-sp-4);
  border: 1px solid var(--lwb-ink-200);
  border-left: 3px solid var(--lwb-ink-300);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-surface);
  box-shadow: var(--lwb-sh-md);
  color: var(--lwb-ink-900);
  font-size: var(--lwb-fs-sm);
}

.lotzwoo-b2b-shop .lwb-orderbar__notice.is-ok { border-left-color: var(--lwb-ok-500); }
.lotzwoo-b2b-shop .lwb-orderbar__notice.is-warn { border-left-color: var(--lwb-warn-500); }
/* Die Rinne muss man sehen, auch wenn nichts drin ist — sonst weiß niemand,
   wie weit der Weg überhaupt ist. Sie trägt dafür eine eigene Fläche *und*
   eine Kontur.

   Die Fläche ist Weiß, seit die Bestellleiste unter ihr auf `--lwb-ink-50`
   steht: das frühere `--lwb-ink-100` war eine Tönung gegen Weiß und ist auf
   einem getönten Grund fast verschwunden. Jetzt ist es umgekehrt — die
   Rinne ist heller als ihr Untergrund, nicht dunkler. Wer die Leiste wieder
   auf Weiß setzt, muss diese Zeile mitnehmen, sonst steht Weiß auf Weiß und
   nur die Kontur bleibt.

   Seit AP-22 heißt „Weiß" hier `--lwb-front` und ist es auch: `--lwb-surface`
   war auf Bersta #fbf7f0 und damit heller als die Leiste nur noch um 1.09:1
   — gemessen, nicht geschätzt. Vom Schatten der Rolle nimmt die Rinne
   nichts: sie ist 8 px hoch und liegt in einer Leiste, die selbst einen
   trägt; ihr Heben ist die Kontur, und die ist mit `--lwb-ink-300` eine
   Stufe kräftiger als `--lwb-front-border` — absichtlich, das ist die
   einzige der drei Flächen, die nur eine Linie hoch ist. */
.lotzwoo-b2b-shop .lwb-meter {
  width: 180px;
  height: 8px;
  border: 1px solid var(--lwb-ink-300);
  border-radius: var(--lwb-r-full);
  background: var(--lwb-front);
  overflow: hidden;
}

.lotzwoo-b2b-shop .lwb-meter i {
  display: block;
  height: 100%;
  background: var(--lwb-brand-500);
  transition: width 180ms ease;
}

/* Ein Prozent ist ein halbes Pixel und damit gar nichts. Sobald überhaupt
   etwas erfasst ist, muss der Balken das zeigen — sonst liest sich „ein
   bisschen" wie „noch nichts". Null bleibt null, dafür die zweite Regel. */
.lotzwoo-b2b-shop .lwb-meter i { min-width: 4px; }
.lotzwoo-b2b-shop .lwb-meter i[style*="width:0%"] { min-width: 0; }

/* Noch keine Antwort von `cart/validate`. Die Rinne hält den Platz, damit die
   klebende Leiste nicht die Höhe wechselt, sobald die Zahl eintrifft — sie
   trägt Knöpfe, und eine Leiste, die unter der Hand umspringt, verschiebt sie.
   Zurückgenommen und ohne Füllung: die Aussage „unbekannt" trägt die
   Beschriftung darüber, die dann noch die Schwelle nennt und nicht den
   Abstand. */
.lotzwoo-b2b-shop .lwb-meter.is-unknown { opacity: .45; }

.lotzwoo-b2b-shop .lwb-meter.is-reached i { background: var(--lwb-ok-500); }

.lotzwoo-b2b-shop .lwb-loadmore { padding: var(--lwb-sp-4) 0; text-align: center; }
.lotzwoo-b2b-shop .lwb-progress { height: 4px; border-radius: var(--lwb-r-full); background: var(--lwb-ink-100); overflow: hidden; margin-bottom: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-progress i { display: block; height: 100%; background: var(--lwb-brand-500); transition: width 180ms ease; }

.lotzwoo-b2b-shop .lwb-empty__ico { color: var(--lwb-ink-300); margin-bottom: var(--lwb-sp-3); }
.lotzwoo-b2b-shop .lwb-gate__ico { color: var(--lwb-brand-500); margin-bottom: var(--lwb-sp-3); }

/* `hidden` schlaegt die Grundregel des Knopfes.
   `.lwb-btn` setzt `display: inline-flex`; das UA-Blatt setzt fuer [hidden]
   nur `display: none` und verliert gegen jede Klassenregel. Ohne diese Zeile
   stuenden am Tor beide Knoepfe nebeneinander — der, der weiterhilft, und der,
   der es gerade nicht tut. */
.lotzwoo-b2b-shop .lwb-btn[hidden] { display: none; }
.lotzwoo-b2b-shop .lwb-empty { padding: var(--lwb-sp-8); text-align: center; border: 1px dashed var(--lwb-ink-200); border-radius: var(--lwb-r-lg); background: var(--lwb-surface); }

/* ---------------- Modal, drawer, toasts ---------------- */

/* `.lwb-modal-backdrop` gibt es seit dem 2026-08-16 nicht mehr: das Modal ist ein
   natives `<dialog>`, sein Hintergrund ist `::backdrop`. Die Regel bleibt fuer
   den Drawer, der weiterhin ein eigenes Hintergrundelement hat. */
.lotzwoo-b2b-shop .lwb-modal-backdrop,
.lotzwoo-b2b-shop .lwb-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--lwb-z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--lwb-sp-4);
  background: rgba(13, 21, 32, .5);
}

.lotzwoo-b2b-shop .lwb-drawer-backdrop { z-index: var(--lwb-z-drawer); justify-content: flex-start; padding: 0; }

/* Ein `<dialog>` bringt eigene Browservorgaben mit: Rahmen, Innenabstand,
   `max-width: calc(100% - 6px - 2em)` und `display: none`, solange es zu ist.
   Die werden hier zurueckgesetzt — `display` erst im offenen Zustand, sonst
   waere der Dialog auch geschlossen sichtbar. */
.lotzwoo-b2b-shop .lwb-modal {
  position: fixed;
  inset: 0;
  margin: auto;
  padding: 0;
  border: 0;
  max-width: none;
  max-height: 88vh;
  width: min(860px, calc(100% - 2 * var(--lwb-sp-4)));
  border-radius: var(--lwb-r-lg);
  background: var(--lwb-surface);
  color: inherit;
  box-shadow: var(--lwb-sh-lg);
  overflow: hidden;
}

.lotzwoo-b2b-shop .lwb-modal[open] {
  display: flex;
  flex-direction: column;
}

.lotzwoo-b2b-shop .lwb-modal::backdrop {
  background: rgba(13, 21, 32, .5);
}

.lotzwoo-b2b-shop .lwb-modal__head { display: flex; gap: var(--lwb-sp-3); align-items: flex-start; padding: var(--lwb-sp-4) var(--lwb-sp-5); border-bottom: 1px solid var(--lwb-ink-100); }
.lotzwoo-b2b-shop .lwb-modal__body { flex: 1; overflow: auto; padding: var(--lwb-sp-5); }
.lotzwoo-b2b-shop .lwb-modal__foot { display: flex; gap: var(--lwb-sp-2); align-items: center; padding: var(--lwb-sp-3) var(--lwb-sp-5); border-top: 1px solid var(--lwb-ink-100); background: var(--lwb-ink-50); }
.lotzwoo-b2b-shop .lwb-modal__close { margin-left: auto; border: 0; background: none; font-size: 20px; line-height: 1; color: var(--lwb-ink-500); cursor: pointer; }

.lotzwoo-b2b-shop .lwb-ctxsteps { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--lwb-sp-5); }
.lotzwoo-b2b-shop .lwb-ctxstep h3 { font-size: var(--lwb-fs-base); margin-bottom: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-optlist { display: flex; flex-direction: column; gap: var(--lwb-sp-2); max-height: 44vh; overflow: auto; }

.lotzwoo-b2b-shop .lwb-opt {
  display: block;
  width: 100%;
  padding: var(--lwb-sp-3);
  border: 1px solid var(--lwb-ink-200);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-surface);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-opt:hover { border-color: var(--lwb-brand-300); }
.lotzwoo-b2b-shop .lwb-opt[aria-pressed="true"] { border-color: var(--lwb-brand-500); box-shadow: inset 0 0 0 1px var(--lwb-brand-500); background: var(--lwb-brand-50); }
.lotzwoo-b2b-shop .lwb-opt[disabled] { opacity: .55; cursor: not-allowed; }
.lotzwoo-b2b-shop .lwb-opt__name { font-weight: 600; color: var(--lwb-ink-900); }
.lotzwoo-b2b-shop .lwb-opt__meta { font-size: var(--lwb-fs-xs); color: var(--lwb-ink-500); margin-top: 2px; }

/* ---------------- Produktdetail-Modal (AP-38) ----------------
   Ein Nachschlagewerk. Die Tabelle ist der Inhalt, das Bild ist die
   Beigabe — deshalb bekommt die Kopfzone eine feste, kleine Spalte und
   nicht die Hälfte der Fläche. */

.lotzwoo-b2b-shop .lwb-nameopen {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

/* Der Griff darf nicht schreien — er sitzt auf jedem Artikelnamen in allen
   drei Ansichten. Sichtbar wird er beim Zeigen und beim Tasten. */
.lotzwoo-b2b-shop .lwb-nameopen:hover { text-decoration: underline; }
/* War `outline: var(--lwb-focus)` — ungueltig, siehe Flaechenregel oben. */
.lotzwoo-b2b-shop .lwb-nameopen:focus-visible { outline: none; box-shadow: var(--lwb-focus); border-radius: var(--lwb-r-sm); }

.lotzwoo-b2b-shop .lwb-detail__top {
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  gap: var(--lwb-sp-5);
  align-items: start;
}

.lotzwoo-b2b-shop .lwb-detail__media {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--lwb-ink-100);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-ink-50);
  overflow: hidden;
}

.lotzwoo-b2b-shop .lwb-detail__img { width: 100%; height: 100%; object-fit: contain; }

/* Der Fall „kein Bild" ist am Klon der einzige Fall — 26 Produkte, kein
   Bildsatz. Er bekommt deshalb eine eigene Gestalt und keine kaputte. */
.lotzwoo-b2b-shop .lwb-detail__noimg {
  display: flex;
  flex-direction: column;
  gap: var(--lwb-sp-2);
  align-items: center;
  justify-content: center;
  color: var(--lwb-ink-400);
  text-align: center;
  padding: var(--lwb-sp-3);
}

.lotzwoo-b2b-shop .lwb-detail__ident { display: flex; flex-direction: column; gap: var(--lwb-sp-2); }
.lotzwoo-b2b-shop .lwb-detail__pack { font-weight: 600; color: var(--lwb-ink-700); }
.lotzwoo-b2b-shop .lwb-detail .lwb-pills { margin-top: var(--lwb-sp-4); }
.lotzwoo-b2b-shop .lwb-detail__none { margin-top: var(--lwb-sp-5); }

.lotzwoo-b2b-shop .lwb-detail__table {
  width: 100%;
  margin-top: var(--lwb-sp-5);
  border-collapse: collapse;
  font-size: var(--lwb-fs-sm);
}

.lotzwoo-b2b-shop .lwb-detail__table th,
.lotzwoo-b2b-shop .lwb-detail__table td {
  padding: var(--lwb-sp-2) 0;
  border-top: 1px solid var(--lwb-ink-100);
  text-align: left;
  vertical-align: top;
}

/* Die Beschriftungsspalte ist schmal und fest: eine Wertespalte, die je
   nach Artikel woanders anfängt, ist beim Querlesen von Allergenen genau
   das, was das Modal vermeiden soll. */
.lotzwoo-b2b-shop .lwb-detail__table th[scope="row"] {
  width: 38%;
  padding-right: var(--lwb-sp-4);
  font-weight: 600;
  color: var(--lwb-ink-600);
}

/* Zutatenlisten und Nährwerte tragen Zeilenumbrüche. Der Server schickt
   reinen Text, die Umbrüche macht deshalb die Gestaltung. */
.lotzwoo-b2b-shop .lwb-detail__table td { color: var(--lwb-ink-900); white-space: pre-line; }

.lotzwoo-b2b-shop .lwb-detail__group th {
  padding-top: var(--lwb-sp-5);
  border-top: 0;
  font-size: var(--lwb-fs-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--lwb-ink-500);
}

.lotzwoo-b2b-shop .lwb-detail__table tr:first-child th { padding-top: 0; }

/* AP-51: der Verweis auf die Produktseite. Dezent heißt hier eine Stufe unter
   allem anderen im Modal — Schriftgröße der SKU, gedämpfte Farbe, und die
   Unterstreichung erst beim Zeigen. Der Hauptweg ist die Zeile. */
.lotzwoo-b2b-shop .lwb-detail__page { margin-top: var(--lwb-sp-5); }

.lotzwoo-b2b-shop .lwb-detail__pagelink {
  color: var(--lwb-ink-500);
  text-decoration: none;
  border-bottom: 1px solid var(--lwb-ink-200);
}

.lotzwoo-b2b-shop .lwb-detail__pagelink:hover,
.lotzwoo-b2b-shop .lwb-detail__pagelink:focus-visible { color: var(--lwb-ink-900); }

.lotzwoo-b2b-shop .lwb-drawer {
  display: flex;
  flex-direction: column;
  width: min(360px, 92vw);
  height: 100%;
  /* Unter 900 px ist dieser Schub die Filterspalte — es gibt keine zweite.
     Er trägt deshalb dieselbe Vordergrund-Rolle; bliebe er auf der
     Grundfläche, stünde die weiße Spalte in ihm auf Creme und der Schub
     wäre zweifarbig. Seinen eigenen Schatten behält er: er liegt über der
     Seite, nicht in ihr, und `--lwb-sh-lg` ist dafür die richtige Stufe. */
  background: var(--lwb-front);
  box-shadow: var(--lwb-sh-lg);
}

.lotzwoo-b2b-shop .lwb-drawer__head { display: flex; gap: var(--lwb-sp-2); align-items: center; padding: var(--lwb-sp-3) var(--lwb-sp-4); border-bottom: 1px solid var(--lwb-ink-100); }
.lotzwoo-b2b-shop .lwb-drawer__body { flex: 1; overflow: auto; }
.lotzwoo-b2b-shop .lwb-drawer .lwb-sidebar { position: static; max-height: none; border: 0; box-shadow: none; }

/* Oben rechts, unter der Kontextleiste — nicht mehr unten rechts.
   Der Stapel ist `position: fixed` auf z-index 10060, das Bestell-Dock klebt
   auf 29. Unten rechts lag also jede Meldung genau auf „Übernehmen" und „Zur
   Kasse", also auf dem Knopf, von dem sie meistens handelt. Der Versatz nach
   unten hält sie unter der klebenden Kontextleiste. **Die 52px, die hier bis
   AP-48 standen, waren nie ihre Höhe:** `min-height` ist 44px, unter 600px
   wird sie zweizeilig, und mit gesetztem `Context_Notice` dreizeilig. Gemessen
   wird sie jetzt (`--lwb-ctx-h`, aus `b2b-ctxheight.js`). */
.lotzwoo-b2b-shop .lwb-toasts {
  position: fixed;
  right: var(--lwb-sp-4);
  top: calc(var(--lwb-sticky-top) + var(--lwb-ctx-h, 52px) + 16px);
  z-index: var(--lwb-z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--lwb-sp-2);
  max-width: min(380px, calc(100vw - 32px));
}

.lotzwoo-b2b-shop .lwb-toast {
  display: flex;
  gap: var(--lwb-sp-2);
  align-items: flex-start;
  padding: var(--lwb-sp-3) var(--lwb-sp-3) var(--lwb-sp-3) var(--lwb-sp-4);
  border-left: 3px solid var(--lwb-ink-400);
  border-radius: var(--lwb-r-md);
  background: var(--lwb-ink-900);
  color: var(--lwb-surface);
  font-size: var(--lwb-fs-sm);
  box-shadow: var(--lwb-sh-lg);
}

.lotzwoo-b2b-shop .lwb-toast__text { flex: 1 1 auto; }

/* Dieselbe Meldung ein zweites Mal zählt hoch, statt sich zu stapeln. */
.lotzwoo-b2b-shop .lwb-toast__seen {
  flex: 0 0 auto;
  opacity: .7;
  font-variant-numeric: tabular-nums;
}

/* Der Schließer ist die einzige Art, wie eine Meldung noch verschwindet.
   Deshalb muss er sichtbar sein und eine Trefferfläche haben, keine
   Verzierung, die man erst beim Darüberfahren findet. */
.lotzwoo-b2b-shop .lwb-toast__close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--lwb-r-sm);
  background: transparent;
  color: inherit;
  opacity: .7;
  cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-toast__close:hover { opacity: 1; background: rgba(255, 255, 255, .14); }

.lotzwoo-b2b-shop .lwb-toast--ok { border-left-color: #4ade80; }
.lotzwoo-b2b-shop .lwb-toast--err { border-left-color: #f87171; }
.lotzwoo-b2b-shop .lwb-toast b { display: block; }

/* ---------------- Narrow screens ---------------- */

/* **Die Schwelle steht seit dem 2026-08-27 bei 1340 px, nicht bei 1100.**

   Nachgerechnet und nachgemessen: sieben Spalten brauchen 992 px Tabellenbreite
   — 510 fuer Bild, Stern, Gebinde, Preis und Verfuegbarkeit, 150 als Boden fuer
   den Artikelnamen, 228 fuer Stepper und Knopf nebeneinander, dazu 72 Fugen und
   32 Polster. Die Tabelle ist rund 344 px schmaler als das Fenster (bei 1440 px
   gemessene 1096), also passt das ab **1336 px**.

   Bei 1100 stand die Schwelle zu tief, und das Band dazwischen war schon vorher
   kaputt: bei 1200 px hielt die Namensspalte **43 px**, bei 1101 px null. Der
   Artikelname ist das Wichtigste in der Zeile; dass er dort verschwand, ist
   ueber Monate niemandem aufgefallen, weil keine Zusicherung ihn misst.

   Der Preis dieser Zeile ist sichtbar und gewollt: zwischen 1100 und 1340 px
   fallen **Gebinde** und **Verfuegbarkeit** jetzt frueher weg. Das ist die
   ehrliche Antwort auf „nebeneinander, wenn Platz ist" — dort ist keiner. */
@media (max-width: 1340px) {
  .lotzwoo-b2b-shop .lwb-table__head,
  .lotzwoo-b2b-shop .lwb-row { grid-template-columns: 44px 40px minmax(0, 1fr) 130px minmax(120px, var(--lwb-akt-breite)); }
  .lotzwoo-b2b-shop .lwb-row__img { width: 44px; }
  /* **Hier stand `nth-child`, und die Zaehlung ist in einer Woche zweimal
     verrutscht** — einmal mit der Bildspalte, einmal mit der neuen Kopfzeile.
     Beim ersten Mal haette sie die falschen zwei Ueberschriften ausgeblendet,
     waehrend die Zellen darunter stimmen: ein Fehler, den kein Nachweis
     bemerkt, weil beide Zahlen weiter *irgendeine* Zelle treffen. Die Klassen
     verrutschen nicht. */
  .lotzwoo-b2b-shop .lwb-table__head .lwb-head--pack,
  .lotzwoo-b2b-shop .lwb-row .lwb-row__pack,
  .lotzwoo-b2b-shop .lwb-table__head .lwb-head--avail,
  .lotzwoo-b2b-shop .lwb-row .lwb-row__avail { display: none; }
}

@media (max-width: 640px) {
  .lotzwoo-b2b-shop .lwb-table__head { display: none; }
  .lotzwoo-b2b-shop .lwb-row { grid-template-columns: 40px 36px minmax(0, 1fr); }
  .lotzwoo-b2b-shop .lwb-row__img { width: 40px; }
  /* Spalte 3, nicht 2: der Textblock ist seit der Bildspalte die dritte.
     Auf 2 gesetzt landeten Preis und Knoepfe unter dem Stern. */
  .lotzwoo-b2b-shop .lwb-row .lwb-row__price,
  .lotzwoo-b2b-shop .lwb-row .lwb-row__actions { grid-column: 3; justify-content: flex-start; }

  /* Auf 390 px steht das Bild über der Kennung statt daneben, und es wird
     eine Kachel statt eines Quadrats über die halbe Höhe: das Modal ist
     ein Nachschlagewerk, und was nachgeschlagen wird, ist die Tabelle. */
  .lotzwoo-b2b-shop .lwb-detail__top { grid-template-columns: minmax(0, 1fr); gap: var(--lwb-sp-4); }
  .lotzwoo-b2b-shop .lwb-detail__media { aspect-ratio: 16 / 9; }
  /* Die Beschriftung darf hier breiter werden — „Herkunft (Geschlachtet in)"
     bricht auf 38 % einer 390-px-Fläche in vier Zeilen. */
  .lotzwoo-b2b-shop .lwb-detail__table th[scope="row"] { width: 46%; padding-right: var(--lwb-sp-3); }
}

@media (prefers-reduced-motion: reduce) {
  .lotzwoo-b2b-shop * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ============================== scanning ==============================
   The scan surface lies above the rows and over every view, because
   scanning is an input method rather than a fourth way of looking at the
   catalogue (AD-9). It is never subtle while it is armed: a listener that
   reads the keyboard without saying so is a trap. */

/* **Er sieht aus wie das Suchfeld** (2026-08-29, angefordert): dieselbe
   Rundung, derselbe Grund. Hier standen `--lwb-r-sm` und `--lwb-ink-50` — die
   kleinere Rundung und der getoente Grund der Seite. In einer Reihe, in der
   Suchfeld und Sortierfeld beide `--lwb-r-md` auf `--lwb-surface` tragen, war
   er damit das eine Element, das nach hinten trat, obwohl er dieselbe Art
   Bedienelement ist.

   Der gedrueckte Zustand bleibt, was er war: Markengrund, weisse Schrift. Er
   ist die Aussage „der Scanner ist scharf", und die soll sich vom Ruhezustand
   abheben. */
.lotzwoo-b2b-shop .lwb-scantoggle {
    display: inline-flex;
    align-items: center;
    gap: var(--lwb-sp-2);
    border: 1px solid var(--lwb-ink-200);
    background: var(--lwb-surface);
    color: var(--lwb-ink-900);
    border-radius: var(--lwb-r-md);
    padding: 6px 12px;
    font: inherit;
    /* `md` statt `sm` seit AP-80 (B) — derselbe Grund wie am Umschalter. */
    font-size: var(--lwb-fs-md);
    cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-scantoggle[aria-pressed="true"] {
    background: var(--lwb-brand-600);
    border-color: var(--lwb-brand-600);
    color: var(--lwb-surface);
}

/* **Die Schriftvereinheitlichung aus Teil B kostet Breite, und auf 320 px war
   das zu viel.** Gefunden hat es der Sammellauf, nicht das Lesen: `kopfstufen`
   meldete am 2026-08-24 **4 px waagrechten Ueberlauf am Dokument**, und
   gemessen war es der Umschalter — 308,3 px breit, rechte Kante bei 324,3 in
   einem 320er Fenster. Mit 13 px passte er, mit 14 px nicht mehr.

   Zurueckgenommen wird das **Polster**, nicht die Schrift: die eine Hoehe und
   die eine Schriftgroesse sind der Punkt von Teil B, das Polster ist es
   nicht. Drei Knoepfe mal 2 x 4 px sind 24 px — genug, und 40 px Hoehe
   bleiben.

   **Der Ort ist hier und nicht oben beim Hoehenblock**, und das ist keine
   Geschmacksfrage: `.lwb-viewswitch button` und `.lwb-scantoggle` setzen ihr
   `padding` als Kurzform weiter unten in dieser Datei. Ein `padding-inline`
   davor hat dieselbe Spezifitaet und verliert nach Reihenfolge — beim ersten
   Anlauf gemessen: Ueberlauf unveraendert 4 px. */
@media (max-width: 400px) {
  .lotzwoo-b2b-shop .lwb-viewswitch button { padding-inline: 8px; }
  .lotzwoo-b2b-shop .lwb-scantoggle { padding-inline: 8px; }
}

.lotzwoo-b2b-shop .lwb-scan {
    border: 1px solid var(--lwb-brand-600);
    border-radius: var(--lwb-r-md);
    background: var(--lwb-ink-50);
    margin-bottom: var(--lwb-sp-3);
    overflow: hidden;
}

.lotzwoo-b2b-shop .lwb-scan__head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: color-mix(in srgb, var(--lwb-brand-600) 12%, transparent);
    border-bottom: 1px solid var(--lwb-ink-200);
}

.lotzwoo-b2b-shop .lwb-scan__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--lwb-brand-600);
    flex: none;
    animation: lwb-scan-pulse 1.6s ease-in-out infinite;
}

/* Someone who has told the browser they do not want motion still needs to
   see that the shop is listening — the dot stays, only the pulse goes. */
@media (prefers-reduced-motion: reduce) {
    .lotzwoo-b2b-shop .lwb-scan__dot {
        animation: none;
    }
}

@keyframes lwb-scan-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

/* Der Log wächst nicht mehr in die Seite hinein, er scrollt in sich. Er steht
   über der Artikelliste, und ein Feld, das alle paar Sekunden um eine Zeile
   wächst, schiebt genau das weg, was der Kunde gerade liest. Die Mindesthöhe
   hält den Rahmen stabil, damit der leere Zustand nicht kleiner ist als der
   volle und die Seite beim ersten Scan nicht springt. */
.lotzwoo-b2b-shop .lwb-scan__feed {
    min-height: 132px;
    max-height: 264px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.lotzwoo-b2b-shop .lwb-scan__line {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--lwb-ink-100);
}

/* Aus der Erfassung wiederhergestellt, nicht eben gescannt. Zurückgenommen in
   der Farbe, weil der Unterschied gesehen und nicht gelesen werden muss —
   sonst greift jemand nach einer Packung, die er längst in der Hand hatte. */
.lotzwoo-b2b-shop .lwb-scan__line.is-earlier {
    opacity: .72;
}

.lotzwoo-b2b-shop .lwb-scan__earlier {
    position: sticky;
    top: 0;
    padding: 6px 12px;
    background: var(--lwb-ink-50);
    border-bottom: 1px solid var(--lwb-ink-100);
    font-size: var(--lwb-fs-2xs);
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--lwb-ink-500);
}

.lotzwoo-b2b-shop .lwb-scan__line:last-child {
    border-bottom: 0;
}

.lotzwoo-b2b-shop .lwb-scan__line.is-bad {
    background: color-mix(in srgb, var(--lwb-err-500) 8%, transparent);
}

.lotzwoo-b2b-shop .lwb-scan__name {
    font-weight: 600;
}

.lotzwoo-b2b-shop .lwb-scan__times {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--lwb-brand-600);
}

.lotzwoo-b2b-shop .lwb-scan__empty {
    padding: 12px;
    color: var(--lwb-ink-500);
    font-size: var(--lwb-fs-sm);
}

/* ==================================================================
   AP-81 — Die Tuer zum Sortiment (.lwb-door)

   Die Flaeche, die ein **Gast** auf der Sortimentsseite sieht. Sie ist
   an dieser Installation zugleich die Startseite: die Seite mit dem
   Kurzcode ist `page_on_front`, und `redirect_canonical()` schickt
   `/b2b-sortiment/` deshalb auf `/`.

   **Warum diese Regeln hier stehen und nicht in einem zweiten Blatt.**
   Bis AP-81 lud der Gastzweig `b2b-shop.css` gar nicht — die zwei
   Schaltflaechen trugen `lwb-btn` und gestalteten nichts (an der Bank
   gemessen: 0 Treffer im Gastdokument). Der Fehler war das fehlende
   Blatt, nicht das falsche. Ein eigenes Blatt daneben haette zwei
   Fassungen von `.lwb-btn` erzeugt, und die zweite waere die
   schlechtere gewesen.

   Ein Gast bekommt **nur** dieses Blatt: kein Skript, kein Bootstrap.
   ================================================================== */

/* **Eine Spalte statt zweier — seit AP-83.** Bis dahin war das hier ein
   zweispaltiges Raster: links die Tuer, rechts vier Verkaufsaussagen aus
   dem Plugin. Die Aussagen sind fort, der Text der Seite gehoert dem
   Betreiber. Ein Raster mit einer Spalte ist keines. */
.lotzwoo-b2b-shop.lwb-door {
    display: grid;
    gap: var(--lwb-sp-8);
    color: var(--lwb-ink-700);
}

/* **Das Mass steht an der Karte und nicht am Behaelter, und das ist
   gemessen.** Am 2026-08-25 an der Bank: `.lotzwoo-b2b-shop.lwb-door`
   rechnet mit 1920 px, obwohl hier 28 rem stand. Das Basis-Theme fuehrt

       .lotzwoo-page-full-width .lotzwoo-b2b-shop {
           max-width: var(--wp--style--global--wide-size);
       }

   — gleiche Spezifitaet (0,2,0), spaeteres Blatt, also gewinnt es. Das ist
   **richtig so**: die Sortimentsseite ist eine Vollbreiten-Vorlage, und wie
   breit eine Seite ist, entscheidet das Theme (AD-8). Ein `!important` oder
   ein verdoppelter Klassenname haette dem Theme seine eigene Seite
   weggenommen, um ein Formular schmal zu bekommen.

   `.lwb-door__gate` ist der Name des Plugins allein — kein fremdes Blatt
   greift ihn. Die Karte bindet sich hier selbst auf 28 rem und stellt sich
   mittig in das, was das Theme ihr an Breite gibt. Damit gilt dasselbe Mass
   auch dort, wo der Kurzcode `[lotzwoo_b2b_login]` sie hinsetzt: in einer
   Spalte, in einer Gruppe, unter einem Bild. */
.lotzwoo-b2b-shop .lwb-door__gate {
    max-width: 28rem;
    margin-inline: auto;
    padding: var(--lwb-sp-6);
    border: 1px solid var(--lwb-front-border);
    border-radius: var(--lwb-r-lg);
    background: var(--lwb-front);
    box-shadow: var(--lwb-front-shadow);
}

.lotzwoo-b2b-shop .lwb-door__title {
    margin: 0 0 var(--lwb-sp-4);
    font-size: var(--lwb-fs-xl);
    line-height: 1.25;
    color: var(--lwb-ink-900);
}

.lotzwoo-b2b-shop .lwb-door__field {
    margin: 0 0 var(--lwb-sp-4);
}

.lotzwoo-b2b-shop .lwb-door__field label {
    display: block;
    margin-bottom: var(--lwb-sp-1);
    font-size: var(--lwb-fs-sm);
    font-weight: 600;
    color: var(--lwb-ink-600);
}

/* Dieselbe Bedienelementhoehe wie die Werkzeugleiste seit AP-80
   (`--lwb-control-h`). Gesetzt statt ueber Polster gerechnet — der
   Grund steht in AP-80s Bericht, Klasse-B-Entscheidung 2. */
.lotzwoo-b2b-shop .lwb-door__input {
    width: 100%;
    height: var(--lwb-control-h);
    padding: 0 11px;
    border: 1px solid var(--lwb-ink-200);
    border-radius: var(--lwb-r-md);
    background: var(--lwb-surface);
    color: var(--lwb-ink-900);
    font: inherit;
    font-size: var(--lwb-fs-base);
}

.lotzwoo-b2b-shop .lwb-door__remember {
    margin: 0 0 var(--lwb-sp-4);
    font-size: var(--lwb-fs-sm);
    color: var(--lwb-ink-600);
}

.lotzwoo-b2b-shop .lwb-door__remember label {
    display: inline-flex;
    align-items: center;
    gap: var(--lwb-sp-2);
    cursor: pointer;
}

.lotzwoo-b2b-shop .lwb-door__submit {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--lwb-sp-3);
    margin: 0;
}

.lotzwoo-b2b-shop .lwb-door__lost {
    font-size: var(--lwb-fs-sm);
    color: var(--lwb-brand-600);
}

/* Der Verweis, kein zweites Formular. Er erscheint nur, wenn
   `Registration_Precondition` eine Registrierung ueberhaupt zulaesst —
   ein Verweis auf ein abgeschaltetes Formular liest sich wie ein
   kaputter Shop. */
.lotzwoo-b2b-shop .lwb-door__request {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--lwb-sp-3);
    margin: var(--lwb-sp-6) 0 0;
    padding-top: var(--lwb-sp-5);
    border-top: 1px solid var(--lwb-ink-200);
}

.lotzwoo-b2b-shop .lwb-door__request-hint {
    font-size: var(--lwb-fs-sm);
    color: var(--lwb-ink-500);
}

