/* Techparts – Explosionszeichnung
   Eigenstaendig gestaltet, damit der Block in jedem Theme funktioniert, aber
   ueber CSS-Variablen aus den Block-Einstellungen anpassbar bleibt.

   **Jeder Selektor beginnt mit `.tpd:not(#tp-gewicht):not(#tp-gewicht)`.**
   Das zaehlt wie zwei IDs, ohne dass ein Element eine ID braucht. Anlass
   war das Plugin Divi Builder: Es wickelt jeden Seiteninhalt in
   `#et-boc .et-l` - auch auf Seiten, die mit Elementor gebaut sind - und
   setzt dort mit `#et-boc .et-l div` Rahmen, Innenabstand und Hintergrund
   zurueck. Beim Haendler stand die Karte am 27. September 2026 deshalb
   ohne Rahmen da. Gegen eine ID hilft keine Zahl von Klassen und keine
   Ladereihenfolge.

   Neue Regeln schreibt man ohne; `node dev-tools/css-gewicht.mjs` setzt das
   Gewicht nach, und die Paketierung verweigert eine Datei ohne. Die
   Einstellungen reisen als Variablen im `style` der Elemente und gelten
   weiter; eigenes CSS des Haendlers braucht jetzt `!important`. */

.tpd:not(#tp-gewicht):not(#tp-gewicht) {
  --tpd-dot-size: 26px;
  --tpd-dot-color: #2c6ecb;
  --tpd-dot-color-active: #ff8800;
  --tpd-max-height: 650px;
  --tpd-card-width: 280px;
  --tpd-card-bg: #fff;
  --tpd-card-text: #1a1a1a;
  --tpd-card-radius: 10px;
  --tpd-btn-bg: #2c6ecb;
  --tpd-btn-text: #fff;
  /* Schriftgroessen und Knopfform. Seit FREE 1.38 gehoeren sie zu PRO; ohne
     PRO gelten diese Werte - und das sind die bisherigen Vorgaben der
     Einstellungen (14 / 14 / 13 px), nicht mehr die 0.85rem aus der Zeit
     davor. Sonst saehe ein Shop ohne PRO nach dem Update anders aus. */
  --tpd-list-size: 14px;
  --tpd-card-size: 14px;
  --tpd-btn-size: 13px;
  --tpd-btn-radius: 6px;
  --tpd-title-scale: 1;
  /* Hervorhebung, ebenfalls PRO seit 1.38. Ohne diese Zeile griffen an
     einer Stelle die Rueckfallwerte #f59e0b und #0a3d62 - nie zu sehen,
     solange FREE die Variable immer setzte. */
  --tpd-highlight: #2c6ecb;
  --tpd-highlight-width: 2px;
  --tpd-border: rgba(0, 0, 0, 0.12);
  --tpd-muted: rgba(0, 0, 0, 0.55);

  container-type: inline-size;
  margin: 0 auto;

  /*
    **Volle Breite ausdruecklich, nicht als Selbstverstaendlichkeit.**

    Im normalen Fluss fuellt ein `div` seinen Elternteil von selbst - deshalb
    stand hier jahrelang keine Breite. Shopifys Theme **Horizon** legt die
    Bloecke eines Abschnitts aber im Flex-Layout an, und dort ist die
    Vorgabe `width: auto` gleichbedeutend mit "so breit wie der Inhalt".
    Zusammen mit `container-type: inline-size` schrumpft der Block dann auf
    **Wortbreite**: Am 2026-08-23 stand die leere Meldung in einer 50 px
    schmalen Spalte, ein Wort je Zeile.

    `box-sizing` gehoert dazu, weil `--empty` einen Innenabstand hat - sonst
    kaeme die Breite oben drauf und der Block liefe aus dem Abschnitt heraus.
  */
  width: 100%;
  box-sizing: border-box;
}

/*
  **Shopifys Huelle um den App-Block braucht die Breite, nicht nur der Block.**

  `container-type: inline-size` an der Wurzel ist noetig - die Zeichnung
  richtet ihre Umbrueche danach. Es hat aber eine Nebenwirkung, die man ihm
  nicht ansieht: Ein Element mit Groessen-Containment meldet nach aussen eine
  **intrinsische Breite von null**. Es sagt seinem Elternteil also "ich
  brauche keinen Platz".

  In Dawn ist das folgenlos - dort steht der Block im normalen Fluss und
  bekommt die volle Breite zugeteilt, ohne gefragt zu werden. **Horizon** legt
  die Bloecke eines Abschnitts dagegen im Flex-Layout an und fragt jeden
  einzelnen nach seiner Wunschbreite. Antwort: null. Die Huelle schrumpft
  zusammen, und `width: 100%` am Block ist dann 100 % von fast nichts - am
  2026-08-23 gemessen rund 50 px, ein Wort je Zeile.

  Deshalb bekommt die Huelle selbst die Breite. `:has()` trifft sie nur dort,
  wo wirklich einer unserer Bloecke drinsteht - fremde Bloecke im selben
  Abschnitt bleiben unberuehrt.
*/
.shopify-block:has(> .tpd),
.shopify-app-block:has(> .tpd) {
  width: 100%;
}

.tpd--empty:not(#tp-gewicht):not(#tp-gewicht) {
  border: 1px dashed var(--tpd-border);
  border-radius: var(--tpd-card-radius);
  padding: 24px;
  text-align: center;
  font-size: 0.9rem;
  opacity: 0.75;
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__header { margin-bottom: 4px; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__heading { margin: 0; font-size: 1.4rem; line-height: 1.2; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__subheading { margin: 2px 0 0; font-size: 0.9rem; color: var(--tpd-muted); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__description { margin: 8px 0 12px; font-size: 0.95rem; }

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 20px;
  align-items: start;
}
.tpd[data-list-position="below"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout {
  grid-template-columns: minmax(0, 1fr);
}
/* Die Liste links.
   Gemeldet am 2026-09-17: Die Einstellung bot drei Werte an, das Stylesheet
   kannte zwei - "left" tat nichts. Getauscht werden die Spaltenbreiten, die
   Reihenfolge macht `order` an der Liste. Das Markup bleibt, wie es ist:
   Nach der Zeichnung zu lesen ist auch dann richtig, wenn sie rechts steht,
   und die Verabredung mit dem Skript haengt an der Reihenfolge im DOM. */
.tpd[data-list-position="left"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout {
  grid-template-columns: minmax(300px, 380px) minmax(0, 1fr);
}
/* Das Rasterkind ist `.tpd__list-wrap` -- `.tpd__list` ist die Liste im
   eingefahrenen Panel und steht ganz woanders. Der erste Versuch traf
   genau die falsche: Sie ist ausgeblendet, also blieb alles, wie es war. */
.tpd[data-list-position="left"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-wrap { order: -1; }
@container (max-width: 860px) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout { grid-template-columns: minmax(0, 1fr); }
  /* Untereinander gehoert die Zeichnung nach oben - auch wenn die Liste
     auf breiten Schirmen links steht. Wer auf dem Telefon zuerst eine
     Teileliste sieht, weiss nicht, wovon sie handelt. */
  .tpd[data-list-position="left"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-wrap { order: 0; }
}

/* ---------------- Bühne ---------------- */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__stage {
  position: relative;
  border: 1px solid var(--tpd-border);
  border-radius: var(--tpd-card-radius);
  background: #fff;
  /* Siehe Viewport: kein Scrollcontainer, damit der Fokus nichts verschiebt.
     Das hereinfahrende Fenster wird weiterhin sauber abgeschnitten. */
  overflow: clip;
}

/* Fester Rahmen: Die Zeichnung wird darin zentriert und beim Zoomen
   verschoben, statt den Rahmen zu vergroessern. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport {
  position: relative;
  height: var(--tpd-max-height);
  /* `clip` statt `hidden`: `hidden` erzeugt einen Scrollcontainer, den der
     Browser selbst scrollen darf - etwa wenn der angeklickte Punkt den Fokus
     bekommt und teilweise ausserhalb liegt. Die Zeichnung ruckte dadurch beim
     Klicken zur Seite. `clip` schneidet genauso ab, laesst sich aber gar nicht
     erst scrollen. Verschieben laeuft ohnehin ueber die Transformation. */
  overflow: clip;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
}
/* Die Hoehe folgt dem Bild, statt einen festen Rahmen zu fuellen.
   Siehe NOTIZEN.md parts-diagram.liquid#40. */
.tpd[data-fit="true"]:not(.is-fullscreen):not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport { height: auto; }

/*
  **Auf schmalen Schirmen braucht der Rahmen eine Mindesthoehe.**

  Folgt er dort der Zeichnung, wird er flach - gemessen 180 px bei 390 px
  Breite. Die Artikelkarte ist rund 200 px hoch; `place()` findet dann weder
  unter noch ueber dem Punkt Platz und legt sie **auf** den Punkt. Der
  naechste Tipp landet auf dem Produktlink in der Karte statt auf dem Punkt:
  Ein Doppeltipp zum Zoomen fuehrt auf eine fremde Produktseite. Gemessen am
  2026-09-20: Punkt bei y=485, Karte von 416 bis 620.

  Eine Mindesthoehe loest das an der Wurzel, statt den zweiten Tipp zu
  unterdruecken. Weisse Baender koennen dadurch auf dem Telefon wieder
  entstehen - das ist der Preis dafuer, dass die Karte Platz hat, und er ist
  kleiner als der Preis eines falschen Seitenwechsels.
*/
@container (max-width: 560px) {
  .tpd[data-fit="true"]:not(.is-fullscreen):not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport { min-height: 360px; }
}

.tpd[data-zoom="true"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport { cursor: grab; }
.tpd[data-zoom="true"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport.is-panning { cursor: grabbing; }

/* Wer bekommt die Fingergeste?
   Nicht gezoomt: die Seite darf senkrecht scrollen, das Aufziehen mit zwei
   Fingern kommt zu uns (`pan-y` schliesst `pinch-zoom` aus).
   Gezoomt: alles zu uns, damit ein Finger die Zeichnung verschiebt.
   Im Vollbild scrollt ohnehin nichts - dort gilt durchgehend `none`. */
.tpd[data-zoom="true"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport { touch-action: pan-y; }
.tpd[data-zoom="true"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport.is-zoomed,
.tpd.is-fullscreen[data-zoom="true"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport { touch-action: none; }

/* Die Transformation sitzt hier. Weil die Hotspots Kinder sind, skalieren
   sie automatisch mit – genau das war vorher nicht der Fall.

   Bewusst OHNE `will-change: transform`: das befoerdert das Element auf eine
   eigene Compositing-Ebene, die einmal bei 100 % gerastert und danach als
   Bitmap hochskaliert wird. Ergebnis waeren unscharfe Punkte und eine
   verwaschene Zeichnung. Ohne den Hinweis rastert der Browser nach dem Zoom
   neu – gestochen scharf. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__canvas {
  position: relative;
  transform-origin: center center;
  line-height: 0;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__canvas.is-animating { transition: transform 0.18s ease-out; }

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__image {
  display: block;
  max-width: 100%;
  max-height: var(--tpd-max-height);
  width: auto;
  height: auto;
  user-select: none;
  -webkit-user-drag: none;
}

/* ---------------- Hotspots ---------------- */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot {
  position: absolute;
  /* --tpd-dot-scale wirkt gegen den Canvas-Zoom. Wie stark, bestimmt die
     Einstellung "Punkte beim Zoomen": voll mitwachsen, gedaempft oder
     konstant gross. Gesetzt wird die Variable in parts-diagram.js. */
  transform: translate(-50%, -50%) scale(var(--tpd-dot-scale, 1));
  /* Der Punkt waechst mit seiner Beschriftung.
     Bei "1" oder "12" reicht `min-width` und er bleibt ein exakter Kreis; erst
     ab drei, vier Zeichen dehnt er sich zur Pille. Positionsnummern sind
     naemlich nicht immer 1..N - manche Hersteller drucken fuenfstellige
     Nummern (Fantic: 435, 4660, 49193), und die passten bisher schlicht nicht
     hinein.
     `border-radius` muss dafuer eine Laenge sein: `50%` ergaebe bei einem
     breiten Punkt eine Ellipse, nicht die runden Enden einer Pille.
     `box-sizing` steht hier ausdruecklich, weil `min-width` sonst nur den
     Inhalt meint und der Innenabstand oben drauf kaeme - der kurze Punkt waere
     dann breiter als hoch. Auf ein globales border-box des Themes duerfen wir
     uns nicht verlassen. */
  box-sizing: border-box;
  width: auto;
  min-width: var(--tpd-dot-size);
  height: var(--tpd-dot-size);
  padding: 0 calc(var(--tpd-dot-size) * 0.2);
  white-space: nowrap;
  border-radius: var(--tpd-dot-size);
  border: 2px solid #fff;
  background: var(--tpd-dot-color);
  color: #fff;
  font-size: calc(var(--tpd-dot-size) * 0.42);
  font-weight: 700;
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  transition: background-color 0.12s ease;
  z-index: 2;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot:hover,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot:focus-visible,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot.is-active,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot.is-pinned {
  background: var(--tpd-dot-color-active);
  z-index: 3;
  outline: none;
}
/* Festgehaltene Auswahl zusaetzlich mit Ring, damit sie sich vom blossen
   Ueberfahren unterscheidet. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot.is-pinned {
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.9),
    0 0 0 5px var(--tpd-dot-color-active), 0 1px 4px rgba(0, 0, 0, 0.35);
}
/* Andere Formen als der Kreis bringt PRO mit (`techparts-pro/assets/marken.css`,
   seit FREE 1.39). */

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot:focus-visible {
  box-shadow: 0 0 0 3px rgba(255, 136, 0, 0.5);
}
/* Position ohne hinterlegtes Produkt – im Shop dezent, damit sie nicht stört. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__dot--empty { background: #9aa0a6; }

/* Während des Verschiebens keine Hover-Reaktion, sonst flackert es. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__viewport.is-panning .tpd__dot { pointer-events: none; }

/* ---------------- Zoom-Bedienung ---------------- */
/* Waagerechte Leiste statt gestapelter Symbole: Der Vollbild-Knopf traegt
   Beschriftung, weil sein Symbol allein zu haeufig fuer "maximieren" oder
   "zuruecksetzen" gehalten wird. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__toolbar {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
  max-width: calc(100% - 20px);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__toolbar:empty { display: none; }

/* Eine Pille statt einzelner Kacheln - dieselbe Gruppe wie im Admin:
   kleiner, Prozentwert, groesser, Ausgangszustand, Vollbild. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoomgroup {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--tpd-border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoomgroup:empty { display: none; }

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-btn {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: none;
  color: #1a1a1a;
  cursor: pointer;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-btn:hover { background: #eceef0; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-btn:active { transform: translateY(1px); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-btn svg {
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Der Vollbild-Knopf sitzt in derselben Gruppe. Die Farben aus den
   Theme-Einstellungen tragen jetzt den eingeschalteten Zustand - so bleiben
   sie wirksam, obwohl der Knopf keine eigene Pille mehr ist. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__fs[aria-pressed="true"] {
  background: var(--tpd-fs-btn-bg, #26303d);
  color: var(--tpd-fs-btn-text, #fff);
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-level {
  min-width: 54px;
  text-align: center;
  font-size: 0.78rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: #1a1a1a;
  white-space: nowrap;
  pointer-events: none;
}

/* ---------------- Produktkarte ---------------- */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__cards { position: absolute; inset: 0; pointer-events: none; z-index: 5; }

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card {
  position: absolute;
  width: var(--tpd-card-width);
  display: grid;
  gap: 8px;
  padding: 10px;
  background: var(--tpd-card-bg);
  color: var(--tpd-card-text);
  border: 1px solid var(--tpd-border);
  border-radius: var(--tpd-card-radius);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.16);
  pointer-events: auto;
  font-size: var(--tpd-card-size);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card[hidden] { display: none; }

/* Platz fuer den Schliessknopf - sonst laeuft die Positionsnummer darunter. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-head { display: grid; gap: 2px; padding-inline-end: 28px; }

/*
  Der Schliessknopf der Karte. Gebaut von parts-diagram.js, damit
  Produktseite und Katalog ihn aus einer Quelle bekommen.

  Bewusst kleiner und leiser als der des eingedockten Fensters: Die Karte ist
  klein, und der Knopf soll den Artikel nicht ueberstrahlen. Die Trefferflaeche
  bleibt trotzdem bei 28 px - darunter trifft ein Finger nicht zuverlaessig.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-close {
  position: absolute;
  top: 6px;
  inset-inline-end: 6px;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--tpd-muted);
  cursor: pointer;
  line-height: 1;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-close:hover { color: var(--tpd-card-text); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-close svg {
  width: 14px; height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-pos {
  font-size: 0.8em;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--tpd-muted);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-label { font-weight: 600; line-height: 1.25; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__card-meta { font-size: 0.86em; color: var(--tpd-muted); }

/* Reiter eines Produkts mit mehreren Blaettern. Sie stehen ausserhalb der
   Zeichnung, damit sie beim Umschalten stehenbleiben. */
/*
  Karteireiter sassen einmal auf dem Rahmen der Zeichnung - oben abgerundet,
  unten offen, mit `margin-block-end: -1px`. Zwischen ihnen und der Zeichnung
  steht aber die Ansichtsleiste: Sie dockten an nichts an und sahen dadurch
  unfertig aus.

  Jetzt tragen sie dieselbe Sprache wie die Ansichtsknoepfe eine Datei
  weiter unten, und aus demselben Grund: **Der gewaehlte traegt Farbe, nicht
  nur einen Rahmen.** Bei zwoelf Kaestchen nebeneinander ist ein Rahmen kaum
  vom Nachbarn zu unterscheiden - erst recht, wenn sie umbrechen.
*/
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-block-end: 12px;
}
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__tab {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  /* Groesse, Form und Farbe kommen aus den Einstellungen - die Werte hinter
     dem Komma sind das, was hier frueher fest stand, und gelten fuer jede
     Ausgabe, die keine Variablen mitbringt. */
  padding: var(--tpd-sheet-pad, 7px) var(--tpd-sheet-pad-x, 14px);
  border-radius: var(--tpd-sheet-radius, 999px);
  /* Weiss mit feinem Rahmen, nicht grau: Der Hintergrund eines Themes ist
     oft selbst hellgrau - gemessen an einem Testshop #eef1f5 -, und ein
     graues Kaestchen darauf verschwindet. Die Ansichtsleiste macht es aus
     demselben Grund so. */
  background: var(--tpd-sheet-bg, #fff);
  border: 1px solid var(--tpd-border, rgba(0, 0, 0, 0.12));
  color: var(--tpd-sheet-text, #5c6470);
  font-size: var(--tpd-sheet-size, 0.9em);
  line-height: 1.3;
  max-inline-size: var(--tpd-sheet-max, 260px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__tab:hover {
  background: #f4f5f7;
  color: #1a1a1a;
}
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__tab.is-active,
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__tab.is-active:hover {
  background: var(--tpd-sheet-active-bg, var(--tpd-highlight, var(--tpd-dot-color, #2c6ecb)));
  border-color: var(--tpd-sheet-active-bg, var(--tpd-highlight, var(--tpd-dot-color, #2c6ecb)));
  color: var(--tpd-sheet-active-text, #fff);
  font-weight: 600;
}
/* `all: unset` nimmt auch den Fokusrahmen des Browsers weg. Mit den
   Pfeiltasten waere dann nicht zu sehen, wo man steht - und nur der aktive
   Reiter traegt `tabindex="0"`, der Fokus wandert also sichtbar durch die
   Leiste. Dieselbe Luecke hatten die Punkte und der Alternativen-Schalter,
   beide haben laengst ihr `:focus-visible`. */
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__tab:focus-visible {
  outline: 2px solid var(--tpd-highlight, var(--tpd-dot-color, #0a3d62));
  outline-offset: 2px;
}

/* Das Auswahlfeld statt der Leiste - siehe NOTIZEN.md parts-diagram.liquid#38.
   Beide stehen im Markup; welches gilt, misst `parts-diagram.js`. Ohne
   Skript bleibt die Leiste stehen, und das ist der richtige Rueckfall: Sie
   ist umstaendlich, aber vollstaendig bedienbar. */
/* Auf dem Telefon steht das Feld allein ueber der Zeichnung, ohne Nachbarn,
   an denen sich das Auge orientiert - da wird es leicht fuer Zierrat
   gehalten. Deshalb eine sichtbare Beschriftung und eine Schrift, die
   groesser ist als die der Reiter, nicht kleiner. */
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__label {
  display: none;
  font-size: 0.95em;
  font-weight: 600;
  margin-block-end: 4px;
}
.tpd-blaetter-wrap:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__wahl {
  display: none;
  inline-size: 100%;
  box-sizing: border-box;
  padding: 10px 12px;
  margin-block-end: 8px;
  border: 1px solid var(--tpd-border, #d5dbe0);
  border-radius: 8px;
  background: #fff;
  font: inherit;
  font-size: 1.05em;
}
.tpd-blaetter-wrap--viele:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter {
  display: none;
}
.tpd-blaetter-wrap--viele:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__label,
.tpd-blaetter-wrap--viele:not(#tp-gewicht):not(#tp-gewicht) .tpd-blaetter__wahl {
  display: block;
}
/* Der Hinweis der Position - in der Zeile hinter dem Preis. Eigene
   Klasse, weil er dort ueber die volle Breite steht und nicht wie die
   Nummern in einer Zeile mitlaeuft. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-note { display: block; font-size: 0.86em; color: var(--tpd-muted); }

/* Position ohne Artikel: sagt es, statt eine Luecke zu lassen.
   Kein Preis, kein Knopf - siehe NOTIZEN.md tpd-part.liquid#5. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-request {
  display: inline-block;
  font-size: 0.86em;
  font-weight: 600;
  color: var(--tpd-muted);
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 1px 8px;
  margin-top: 2px;
}

/* ---------------- Ein Artikel (Karte wie Liste) ---------------- */
/* Mehrere Artikel je Position sind der Normalfall bei Gebinden und
   Ersatzartikeln – sie stehen untereinander im selben Rahmen. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__parts { display: grid; gap: 8px; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__parts .tpd__part + .tpd__part {
  border-top: 1px solid var(--tpd-border);
  padding-top: 8px;
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part {
  display: grid;
  gap: 10px;
  align-items: center;
  min-width: 0;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--card { grid-template-columns: auto minmax(0, 1fr); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--card .tpd__part-action { grid-column: 1 / -1; }
/*
  `fit-content(220px)` fuer die Aktionsspalte, nicht `auto`.

  Ein `<select>` meldet als Wunschbreite seine laengste Option. Bei
  Variantennamen wie "Ski Wax Special Edition XL - $34.95" sind das leicht
  300 px, und in einer `auto`-Spalte gewinnt dieser Wunsch gegen das `1fr` des
  Titels: Der Teilename brach auf 83 px um, waehrend das Auswahlfeld die halbe
  Zeile einnahm.

  Ein `max-width` am Feld reicht nicht - Chrome zieht fuer die Spaltenbreite
  weiter die ungekappte Wunschbreite heran. `fit-content(220px)` deckelt die
  Spalte selbst und laesst sie darunter frei schrumpfen: Zeilen ohne Varianten
  tragen nur den Knopf und bleiben so schmal wie er.
*/
/*
  ---------------------------------------------------------------- Die Kachel

  **Die Positionsnummer steht oben links, das Bild darunter, und die
  Aktionszeile unten ueber die volle Breite.**

  Vorher stand alles in *einer* Reihe: Nummer, Bild, Angaben, Warenkorb. Das
  war kompakt und in einer breiten Liste unruhig - vier verschieden hohe
  Bloecke auf einer Grundlinie, und der Preis ging zwischen Titel und Nummern
  unter.

  Jetzt fuehrt die Kachel den Blick: erst die Nummer (sie verbindet mit dem
  Punkt auf der Zeichnung), dann Titel und Preis, dann die Nummern zum
  Wiedererkennen - und ganz unten, abgesetzt, das Bestellen.

  `align-items: start`, damit Nummer und Bild oben sitzen und nicht in der
  Mitte ihrer Zeile schweben.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row {
  grid-template-columns: fit-content(60px) minmax(0, 1fr);
  grid-template-areas:
    "no    body"
    "media body"
    "action action";
  align-items: start;
  column-gap: 14px;
  row-gap: 6px;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__item-no { grid-area: no; justify-self: start; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__part-media { grid-area: media; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__part-body { grid-area: body; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__part-action { grid-area: action; justify-self: end; }

/*
  Die Nummer traegt die Kachel optisch - sie ist das, was den Eintrag mit dem
  Punkt auf der Zeichnung verbindet. Deshalb gross und in der Punktfarbe.

  `min-width` und `height` gleich gross ergeben einen exakten Kreis; eine
  lange Nummer dehnt ihn zur Pille, weil `width: auto` bleibt. Dieselbe Regel
  wie beim Punkt selbst - siehe `.tpd__dot`.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__item-no {
  /*
    Gross genug, um die Kachel zu fuehren - klein genug, um nicht zu
    dominieren. Bei 40 px zog sie den Blick vom Teilenamen ab, und der ist
    das, wonach der Kunde sucht.

    **Eine lange Nummer bricht um, sie wird nicht gekuerzt.** Positionsnummern
    sind nicht immer ein- oder zweistellig - der Fantic-Katalog fuehrt 49193,
    und aus einem Import koennen `49238ABCDEFG` werden. Ungedeckelt lief das
    Schild aus seiner Spalte heraus und legte sich ueber den Teilenamen; genau
    so sah es am 2026-08-24 aus.

    Abschneiden waere der naheliegende Griff und der falsche: Steht dort
    "49238A…", laesst sich die Zeile dem Punkt auf der Zeichnung nicht mehr
    zuordnen - und **genau dafuer ist das Abzeichen da**. Also umbrechen: Das
    Schild wird zwei Zeilen hoch und behaelt jedes Zeichen.

    `inline-flex` mit `min-width` = `min-height` haelt kurze Nummern als
    exakten Kreis; `border-radius` als Laenge, nicht in Prozent, sonst ergaebe
    ein hohes Schild eine Ellipse.
  */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  max-width: 60px;
  min-height: 30px;
  height: auto;
  padding: 3px 8px;
  line-height: 1.2;
  border-radius: 15px;
  font-size: 0.9em;
  white-space: normal;
  overflow-wrap: anywhere;
  overflow: visible;
  text-overflow: clip;
}
/* Das Bild sitzt unter der Nummer und richtet sich an ihrer Breite aus. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__part-media img,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__part-media .tpd__part-media--empty {
  width: 56px;
  height: 56px;
  border-radius: 10px;
  /* Das Symbol waechst mit dem Kaestchen mit - siehe `--empty` weiter unten. */
  background-size: 26px 26px;
}
/* Etwas Luft zwischen Titel, Preis und Nummern - in der Kachel ist Platz. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row > .tpd__part-body { gap: 3px; }
/* Nur die Groesse ist der Kachel eigen - in ihr ist Platz dafuer. Die Farbe
   steht eine Ebene hoeher, sonst haette der Preis in der Karte am Punkt und
   im eingedockten Fenster eine andere. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row .tpd__price { font-size: 1.15em; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row .tpd__meta-row { column-gap: 18px; }

/*
  Die Liste ist ihr eigener Abfragebereich.

  Ohne das misst `@container` den naechsten Vorfahren mit `container-type` -
  und das ist `.tpd`, also Zeichnung UND Liste zusammen. Der Block ist fast
  immer breiter als 560 px, die Regel unten griff deshalb nie, obwohl die
  Listenspalte daneben nur gut 400 px hat. Gemessen werden muss die Spalte, in
  der die Zeile tatsaechlich steht.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-wrap { container-type: inline-size; }

/* Schmale Liste: Das Formular rutscht unter die Angaben, statt dem Teilenamen
   den letzten Platz zu nehmen.

   Die Regel galt ueber `:has(.tpd__select)` einmal **nur** fuer Zeilen mit
   Variantenauswahl - mit der Begruendung, wo bloss der Knopf stehe, passe er
   weiter daneben. Das stimmte, solange dort bloss ein Knopf stand. Seit der
   Mengenwaehler vor jedem "In den Warenkorb" sitzt, braucht die Spalte gut
   200 px statt 110; in einer 450 px breiten Liste bleiben dem Teilenamen
   damit rund 120 px, und er bricht auf drei Zeilen um. Genau so sah es aus.

   Die Auswahl ist also nie das Merkmal gewesen - die Breite der Aktionsspalte
   ist es. Wer hier wieder einschraenkt, muss nachrechnen, was rechts steht. */
/*
  **Die schmale Liste ordnet wie die breite** - seit dem 2026-08-24.

  Hier stand eine Sonderbehandlung: Die Positionsnummer bekam eine eigene
  Zeile ueber dem Inhalt, und "3x in der Zeichnung" wurde per Raster neben sie
  gelegt. Der Grund war echt - seit die Nummer mit ihrer Beschriftung waechst,
  schob eine lange Nummer Bild und Text vor sich her, und dem Teilenamen blieb
  in einer 450 px schmalen Liste fast nichts.

  **Der Deckel an der Spalte loest dasselbe Problem, ohne eine Zeile zu
  kosten:** `fit-content(72px)` laesst die Nummer wachsen, bis sie so breit
  ist wie das Bild darunter, und kappt sie dann. Bild und Titel stehen damit
  in jeder Zeile an derselben Stelle - genau das, was die eigene Zeile
  erreichen sollte -, und der Titel beginnt oben neben der Nummer statt
  darunter.

  Die Marke steht seitdem unten in der Bestellzeile, wo sie laut Vorlage
  hingehoert; die Rasterakrobatik dafuer ist damit gegenstandslos.

  Was bleibt, ist der engere Spaltenabstand - in einer schmalen Liste zaehlt
  jeder Pixel.
*/
@container (max-width: 560px) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part--row { column-gap: 10px; }
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-media img,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-media--empty {
  display: block;
  width: 48px;
  height: 48px;
  object-fit: contain;
  border-radius: 6px;
}

/*
  **Kein grauer Grund hinter einem echten Produktbild.**

  Der Grund war einmal fuer beide da - Bild wie Leerstelle -, und bei einem
  freigestellten PNG sah man ihn als Kasten dahinter. Ersatzteilbilder sind
  fast immer freigestellt; der Kasten war also die Regel, nicht die Ausnahme.
  Die Leerstelle braucht ihn weiterhin, sonst waere sie unsichtbar.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-media--empty {
  /*
    **Ein gezeichneter Platzhalter statt einer grauen Flaeche.**

    Eine leere Flaeche liest sich wie ein Bild, das noch laedt - der Kunde
    wartet auf etwas, das nie kommt. Das Symbol sagt: Zu diesem Teil gibt es
    kein Bild, und daran aendert sich auch nichts.

    Als Data-URI im Stylesheet, nicht als Datei: Es ist ein paar hundert Byte,
    und eine eigene Datei waere ein zusaetzlicher Abruf je Seite - bei einer
    Teileliste mit dreissig Positionen ohne Bild der schlechtere Handel.
    `stroke` traegt die gedaempfte Textfarbe des Blocks, damit es sich in ein
    dunkles Theme einfuegt.
  */
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-opacity='.28' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='2.5'/%3E%3Ccircle cx='8.5' cy='9.5' r='1.6'/%3E%3Cpath d='M4 17l4.5-4.5a2 2 0 0 1 2.8 0L15 16'/%3E%3Cpath d='M14 15l1.8-1.8a2 2 0 0 1 2.8 0L20 14.6'/%3E%3C/svg%3E")
      center / 22px 22px no-repeat,
    rgba(0, 0, 0, 0.04);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-body { display: grid; gap: 1px; min-width: 0; }
/* Der Titel haengt am Verhaeltnis zur Zeile, nicht an einem eigenen
   Pixelwert: Sonst bliebe er stehen, sobald die Zeile groesser gestellt wird,
   und der Haendler muesste zwei Regler von Hand im Gleichlauf halten. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-title {
  font-weight: 600;
  font-size: calc(1em * var(--tpd-title-scale, 1));
  line-height: 1.25;
  color: inherit;
  text-decoration: none;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-title:hover { text-decoration: underline; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__part-action { min-width: 0; }

/* ---------------- Preis, Artikelnummer, Lager ----------------
   Alle Groessen hier in `em`, nicht in `rem`: Sie sollen sich an der
   Grundgroesse von Karte bzw. Listenzeile ausrichten, damit ein Regler die
   ganze Zeile mitnimmt. Mit `rem` hing nur der Preis am Regler - er ist der
   einzige ohne eigene Angabe -, alles andere blieb stehen. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__prices { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
/* Blau wie der Warenkorb-Knopf: Der Preis ist die Angabe, wegen der der
   Kunde hinsieht, und er soll in Karte, Kachel und Fenster gleich aussehen.
   Die Farbe stand einmal nur an der Kachel - in der Karte am Punkt war
   derselbe Preis schwarz, und das sah aus wie zwei verschiedene Dinge. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__price { font-weight: 700; color: var(--tpd-btn-bg); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__price-was { color: var(--tpd-muted); font-size: 0.85em; }

/* Zeilen- und Spaltenabstand getrennt.
   In der schmalen Karte bricht die Zeile ohnehin um, und ein gemeinsames
   `gap` galt dann auch senkrecht: Artikelnummer, OEM-Nummer und Lagerstand
   standen mit je 8 px Luft untereinander und machten die Kachel unnoetig hoch.
   Waagerecht braucht es den Abstand weiterhin - nebeneinander kleben die
   Nummern sonst aneinander. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__meta-row {
  display: flex;
  align-items: center;
  column-gap: 10px;
  row-gap: 0;
  line-height: 1.35;
  flex-wrap: wrap;
  font-size: 0.86em;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__sku { color: var(--tpd-muted); font-variant-numeric: tabular-nums; }
/* Die OEM-Nummer traegt ihre Beschriftung mit, die eigene Artikelnummer nicht -
   sonst wird die Zeile doppelt so lang, ohne mehr zu sagen. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__sku--oem { white-space: nowrap; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__stock--in { color: #0c7a43; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__stock--out { color: #b42318; }

/* ---------------- Warenkorb-Formular ---------------- */
/*
  Flex statt Grid, seit der Mengenwaehler dazugekommen ist.

  Das Formular traegt jetzt bis zu drei Dinge: Variantenauswahl, Mengenwaehler
  und Knopf. Im Grid brauchte jede Kombination ihre eigene Spaltenangabe - mit
  `flex-wrap` sucht sich die Auswahl ihre eigene Zeile, sobald es eng wird,
  und Menge und Knopf bleiben beieinander.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__form--card { margin-top: 6px; }
/* Die Auswahl nimmt die ganze Zeile: Ihre Optionen sind lang, und neben Menge
   und Knopf bliebe vom Variantennamen nichts uebrig. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__select { flex: 1 1 100%; }
/* Der Knopf bekommt keine feste Breite: Neben dem Mengenwaehler passt er in
   eine 280 px breite Karte, und wird die Beschriftung laenger, rutscht er
   durch `flex-wrap` von selbst in die naechste Zeile. */

/*
  **Der "View cart"-Link kommt von WooCommerce, nicht von uns.**

  Wir loesen nach einem erfolgreichen Kauf das jQuery-Ereignis `added_to_cart`
  aus und geben den Knopf mit - das muessen wir, sonst aktualisieren fremde
  Warenkorb-Widgets ihre Zahl nicht. WooCommerces eigener Zuhoerer haengt
  daraufhin einen Link "In den Warenkorb ansehen" **hinter** den Knopf.

  Unbedacht sprengt der die Zeile: Menge, Kaufknopf und Link nebeneinander
  passen in eine 280 px breite Karte nicht mehr. Er bekommt deshalb eine
  eigene Zeile und die Gestalt eines Nebenhinweises - er ist einer.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__form .added_to_cart {
  flex: 1 1 100%;
  order: 99;
  margin-top: 2px;
  font-size: 0.85em;
  text-decoration: underline;
  color: var(--tpd-muted);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__form .added_to_cart:hover { color: var(--tpd-card-text); }

/* ---------------- Mengenwaehler ---------------- */
/*
  Steht in Karte **und** Listenzeile links vor dem Knopf. Vorher trug nur die
  Karte ein Feld, die Zeile eine versteckte Menge; wer aus der Liste zwei
  Schrauben wollte, musste zweimal klicken - und merkte es erst im Warenkorb.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty-group {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--tpd-border);
  border-radius: 6px;
  overflow: hidden;
  background: var(--tpd-card-bg);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty-btn {
  font: inherit;
  font-size: 1em;
  line-height: 1;
  width: 26px;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  /* Der Knopf traegt nur ein Zeichen - ohne das sitzt es je nach Schrift des
     Themes schief. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty-btn:hover { background: rgba(0, 0, 0, 0.06); }

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__select,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty {
  font: inherit;
  font-size: 0.92em;
  padding: 6px;
  border: 1px solid var(--tpd-border);
  border-radius: 6px;
  background: var(--tpd-card-bg);
  color: inherit;
  min-width: 0;
  /* Fuellt die gedeckelte Spalte und kuerzt den ueberzaehligen Text selbst. */
  width: 100%;
  max-width: 100%;
}
/* Im Waehler traegt die Gruppe den Rahmen, nicht das Feld - sonst stuenden
   zwei ineinander. Die eigenen Pfeilchen des Browsers fallen weg: Dafuer gibt
   es links und rechts einen Knopf, und in 34 px Breite haetten sie ohnehin
   keinen Platz. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty {
  width: 34px;
  padding: 6px 2px;
  border: 0;
  border-radius: 0;
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty::-webkit-outer-spin-button,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/*
  **Der Riegel gegen die Breitenregel des Themes.**

  Gemeldet am 2026-09-17 mit zwei Bildern: In der Shopify-Fassung stehen
  Mengenwaehler und Knopf kompakt nebeneinander, im Shop des Haendlers lief der
  Waehler ueber die ganze Kartenbreite und der Knopf rutschte in die naechste
  Zeile.

  Der Grund liegt nicht hier, sondern in der Nachbarschaft: Sehr viele Themes
  bringen eine Regel wie `input[type="number"] { width: 100% }` mit. Die ist
  spezifischer als ein blankes `.tpd__qty` - also gewinnt sie. Nachgemessen mit
  `npm run mengenfeld`: Das Feld wuchs von 34 px auf 175 px, die Gruppe auf
  218 px, und der Knopf fand keinen Platz mehr.

  Drei Klassen hintereinander schlagen die ueblichen Theme-Regeln, ohne dass
  irgendwo ein `!important` stehen muss. Das ist die Grenze, die hier
  angemessen ist: Wer sein Theme ausdruecklich staerker schreibt, soll gewinnen
  duerfen - aber nicht versehentlich.

  `flex: 0 0 auto` gehoert dazu. Ohne das darf die Gruppe im Formular wachsen,
  auch wenn das Feld darin schmal bleibt.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__form .tpd__qty-group {
  flex: 0 0 auto;
  width: auto;
  max-width: none;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty-group .tpd__qty {
  flex: 0 0 38px;
  box-sizing: border-box;
  width: 38px;
  min-width: 38px;
  max-width: 38px;
  /*
    **Der Innenabstand gehoert dazu, und er ist die gemeinere Haelfte.**

    Solange das Feld ueber die ganze Karte lief, fiel ein grosszuegiges
    `padding` des Themes nicht auf. Sobald es schmal ist, frisst es den Platz
    fuer die Ziffer: Bei `border-box` bleibt von 38 px minus zweimal 18 px
    nichts uebrig - das Feld ist dann sichtbar leer. Gemeldet am 2026-09-17
    mit "jetzt erscheint keine Zahl mehr".

    Deshalb stehen hier auch Abstand, Schriftgroesse und Zeilenhoehe. Eine
    halbe Vorgabe ist schlimmer als keine: Sie macht das Feld schmal und
    ueberlaesst den Inhalt dem Zufall.
  */
  padding: 6px 2px;
  font-size: 0.92em;
  line-height: 1.3;
  text-align: center;
  height: auto;
  min-height: 0;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__qty-group .tpd__qty-btn {
  flex: 0 0 26px;
  box-sizing: border-box;
  width: 26px;
  min-width: 26px;
}
/* Derselbe Gedanke fuer den Knopf: `button { width: 100% }` ist in Themes
   ebenso verbreitet, und dann steht er allein in seiner Zeile. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__form .tpd__button {
  flex: 0 0 auto;
  width: auto;
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__button {
  font: inherit;
  font-size: var(--tpd-btn-size);
  font-weight: 600;
  padding: 9px 14px;
  border: 0;
  border-radius: var(--tpd-btn-radius);
  background: var(--tpd-btn-bg);
  color: var(--tpd-btn-text);
  cursor: pointer;
  white-space: nowrap;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__button:hover:not([disabled]) { filter: brightness(0.92); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__button[disabled] {
  background: rgba(0, 0, 0, 0.08);
  color: var(--tpd-muted);
  cursor: not-allowed;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__button.is-busy { opacity: 0.6; pointer-events: none; }

/* ---------------- Teileliste ---------------- */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-heading { margin: 0; font-size: 1.05rem; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-count { font-size: 0.8rem; color: var(--tpd-muted); }

/* ---------------- Suche in der Teileliste ----------------
   Das Feld sitzt zwischen Ueberschrift und Liste. Es filtert nur, was ohnehin
   auf der Seite steht - kein Netzaufruf, kein Warten. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__search { margin: 0 0 8px; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__search-input {
  font: inherit;
  font-size: 0.9em;
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--tpd-border);
  border-radius: 6px;
  background: var(--tpd-card-bg);
  color: inherit;
}
/* Zeilen ohne Treffer werden verborgen, nicht entfernt: In ihnen stecken die
   Warenkorb-Formulare, und eine aufgeklappte Alternativenliste soll nach dem
   Leeren des Feldes noch so dastehen wie vorher. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item.is-filtered { display: none; }
/* Bleibt gar nichts uebrig, verschwindet auch der Rahmen der leeren Liste. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__list.is-filtered { display: none; }

/* Waehrend gesucht wird, treten die uebrigen Punkte zurueck. Nicht ausblenden:
   Wer sucht, will sehen, *wo* der Treffer in der Zeichnung sitzt - dafuer
   braucht er die anderen Positionen als Anhaltspunkt. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__canvas.is-searching .tpd__dot { opacity: 0.25; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__canvas.is-searching .tpd__dot.is-found {
  opacity: 1;
  background: var(--tpd-dot-color-active);
  box-shadow: 0 0 0 3px var(--tpd-highlight, #f59e0b), 0 1px 4px rgba(0, 0, 0, 0.35);
  z-index: 3;
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__list {
  list-style: none;
  margin: 0;
  /* Rundum etwas Luft, damit Rahmen und Fokusringe nicht an der Scrollkante
     abgeschnitten werden. */
  padding: 2px 4px;
  display: grid;
  gap: 10px;
  max-height: var(--tpd-max-height);
  overflow-y: auto;
}
.tpd[data-list-position="below"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__list {
  max-height: none;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}

/* Eine Position = eine Karte. Mehrere Artikel darin bleiben dadurch beim
   Anklicken des Hotspots sichtbar als zusammengehoerig markiert. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Mehr Luft als frueher (10 px): Die Kachel traegt jetzt drei Zeilen statt
     einer, und ohne Rand wirkte sie gedraengt. */
  padding: 14px;
  font-size: var(--tpd-list-size);
  border: 1px solid var(--tpd-border);
  border-radius: var(--tpd-card-radius);
  background: var(--tpd-card-bg);
  color: var(--tpd-card-text);
  cursor: pointer;
  scroll-margin: 12px;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item .tpd__part + .tpd__part {
  border-top: 1px solid var(--tpd-border);
  padding-top: 8px;
}
/* Kopfzeile der Karte: links der Hinweis auf mehrere Fundorte, rechts der
   Schalter fuer weitere Artikel. Beide sind optional - die Zeile entsteht nur,
   wenn es etwas zu zeigen gibt. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
/* Hinweis, dass dieselbe Position mehrfach in der Zeichnung sitzt. Steht ganz
   oben in der Karte, damit der Kunde weiss, warum beim Anklicken mehrere
   Punkte aufleuchten. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item-times {
  padding: 3px 12px;
  border-radius: 999px;
  /*
    Ein eigener, sehr blasser Ton statt des Rahmengraus.

    Der Hinweis ist keine Warnung und keine Aktion - er erklaert, warum beim
    Anklicken mehrere Punkte aufleuchten. Grau ging darin unter, kraeftig
    waere zu viel. Als Variable, damit ein Theme ihn mitnehmen kann.
  */
  background: var(--tpd-mark-bg, #fdeaea);
  color: var(--tpd-mark-text, #7a3b3b);
  font-size: 0.78em;
  line-height: 1.6;
}
/*
  **Die Marke steht auf der Zeile des Warenkorbs, links davon.**

  Sie wird dafuer aus dem Fluss genommen und unten links in der Karte
  verankert. Der Platz dort ist frei, weil die Bestellzeile rechtsbuendig
  steht.

  **Ein erster Anlauf legte statt der Marke die ganze Leiste dorthin, und das
  ging schief:** In der Leiste steht neben der Marke auch der Schalter
  "Weitere Artikel" - zusammen waren sie breiter als der freie Platz, die
  Leiste brach um, und die Marke rutschte in die Mitte der Karte, quer ueber
  Bild und Artikelnummer. Genau so sah es am 2026-08-24 aus.

  Die beiden gehoeren auch nicht zusammen: Die Marke erklaert die Zeichnung,
  der Schalter klappt Artikel auf. Der Schalter bleibt deshalb, wo er war.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item { position: relative; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item-times {
  position: absolute;
  inset-inline-start: 14px;
  inset-block-end: 14px;
  /* Eine Zeile, nie zwei - umgebrochen sieht die Marke aus wie ein Absatz,
     der in die Karte gerutscht ist. */
  white-space: nowrap;
}
/*
  **In einer schmalen Liste geht sie zurueck nach oben.**

  Neben dem Warenkorb stehen Mengenwaehler und Knopf, zusammen gut 230 px.
  Die Marke braucht rund 150. In einer 360 px schmalen Teileliste ist fuer
  beides kein Platz - sie ueberdeckten einander oder die Marke braeche um.

  Oben in der Karte hat sie ihn immer. Das war ihr urspruenglicher Ort, und
  bei einem Kunden, der auf dem Telefon liest, ist eine Zeile mehr das
  kleinere Uebel als eine Marke quer ueber der Artikelnummer.
*/
@container (max-width: 560px) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item-times { position: static; }
}
/*
  Die Leiste traegt nur noch die Marke, und die liegt absolut - der Kasten
  selbst wird deshalb aufgeloest, statt eine leere Zeile stehen zu lassen, die
  ueber den Kartenabstand acht Pixel kostet.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item > .tpd__item-meta { display: contents; }

/*
  **Die Kopfzeile der Karte steht unten.**

  Sie hiess einmal so, weil sie oben stand: Der Hinweis "3x in der Zeichnung"
  sollte gelesen werden, bevor der Kunde sich wundert. In der neuen Kachel
  gehoert er auf die Zeile des Bestellens - dort steht ohnehin der Blick, und
  oben nahm er dem Titel den Anfang.

  `order` statt einer anderen Reihenfolge im Markup: Das Snippet wird von der
  Karte **und** vom eingedockten Fenster gerendert, und beide sollen dieselbe
  Quelle behalten.
*/
/* Die Leiste steht wieder oben - siehe oben, die Marke liegt nicht mehr
   darin, sondern unten links in der Karte. */
/* Die weiteren Artikel einer Position (Alternativen) bringt seit FREE 1.41
   PRO mit (`techparts-pro/assets/alternativen.css`). */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item:hover,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item:focus-visible {
  border-color: var(--tpd-highlight, var(--tpd-dot-color));
  outline: none;
}
/*
  Aktive Position. Der Ring liegt bewusst INNEN (inset): die Liste ist ein
  Scroll-Container, ein aeusserer Schatten wuerde an ihrer Kante abgeschnitten
  – links war er dadurch nur halb zu sehen.

  Der 1px-Rahmen zaehlt zur Gesamtstaerke, deshalb legt der Ring nur die
  Differenz drauf. --tpd-highlight-width ist damit wirklich die Dicke, die man
  am Ende sieht.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item.is-active,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item.is-pinned {
  border-color: var(--tpd-highlight, #2c6ecb);
  box-shadow: inset 0 0 0
    calc(var(--tpd-highlight-width, 2px) - 1px)
    var(--tpd-highlight, #2c6ecb);
  outline: none;
}

/* Das Abzeichen der Listenzeile waechst mit seiner Beschriftung — **dieselbe
   Regel wie beim Punkt auf der Zeichnung**, nur eine Stelle weiter.

   Es war ein starrer Kreis mit `border-radius: 50%`, und bei einer langen
   Positionsnummer stand dort "ABC" statt "ABCDEFGH". Der Punkt darf laengst
   zur Pille werden (`.tpd__dot`); das Abzeichen muss es auch, sonst laesst
   sich die Zeile der Zeichnung nicht mehr zuordnen — und genau dafuer ist es
   da.

   Dieselben zwei Fallstricke wie beim Punkt: `border-radius` muss eine
   **Laenge** sein (50 % ergaebe bei einer breiten Pille eine Ellipse statt
   runder Enden), und `box-sizing: border-box` gehoert dazu, sonst meint
   `min-width` nur den Inhalt und der kurze Fall ist breiter als hoch.

   `flex: none`, damit die Pille in der schmalen Zeile nicht zusammen-
   geschoben wird, und ein Deckel: Ab etwa zwoelf Zeichen frisst sie sonst den
   Platz des Teilenamens. Was darueber hinausgeht, endet mit Auslassung —
   realistische Nummern (Fantic 49193, TYM 1-01) passen vollstaendig hinein.

   **Rein ueber CSS geloest, absichtlich.** Vier Stellen bauen dieses Abzeichen
   — zwei in Liquid, zwei in parts-catalog.js. Eine Loesung im Markup muesste
   an allen vieren gleich sein; eine im Stil gilt fuer alle von selbst. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item-no {
  display: inline-block;
  box-sizing: border-box;
  flex: none;
  min-width: 26px;
  max-width: 108px;
  height: 26px;
  padding: 0 7px;
  line-height: 26px;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border-radius: 13px;
  background: var(--tpd-dot-color);
  color: #fff;
  font-size: 0.82em;
  font-weight: 700;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item.is-active .tpd__item-no,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__item.is-pinned .tpd__item-no { background: var(--tpd-dot-color-active); }

/* ---------------- Toast ---------------- */
/*
  Der Hinweisbalken nach dem Hinzufuegen.

  **Er ist der Beleg, nicht die Dekoration.** Ob ein fremdes Theme seinen
  Zaehler am Warenkorbsymbol nachzieht, laesst sich nicht erzwingen - wir
  kennen es nicht. Dass der Kunde erfaehrt, was jetzt im Warenkorb liegt,
  schon. Deshalb faehrt er von unten herein statt bloss aufzublenden, traegt
  ein Hakensymbol und bleibt vier Sekunden: Am 2026-08-24 hat ihn jemand
  uebersehen, der gezielt danach gesucht hat.
*/
.tpd__toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  z-index: 9999;
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: calc(100vw - 32px);
  background: #1a1a1a;
  color: #fff;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 13px 20px;
  border-radius: 10px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
  opacity: 0;
  /* Zwei Verschiebungen in einer Angabe: die Mitte und der Weg von unten. */
  transform: translateX(-50%) translateY(12px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
/*
  Das Hakensymbol steht im Stylesheet, nicht im Markup - der Balken wird an
  einer Stelle gebaut, aber fuer zwei Faelle benutzt, und ein Fehler soll kein
  Haekchen tragen.
*/
.tpd__toast::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E")
      center / 18px 18px no-repeat;
}
.tpd__toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .tpd__toast { transition: opacity 0.2s ease; transform: translateX(-50%); }
  .tpd__toast.is-visible { transform: translateX(-50%); }
}
.tpd__toast--error { background: #b42318; }
/* Ein Fehler bekommt ein Ausrufezeichen statt des Hakens. */
.tpd__toast--error::before {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M12 7v7'/%3E%3Cpath d='M12 17.5v.5'/%3E%3C/svg%3E");
}

@media (prefers-reduced-motion: reduce) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__canvas.is-animating { transition: none; }
}

/* ---------------- Vollbild ---------------- */
/* Die Zeichnung deckt das Fenster ab, die Teileliste weicht dem Platz. Was
   sie gezeigt hat, uebernimmt das Fenster, das beim Klick auf einen Punkt
   hereinfaehrt - so bleibt die volle Breite fuer die Zeichnung.

   `position: fixed` statt der Fullscreen-API: Diese wuerde die Browserleiste
   ausblenden, verlangt eine Nutzergeste und verhaelt sich auf iOS anders. Der
   feste Ueberzug tut dasselbe und ist ueberall gleich. */
.tpd.is-fullscreen:not(#tp-gewicht):not(#tp-gewicht) {
  position: fixed;
  inset: 0;
  /* Ausdrueckliche Groesse zusaetzlich zu `inset`: `dvh` folgt auf Mobilgeraeten
     der ein- und ausfahrenden Adressleiste, `vh` tut das nicht und liesse den
     unteren Rand unter der Leiste verschwinden. */
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  /* Ohne das rechnet der Browser den Innenabstand auf die Hoehe drauf - der
     Ueberzug waere 24 px hoeher als das Fenster, und das von unten
     hereinfahrende Fenster raendte unter dem Bildschirmrand. Die meisten
     Themes setzen border-box global, verlassen duerfen wir uns darauf nicht. */
  box-sizing: border-box;
  z-index: 2147483000;
  margin: 0;
  padding: 12px;
  background: var(--tpd-fs-bg, #fff);
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow: clip;
}
/* ---------------- Nur die Zeichnung ---------------- */
/*
   Die zweite Ansicht: Zeichnung ueber die ganze Breite, keine Teileliste
   daneben. Alles darueber - Pfad, Auswahlfelder, Suche - bleibt stehen; das
   ist der Unterschied zum Vollbild, das die Seite verdeckt.

   Beim Ueberfahren eines Punktes erscheint hier die **schwebende Karte** am
   Punkt, nicht das hereinfahrende Fenster. Dafuer ist nichts zu tun: Das
   Fenster gehoert allein zum Vollbild, weil es dort keine Liste gibt, aus der
   heraus sich kaufen liesse. Ausserhalb des Vollbilds war die Karte schon
   immer der Weg.
*/
.tpd[data-view="wide"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-wrap { display: none; }

/*
  Und die Gegenrichtung: nur die Teileliste.

  Ein anderer Anlass als die beiden anderen Ansichten - hier weiss der Kunde
  schon, was er braucht, und will bestellen: zwoelf Positionen abhaken, Preise
  ueberfliegen, Mengen setzen. Die Zeichnung ist dabei im Weg, auf dem Telefon
  ganz besonders: Dort bricht die geteilte Ansicht ohnehin untereinander um,
  und man scrollt an der ganzen Zeichnung vorbei, bevor die Liste anfaengt.

  Mit der Buehne verschwinden Zoomleiste und Vollbildknopf von selbst - sie
  stecken darin.
*/
.tpd[data-view="list"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__stage { display: none; }

/*
  Und die Mitte: Zeichnung ueber die ganze Breite, Liste darunter.

  Dieselbe Aufteilung, die `data-list-position="below"` dem Haendler anbietet -
  hier waehlt sie der Kunde. Beides bleibt: Der Haendler bestimmt, womit der
  Katalog aufmacht, der Kunde darf umschalten.
*/
.tpd[data-view="below"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout,
.tpd[data-view="wide"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout,
.tpd[data-view="list"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout {
  grid-template-columns: minmax(0, 1fr);
}

/* Die Umschalter. Sitzen rechts in der Kopfzeile, auf Hoehe der Ueberschrift. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__header--split {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
/* `margin-left: auto` statt `justify-content: space-between`: Auf der
   Produktseite darf die Ueberschrift fehlen, und dann steht in der Kopfzeile
   nur die Knopfgruppe. Mit `space-between` klebte sie links. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views {
  margin-left: auto;
  display: inline-flex;
  border: 1px solid var(--tpd-border);
  border-radius: var(--tpd-card-radius, 10px);
  overflow: hidden;
  background: #fff;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__view-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 32px;
  padding: 0;
  border: 0;
  background: transparent;
  color: #5c6470;
  cursor: pointer;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__view-btn + .tpd__view-btn { border-left: 1px solid var(--tpd-border); }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__view-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__view-btn:hover { background: #f1f2f4; }

/*
  **Die Ansichten schweben oben links im Zeichnungsfenster** (seit 1.0.1, wie
  die Shopware-Fassung) - gegenueber der Zoomleiste und in derselben Gestalt:
  eine Pille mit Schatten, Knoepfe mit runden Ecken statt Trennstrichen.

  Die zweite Gruppe in der Kopfzeile erscheint nur in "Nur die Teileliste" -
  dort ist das Fenster verborgen. Eine Kopfzeile ohne Ueberschrift (das
  Skript legt sie fuer diese Gruppe an) gibt es nur dann.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views.is-in-figure {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 6;
  gap: 2px;
  margin: 0;
  padding: 3px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views.is-in-figure .tpd__view-btn {
  width: 32px;
  border-radius: 7px;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views.is-in-figure .tpd__view-btn + .tpd__view-btn { border-left: 0; }

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__header .tpd__views { display: none; }
.tpd[data-view="list"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__header .tpd__views { display: inline-flex; }
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__header--split:not(:has(.tpd__heading)) { display: none; }
.tpd[data-view="list"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__header--split { display: flex; }

/*
  Auf dem Telefon verdecken beide Leisten zu viel von der Zeichnung - und
  nebeneinander passten sie auf 360 px nicht mehr. Kleiner, wie in Shopware.
*/
@container (max-width: 560px) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views.is-in-figure {
    top: 6px;
    left: 6px;
    padding: 2px;
  }
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views.is-in-figure .tpd__view-btn,
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-btn {
    width: 28px;
    height: 28px;
  }
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__views.is-in-figure .tpd__view-btn svg,
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-btn svg {
    width: 16px;
    height: 16px;
  }
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__toolbar {
    top: 6px;
    right: 6px;
  }
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoomgroup { padding: 2px; }
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__zoom-level {
    min-width: 42px;
    font-size: 0.7rem;
  }
}

/*
  Auf schmalen Schirmen faellt "geteilt" weg.

  Unter 860 px bricht die geteilte Ansicht ohnehin in eine Spalte um (siehe
  `.tpd__layout` weiter oben) - sie sieht dort also aus wie "Zeichnung ueber
  der Teileliste". Zwei Symbole, die dasselbe tun, sind schlimmer als eines
  weniger: Wer aufs zweite tippt und nichts geschehen sieht, haelt die Leiste
  fuer kaputt.

  Die Ansicht selbst faellt dabei in parts-diagram.js auf "below" zurueck,
  ohne die gespeicherte Wahl anzufassen - am Schreibtisch gilt sie wieder.
*/
@container (max-width: 860px) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__view-btn[data-tpd-view="split"] { display: none; }
}
/* Die gewaehlte Ansicht traegt Farbe, nicht nur einen Rahmen: Bei zwei
   Knoepfen nebeneinander ist ein Rahmen kaum vom Nachbarn zu unterscheiden. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__view-btn[aria-pressed="true"] {
  background: var(--tpd-highlight, #2c6ecb);
  color: #fff;
}

.tpd.is-fullscreen:not(#tp-gewicht):not(#tp-gewicht) .tpd__description { display: none; }
/* Im Vollbild ist die Umschaltung gegenstandslos - dort gibt es nie eine
   Liste daneben. */
.tpd.is-fullscreen:not(#tp-gewicht):not(#tp-gewicht) .tpd__views { display: none; }
.tpd.is-fullscreen:not(#tp-gewicht):not(#tp-gewicht) .tpd__list-wrap { display: none; }
.tpd.is-fullscreen:not(#tp-gewicht):not(#tp-gewicht) .tpd__layout {
  grid-template-columns: minmax(0, 1fr);
  flex: 1;
  min-height: 0;
}
.tpd.is-fullscreen:not(#tp-gewicht):not(#tp-gewicht) .tpd__stage { height: 100%; }

/* Waehrend das Vollbild offen ist, darf die Seite darunter nicht scrollen. */
body.tpd-fullscreen-open { overflow: hidden; }


/* ---------------- Hereinfahrendes Fenster ---------------- */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel {
  position: absolute;
  z-index: 20;
  display: flex;
  flex-direction: column;
  background: var(--tpd-card-bg);
  color: var(--tpd-card-text);
  border: 1px solid var(--tpd-border);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
  transition: transform 0.22s ease-out;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel[hidden] { display: none; }
/*
  **Auch das Fenster ist sein eigener Abfragebereich.**

  Dieselbe Falle wie bei `.tpd__list-wrap` weiter oben, nur eine Ebene tiefer
  und deshalb beim ersten Mal uebersehen: Ohne `container-type` misst
  `@container` den naechsten Vorfahren, der einen hat - und das ist `.tpd`.
  Im Vollbild ist das der ganze Schirm, also weit ueber 560 px. Die Regeln
  fuer die schmale Karte griffen im Fenster deshalb nie, obwohl das Fenster
  gut 400 px breit ist.

  Sichtbar wurde es am 22. September 2026 auf einer Divi-Produktseite: Die
  Pille "2x in der Zeichnung" blieb absolut positioniert und lag quer ueber
  dem Mengenfeld.

  Der Behaelter sitzt auf der **Liste**, nicht auf dem Fenster - gleiche Stelle
  wie bei `.tpd__list-wrap`, damit beide Listen nach derselben Regel gemessen
  werden. Auf dem Fenster taete er dasselbe; nachgemessen ergibt beides
  340 px Fensterbreite und eine statische Pille.

  *Dass ich das nachgemessen habe, hat einen Grund.* Ein erster Messwert
  behauptete, `container-type` auf dem Fenster lasse es auf 1,6 px
  zusammenfallen - und ich habe die Regel daraufhin verschoben. Der Wert war
  falsch: Die Browserflaeche hatte in dem Moment die Groesse **null**
  (`window.innerWidth === 0`), und in einem nullbreiten Fenster ist jede
  Breitenmessung Unfug. Der Screenshot daneben zeigte die ganze Zeit ein
  sauberes Fenster. **Ich habe der Zahl geglaubt statt dem Bild** - derselbe
  Fehler wie beim Mobil-Lauf im September, nur in klein.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list { container-type: inline-size; }

/* Jede Seite faehrt aus ihrer eigenen Richtung herein. */
.tpd[data-panel-position="right"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel {
  top: 0; bottom: 0; right: 0;
  width: min(var(--tpd-panel-size, 340px), 92vw);
  border-radius: var(--tpd-card-radius) 0 0 var(--tpd-card-radius);
  transform: translateX(100%);
}
.tpd[data-panel-position="left"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel {
  top: 0; bottom: 0; left: 0;
  width: min(var(--tpd-panel-size, 340px), 92vw);
  border-radius: 0 var(--tpd-card-radius) var(--tpd-card-radius) 0;
  transform: translateX(-100%);
}
.tpd[data-panel-position="bottom"]:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel {
  left: 0; right: 0; bottom: 0;
  max-height: min(var(--tpd-panel-size, 340px), 70vh);
  border-radius: var(--tpd-card-radius) var(--tpd-card-radius) 0 0;
  transform: translateY(100%);
}
/* Muss den Positionsregeln oben standhalten: die tragen `.tpd` plus
   Attribut plus Klasse und waeren sonst spezifischer - das Fenster bliebe
   ausgefahren stehen, obwohl es gefuellt ist. */
.tpd[data-panel-position]:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel.is-open { transform: none; }

/* Auf schmalen Bildschirmen faehrt das Fenster von unten herein, egal was
   fuer den Desktop eingestellt ist. Seitlich bliebe von einer 400 px breiten
   Zeichnung fast nichts uebrig. Die Regeln tragen denselben Vorspann wie die
   Positionsregeln oben und stehen spaeter - sonst gewaennen jene. */
@media (max-width: 767px) {
  .tpd[data-panel-position]:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel {
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-height: min(var(--tpd-panel-mobile-size, 60%), 80vh);
    border-radius: var(--tpd-card-radius) var(--tpd-card-radius) 0 0;
    transform: translateY(100%);
  }
  .tpd[data-panel-position]:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel.is-open {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel { transition: none; }
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--tpd-border);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-title {
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.2;
}
/*
  Rund, wie es der Nutzer von der bisherigen Darstellung kennt - und rund
  bleibt er nur, wenn jede Eigenschaft hier selbst genannt wird.

  **Zwei Fehler auf einmal, gemeldet am 22. September 2026 aus dem Vollbild.**

  1. *Er war keine Scheibe, sondern eine Ellipse.* `width: 34px` allein
     genuegt nicht: Themes setzen auf `button` grosszuegige Polsterung und
     haeufig `min-width`. Beides addiert sich zur Breite, die Hoehe bleibt -
     und aus dem Kreis wird ein Oval. Derselbe Fehler wie beim Mengenfeld
     (siehe `.tpd__qty`), nur an einem runden Element sofort sichtbar.
  2. *Beim Ueberfahren wurde das Kreuz weiss.* Der Knopf stand auf
     `color: inherit`, und die Hover-Regel setzte nur den Hintergrund. Ein
     Theme mit `button:hover { color: #fff }` - das ist die Regel, nicht die
     Ausnahme - faerbte das Kreuz damit auf hellem Grund unsichtbar.

  Die Lehre ist in beiden Faellen dieselbe: **Wer eine Eigenschaft nicht
  setzt, ueberlaesst sie dem Theme.** Jeder Zustand nennt deshalb seine Farbe
  selbst. Das vorangestellte `.tpd` liefert die noetige Spezifitaet, ohne
  `!important` - die Regel bleibt damit fuer den Haendler ueberschreibbar.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-close {
  flex: none;
  box-sizing: border-box;
  width: 34px; height: 34px;
  min-width: 34px; min-height: 34px;
  max-width: 34px;
  padding: 0;
  margin: 0;
  display: grid; place-items: center;
  appearance: none;
  border: 1px solid var(--tpd-border);
  border-radius: 50%;
  background: #fff;
  box-shadow: none;
  color: var(--tpd-muted);
  cursor: pointer;
  line-height: 1;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-close svg {
  width: 15px; height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
}
/* Hover und Tastaturfokus sehen gleich aus: Wer mit Tab hierher kommt, soll
   dieselbe Rueckmeldung bekommen wie mit der Maus. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-close:hover,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-close:focus-visible {
  background: #f1f1f1;
  border-color: var(--tpd-muted);
  color: var(--tpd-card-text);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-close:focus-visible {
  outline: 2px solid var(--tpd-highlight, var(--tpd-dot-color, #0a3d62));
  outline-offset: 2px;
}

.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-body {
  padding: 12px;
  overflow-y: auto;
  min-height: 0;
}

/* Die Zeile bringt ihr Aussehen aus der Teileliste mit. Hier faellt nur weg,
   was dort dem Scrollcontainer und der Verknuepfung mit der Zeichnung dient. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list {
  max-height: none;
  gap: 10px;
}

/*
  Im Fenster liegt die Zeile wie eine Karte, nicht wie eine Zeile.

  Es ist dasselbe Markup - `tpd-part.liquid` rendert beide, nur mit anderer
  Klasse. In der Liste steht alles nebeneinander, weil dort Platz in der
  Breite ist und viele Zeilen untereinander stehen. Im Fenster ist es
  umgekehrt: gut 340 px breit, eine einzige Position. Nebeneinander gedraengt
  ueberlappte der Mengenwaehler den Preis.

  Deshalb hier dieselbe Aufteilung wie in der Hover-Karte: Bild und Angaben
  nebeneinander, das Formular darunter ueber die ganze Breite. Wer die Karte
  umbaut, muss diese drei Zeilen mitziehen - sie sollen gleich aussehen, und
  genau das war der Anlass.
*/
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__part--row {
  grid-template-columns: auto auto minmax(0, 1fr);
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__part--row .tpd__part-action {
  grid-column: 1 / -1;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__item { cursor: default; }
/* Im Fenster steht ohnehin nur die eine Position - der Auswahlring waere
   Rauschen und wuerde die Zeile anders aussehen lassen als in der Liste. */
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__item.is-active,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__item.is-pinned {
  border-color: var(--tpd-border);
  box-shadow: none;
}
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__item.is-active .tpd__item-no,
.tpd:not(#tp-gewicht):not(#tp-gewicht) .tpd__panel-list .tpd__item.is-pinned .tpd__item-no {
  background: var(--tpd-dot-color);
}


/* Video und Link einer Position bringt seit FREE 1.40 PRO mit
   (`techparts-pro/assets/video-link.css`). */
