/* =====================================================================
   DSF Teamsport-Konfigurator v1.0
   Design-Sprache: DSF (kantig, Schwarz/Rot/Weiß, CTA-Grün)
   Alle Selektoren mit .dsf-ts-* gescoped, kein CSS-Leakage.
   ===================================================================== */
@import url('fonts.css');

:root {
    --dsf-ts-red: #c8102e;
    --dsf-ts-red-dark: #a30d25;
    --dsf-ts-red-deep: #6e0a19;
    --dsf-ts-black: #141416;
    --dsf-ts-red-bright: #e4304b; /* Akzent auf dunklen Flaechen */
    --dsf-ts-green: #66a834;
    --dsf-ts-green-dark: #53882a;
    --dsf-ts-ink: #1f2937;
    --dsf-ts-muted: #5b6574;
    --dsf-ts-line: #d9dde3;
    --dsf-ts-bg-soft: #fafbfc;
    --dsf-ts-danger: #c0392b;
    /* Auswahlfarbe fuer Haken, aktive Chips und Umschalter. BEWUSST nicht
       Rot: Rot ist im Konfigurator die Farbe fuer Aktion (CTA) und Fehler
       (Blink-Rahmen). Wenn "gewaehlt" genauso aussieht wie "Achtung", liest
       sich eine korrekt ausgefuellte Seite wie eine Fehlerliste. Eine Zeile
       hier faerbt alle Auswahlzustaende um. */
    --dsf-ts-select: #26324a;
    --dsf-ts-select-soft: #eef1f6;
    /* Hinweis-Blau fuer Sachinformationen (Nachbestellung beim Hersteller) */
    --dsf-ts-info: #1d6fa5;
    --dsf-ts-info-soft: #eef6fb;
    --dsf-ts-head: 'Bebas Neue', 'Oswald', sans-serif;
    --dsf-ts-sub: 'Oswald', sans-serif;
    --dsf-ts-shadow: 0 4px 12px rgba(17, 24, 39, .05);
    --dsf-ts-shadow-lift: 0 14px 34px rgba(20, 20, 22, .16);
}

/* =====================================================================
   1. PORTAL / LANDINGPAGE
   ===================================================================== */

.dsf-ts-page {
    color: var(--dsf-ts-ink);
    overflow-x: clip;
}

.dsf-ts-page img { max-width: 100%; }

/* ---------- Hero ---------- */
.dsf-ts-hero {
    position: relative;
    background: linear-gradient(118deg, var(--dsf-ts-black) 0%, var(--dsf-ts-red-deep) 55%, var(--dsf-ts-red) 100%);
    color: #fff;
    padding: clamp(3rem, 7vw, 5.5rem) 1.25rem clamp(3.5rem, 8vw, 6rem);
    overflow: hidden;
}

/* dezente diagonale Speed-Lines im Hero */
.dsf-ts-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(115deg, transparent 0 62%, rgba(255, 255, 255, .045) 62% 70%, transparent 70% 78%, rgba(255, 255, 255, .045) 78% 84%, transparent 84%);
    pointer-events: none;
}

.dsf-ts-hero__inner {
    position: relative;
    max-width: 1180px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
    gap: clamp(1.5rem, 4vw, 4rem);
    align-items: center;
}

.dsf-ts-hero__kicker {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    background: var(--dsf-ts-red);
    color: #fff;
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .82rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    padding: .4rem .85rem;
    margin-bottom: 1.1rem;
}

.dsf-ts-hero__title {
    font-family: var(--dsf-ts-head);
    font-size: clamp(2.6rem, 6vw, 4.6rem);
    line-height: .96;
    letter-spacing: .015em;
    margin: 0 0 1rem;
    text-transform: uppercase;
    color: #fff;
}

.dsf-ts-hero__title em {
    font-style: normal;
    color: var(--dsf-ts-red-bright);
}

.dsf-ts-hero__lead {
    font-size: clamp(1rem, 1.6vw, 1.2rem);
    line-height: 1.55;
    color: rgba(255, 255, 255, .82);
    max-width: 34rem;
    margin: 0 0 1.75rem;
}

.dsf-ts-hero__ctas {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    align-items: center;
}

.dsf-ts-hero__meta {
    margin-top: 1.4rem;
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    font-size: .88rem;
    color: rgba(255, 255, 255, .72);
}

.dsf-ts-hero__meta span::before {
    content: "✓";
    color: #fff;
    font-weight: 700;
    margin-right: .4rem;
}

/* Sponsor-Badge im Hero */
.dsf-ts-hero__sponsor {
    display: inline-flex;
    align-items: center;
    gap: .75rem;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .18);
    padding: .6rem .9rem;
    margin-bottom: 1.25rem;
    backdrop-filter: blur(4px);
}

.dsf-ts-hero__sponsor img {
    height: 30px;
    width: auto;
    background: #fff;
    padding: .2rem .45rem;
}

.dsf-ts-hero__sponsor small {
    font-family: var(--dsf-ts-sub);
    font-size: .74rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .75);
}

/* Trikot-Visual rechts im Hero */
.dsf-ts-hero__visual {
    position: relative;
    display: flex;
    justify-content: center;
}

.dsf-ts-hero__visual svg,
.dsf-ts-hero__visual img {
    width: min(340px, 80%);
    filter: drop-shadow(0 24px 40px rgba(0, 0, 0, .35));
}

.dsf-ts-hero__pricetag {
    position: absolute;
    right: 4%;
    top: 6%;
    background: var(--dsf-ts-red);
    color: #fff;
    font-family: var(--dsf-ts-head);
    text-align: center;
    padding: .65rem 1rem .55rem;
    transform: rotate(4deg);
    box-shadow: var(--dsf-ts-shadow-lift);
}

.dsf-ts-hero__pricetag strong {
    display: block;
    font-size: 1.9rem;
    line-height: 1;
}

.dsf-ts-hero__pricetag small {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-size: .68rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    opacity: .9;
}

/* ---------- Buttons ---------- */
/* Doppeltipp-Zoom auch am einzelnen Bedienelement abschalten. touch-action
   wird nicht vererbt, und aeltere WebKit-Versionen sehen nur das getroffene
   Element. Zwei schnelle Tipps auf ein Plus-Feld sind sonst ein Doppeltipp,
   und der Kunde steht im Zoom, ohne zu wissen, wie er wieder herauskommt.
   Zweifinger-Zoom bleibt ueberall erhalten. */
.dsf-ts-btn,
.dsf-ts-gearchip,
.dsf-ts-gearchip__minus,
.dsf-ts-gearchip__plus,
.dsf-ts-swatch,
.dsf-ts-stepper__step,
.dsf-ts-preview__collapse,
.dsf-ts-preview__player button,
.dsf-ts-morehint,
.dsf-ts-jh__reset,
.dsf-ts-jh__close {
    touch-action: manipulation;
}

.dsf-ts-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .55rem;
    border: 0;
    border-radius: 0;
    cursor: pointer;
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    letter-spacing: .05em;
    text-transform: uppercase;
    text-decoration: none !important;
    transition: background-color .15s ease, color .15s ease, transform .12s ease;
    -webkit-tap-highlight-color: transparent;
    line-height: 1.15;
}

.dsf-ts-btn--primary {
    background: var(--dsf-ts-green);
    color: #fff !important;
    padding: .95rem 1.7rem;
    font-size: 1rem;
}

.dsf-ts-btn--primary:hover { background: var(--dsf-ts-green-dark); }

.dsf-ts-btn--ghost {
    background: transparent;
    color: #fff !important;
    border: 1px solid rgba(255, 255, 255, .45);
    padding: .95rem 1.5rem;
    font-size: .95rem;
}

.dsf-ts-btn--ghost:hover { background: rgba(255, 255, 255, .1); }

.dsf-ts-btn--blue {
    background: var(--dsf-ts-green);
    color: #fff !important;
    padding: .7rem 1.2rem;
    font-size: .9rem;
}

.dsf-ts-btn--blue:hover { background: var(--dsf-ts-green-dark); }

.dsf-ts-btn--line {
    background: #fff;
    color: var(--dsf-ts-ink) !important;
    border: 1px solid var(--dsf-ts-line);
    padding: .7rem 1.2rem;
    font-size: .9rem;
}

/* Mauszeiger-Zustaende pluginweit in Dunkelblau statt im Aktions-Rot.
   Rot ist die Signalfarbe der Aktion und gehoert dem, was WICHTIG ist;
   ein Knopf, ueber dem gerade der Zeiger steht, ist nicht wichtig, nur
   angefasst. (Echte Fehler behalten ihr Rot — das ist --dsf-ts-danger und
   bleibt unberuehrt.) */
.dsf-ts-btn--line:hover { border-color: var(--dsf-ts-select); color: var(--dsf-ts-select) !important; }

.dsf-ts-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ---------- Sektionen ---------- */
.dsf-ts-section {
    max-width: 1180px;
    margin: 0 auto;
    padding: clamp(2.5rem, 6vw, 4.5rem) 1.25rem;
}

.dsf-ts-section--soft { background: var(--dsf-ts-bg-soft); }

/* Der Kopf einer Sektion hatte bis v0.99.95 eine Breite von 720px — und
   damit auch die Ueberschrift. "IN DREI SCHRITTEN ZUM FERTIGEN SATZ" brach
   deshalb schon auf dem Desktop um, obwohl daneben ueber 400px frei
   blieben: nicht die Schrift war zu gross, der Kasten war zu schmal.

   Die Begrenzung gehoert an den FLIESSTEXT, nicht an die Ueberschrift.
   Lange Zeilen sind bei Fliesstext schwer zu lesen (deshalb die 720px) —
   eine Ueberschrift aus vier Woertern liest niemand zeilenweise. */
.dsf-ts-section__head {
    margin-bottom: clamp(1.5rem, 3.5vw, 2.75rem);
}

.dsf-ts-section__kicker,
.dsf-ts-section__sub {
    max-width: 720px;
}

.dsf-ts-section__kicker {
    font-family: var(--dsf-ts-sub);
    font-size: .8rem;
    font-weight: 500;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--dsf-ts-red);
    margin: 0 0 .4rem;
}

.dsf-ts-section__title {
    font-family: var(--dsf-ts-head);
    font-size: clamp(1.9rem, 3.6vw, 2.9rem);
    line-height: 1.02;
    text-transform: uppercase;
    margin: 0 0 .6rem;
    color: var(--dsf-ts-ink);
}

.dsf-ts-section__sub {
    color: var(--dsf-ts-muted);
    font-size: 1.02rem;
    line-height: 1.55;
    margin: 0;
}

/* ---------- Baustein-Wahl auf der Landingpage ---------- */
.dsf-ts-paths {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.4rem;
    max-width: 880px;
}

.dsf-ts-path {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: 1.6rem 1.5rem 1.5rem;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}

.dsf-ts-path:hover {
    box-shadow: var(--dsf-ts-shadow-lift);
    transform: translateY(-3px);
    border-color: #b9c6d8;
}

.dsf-ts-path__media {
    height: 120px;
    display: flex;
    align-items: center;
    margin-bottom: 1rem;
}

.dsf-ts-path__media svg { height: 110px; width: auto; }

.dsf-ts-path__media--gear { color: var(--dsf-ts-red); }

.dsf-ts-path__media--gear .dsf-ts-gearicons { gap: .8rem; }
.dsf-ts-path__media--gear .dsf-ts-gearicons svg { height: 62px; width: auto; }

.dsf-ts-path h3 {
    font-family: var(--dsf-ts-head);
    font-size: 1.6rem;
    text-transform: uppercase;
    margin: 0 0 .35rem;
    color: var(--dsf-ts-ink);
}

.dsf-ts-path p {
    color: var(--dsf-ts-muted);
    font-size: .92rem;
    line-height: 1.5;
    margin: 0 0 1.1rem;
    flex: 1;
}

.dsf-ts-path .dsf-ts-btn { align-self: stretch; }

@media (max-width: 575px) {
    .dsf-ts-path { padding: 1.15rem 1rem 1.1rem; }
    .dsf-ts-path__media { height: 84px; margin-bottom: .7rem; }
    .dsf-ts-path__media svg { height: 80px; }
    .dsf-ts-path__media--gear .dsf-ts-gearicons svg { height: 46px; }
}

/* ---------- "So funktioniert's" ---------- */
.dsf-ts-steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    /* Zwei Reihen fuer ALLE Kacheln: Ueberschrift, Text. Die Kacheln
       uebernehmen dieses Raster (subgrid) — dadurch beginnt der Text
       ueberall auf derselben Linie, auch wenn eine Ueberschrift zwei
       Zeilen braucht ("Wunschbeflockung auswaehlen & eintragen").
       Vorher richtete sich jede Kachel nach sich selbst, und der Text
       der mittleren rutschte um eine Zeile nach unten.

       Kennt ein Browser subgrid nicht, greift der Rest weiter: die
       Kacheln stehen dann wie bisher, nur ohne die Flucht. */
    grid-template-rows: auto auto;
    gap: 1px;
    background: var(--dsf-ts-line);
    border: 1px solid var(--dsf-ts-line);
}

.dsf-ts-steps__item {
    background: #fff;
    padding: 1.5rem 1.35rem 1.6rem;
    position: relative;
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    /* Abstand zwischen Ueberschrift und Text — er kommt aus dem Raster,
       nicht aus einem Rand am Text. So bleibt die Flucht erhalten. */
    row-gap: .8rem;
    align-content: start;
}

.dsf-ts-steps__item h3::before {
    content: "✓";
    color: var(--dsf-ts-red);
    font-weight: 700;
    margin-right: .5rem;
}

.dsf-ts-steps__item h3 {
    font-family: var(--dsf-ts-sub);
    font-size: 1.05rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .04em;
    /* Kein unterer Rand mehr: der Abstand kommt aus row-gap des Rasters.
       Ein Rand am Titel wuerde die zweizeilige Kachel wieder verschieben. */
    margin: 0;
    line-height: 1.25;
    color: var(--dsf-ts-ink);
    align-self: start;
}

.dsf-ts-steps__item p {
    font-size: .9rem;
    color: var(--dsf-ts-muted);
    line-height: 1.5;
    margin: 0;
}

/* ---------- Kampagnen-/Set-Karten ---------- */
.dsf-ts-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
    gap: 1.4rem;
}

.dsf-ts-card {
    background: #fff;
    border: 1px solid var(--dsf-ts-line);
    display: flex;
    flex-direction: column;
    transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
    position: relative;
}

.dsf-ts-card:hover {
    box-shadow: var(--dsf-ts-shadow-lift);
    transform: translateY(-3px);
    border-color: #b9c6d8;
}

.dsf-ts-card__flag {
    position: absolute;
    top: .85rem;
    left: 0;
    background: var(--dsf-ts-red);
    color: #fff;
    font-family: var(--dsf-ts-sub);
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: .1em;
    text-transform: uppercase;
    padding: .3rem .7rem;
    z-index: 2;
}

.dsf-ts-card__flag--sponsor { background: var(--dsf-ts-black); }

.dsf-ts-card__media {
    background: var(--dsf-ts-bg-soft);
    border-bottom: 1px solid var(--dsf-ts-line);
    aspect-ratio: 4 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.25rem;
    overflow: hidden;
}

.dsf-ts-card__media svg,
.dsf-ts-card__media img {
    max-height: 100%;
    width: auto;
    max-width: 100%;
    object-fit: contain;
}

.dsf-ts-card__body {
    padding: 1.1rem 1.15rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: .45rem;
    flex: 1;
}

.dsf-ts-card__title {
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: 1.12rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    margin: 0;
    color: var(--dsf-ts-ink);
}

.dsf-ts-card__sub {
    font-size: .88rem;
    color: var(--dsf-ts-muted);
    line-height: 1.45;
    margin: 0;
    flex: 1;
}

.dsf-ts-card__price {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin-top: .35rem;
}

.dsf-ts-card__price strong {
    font-family: var(--dsf-ts-head);
    font-size: 1.7rem;
    color: var(--dsf-ts-ink);
    line-height: 1;
}

.dsf-ts-card__price s {
    color: var(--dsf-ts-muted);
    font-size: .95rem;
}

.dsf-ts-card__price small {
    color: var(--dsf-ts-muted);
    font-size: .78rem;
}

.dsf-ts-card__cta { margin-top: .8rem; }

/* ---------- USP-Band ---------- */
.dsf-ts-uspband {
    background: var(--dsf-ts-black);
    color: #fff;
}

.dsf-ts-uspband__inner {
    max-width: 1180px;
    margin: 0 auto;
    padding: clamp(2rem, 4.5vw, 3.25rem) 1.25rem;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1.75rem;
}

.dsf-ts-uspband__item h3 {
    font-family: var(--dsf-ts-head);
    font-size: 1.45rem;
    text-transform: uppercase;
    margin: 0 0 .3rem;
    color: var(--dsf-ts-red-bright);
}

.dsf-ts-uspband__item p {
    font-size: .88rem;
    line-height: 1.5;
    color: rgba(255, 255, 255, .75);
    margin: 0;
}

/* ---------- FAQ ---------- */
.dsf-ts-faq { border-top: 1px solid var(--dsf-ts-line); }

.dsf-ts-faq__item { border-bottom: 1px solid var(--dsf-ts-line); }

.dsf-ts-faq__q {
    width: 100%;
    background: none;
    border: 0;
    text-align: left;
    padding: 1.05rem .25rem;
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: 1rem;
    color: var(--dsf-ts-ink);
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}

.dsf-ts-faq__q::after {
    content: "+";
    font-size: 1.4rem;
    color: var(--dsf-ts-red);
    transition: transform .18s ease;
    flex-shrink: 0;
}

.dsf-ts-faq__item.is-open .dsf-ts-faq__q::after { transform: rotate(45deg); }

.dsf-ts-faq__a {
    display: none;
    padding: 0 .25rem 1.1rem;
    color: var(--dsf-ts-muted);
    font-size: .93rem;
    line-height: 1.55;
    max-width: 52rem;
}

.dsf-ts-faq__item.is-open .dsf-ts-faq__a { display: block; }

/* ---------- Abschluss-CTA ---------- */
.dsf-ts-final {
    background: linear-gradient(118deg, var(--dsf-ts-red) 0%, var(--dsf-ts-red-deep) 100%);
    color: #fff;
    text-align: center;
    padding: clamp(2.75rem, 6vw, 4.25rem) 1.25rem;
}

.dsf-ts-final h2 {
    font-family: var(--dsf-ts-head);
    font-size: clamp(2rem, 4.5vw, 3.2rem);
    text-transform: uppercase;
    margin: 0 0 .5rem;
    color: #fff;
}

.dsf-ts-final p {
    color: rgba(255, 255, 255, .8);
    margin: 0 auto 1.5rem;
    max-width: 38rem;
}

.dsf-ts-final__ctas {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    justify-content: center;
}

@media (max-width: 575px) {
    .dsf-ts-final__ctas { flex-direction: column; align-items: stretch; }
}

/* =====================================================================
   2. KONFIGURATOR-JOURNEY (Fullscreen-Overlay)
   ===================================================================== */

.dsf-ts-journey {
    position: fixed;
    inset: 0;
    /* iOS: 100vh schliesst die dynamische Browserleiste ein und schiebt die
       Footer-Navigation aus dem Bild — dvh misst den echten sichtbaren Bereich. */
    height: 100vh;
    height: 100dvh;
    /* Ueber ALLEM liegen, was der Shop sonst einblendet: Cookie-Banner,
       Consent-Widgets, Trusted Shops, Chat-Buttons. Die legen sich gern
       selbst auf den hoechstmoeglichen Wert — deshalb geht der
       Konfigurator bis dicht an die Obergrenze, und bei Gleichstand
       entscheidet die DOM-Reihenfolge fuer ihn (er wird beim Oeffnen
       angehaengt, der Banner steht schon beim Seitenaufbau).
       Darueber bleiben nur die eigenen Ebenen: Lightbox, Dialog, Meldung. */
    z-index: 2147483644;
    background: var(--dsf-ts-bg-soft);
    /* Siehe auch die Regel fuer die Bedienelemente weiter unten
       (.dsf-ts-gearchip u. a.) — touch-action wird nicht vererbt, und
       aeltere WebKit-Versionen werten nur das getroffene Element aus.

       Kein Doppeltipp-Zoom. Er zeigte drei Symptome, die wie drei Fehler
       aussahen, aber einer sind: "Vorschau und Kopfzeile lassen sich
       wegschieben", "Zuruecksetzen rechts abgeschnitten" und "das
       Dialogfenster ist nicht zentriert". Zoomt Safari hinein, wird der
       sichtbare Ausschnitt kleiner als der Layout-Viewport — und alles mit
       position:fixed richtet sich weiter nach dem GROSSEN aus. Die Kopfzeile
       schiebt sich also nicht weg, man schaut nur an ihr vorbei.

       Ausgeloest hat ihn das schnelle Tippen auf die Plus-Felder: zwei
       Beruehrungen innerhalb von rund 300 ms sind fuer Safari ein
       Doppeltipp. 'manipulation' schaltet genau diese Geste ab —
       Zweifinger-Zoom bleibt erhalten, den braucht man zum Lesen. */
    touch-action: manipulation;
    /* Die Huelle selbst scrollt nie; das tut nur .dsf-ts-panel__scroll. */
    overflow: hidden;
    display: none;
    flex-direction: column;
    overscroll-behavior: contain;
    /* Das Overlay liegt IM Shop-DOM. Ein zu breites Kind darf die Shopseite
       niemals seitlich verschiebbar machen — deshalb der Riegel auf jeder
       Breite, nicht erst unter 991px. */
    max-width: 100%;
    overflow-x: hidden;
}

.dsf-ts-journey.is-open { display: flex; }

body.dsf-ts-journey-open { overflow: hidden; }

/* ---------- Journey-Header ---------- */
.dsf-ts-jh {
    background: #fff;
    border-bottom: 1px solid var(--dsf-ts-line);
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: .65rem 1rem;
    flex-shrink: 0;
}

.dsf-ts-jh__brand {
    font-family: var(--dsf-ts-head);
    font-size: 1.3rem;
    line-height: 1;
    color: var(--dsf-ts-red);
    white-space: nowrap;
}

.dsf-ts-jh__sponsorlogo {
    height: 26px;
    width: auto;
    flex-shrink: 0;
    background: #fff;
    border: 1px solid var(--dsf-ts-line);
    padding: 2px 6px;
}

.dsf-ts-jh__campaign {
    font-family: var(--dsf-ts-sub);
    font-size: .82rem;
    color: var(--dsf-ts-muted);
    text-transform: uppercase;
    letter-spacing: .07em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dsf-ts-jh__spacer { flex: 1; }

.dsf-ts-jh__total {
    text-align: right;
    line-height: 1.1;
}

.dsf-ts-jh__total strong {
    font-family: var(--dsf-ts-head);
    font-size: 1.55rem;
    color: var(--dsf-ts-ink);
}

/* "Gesamt inkl. MwSt." ist nur ein Label — bewusst sehr klein/dezent */
.dsf-ts-jh__total small {
    display: block;
    font-size: .5rem;
    color: var(--dsf-ts-muted);
    text-transform: uppercase;
    letter-spacing: .05em;
}

.dsf-ts-jh__close {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    width: 40px;
    height: 40px;
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    color: var(--dsf-ts-muted);
    flex-shrink: 0;
    transition: color .15s ease, border-color .15s ease;
}

.dsf-ts-jh__close:hover { color: var(--dsf-ts-danger); border-color: var(--dsf-ts-danger); }

/* ---------- Stepper ---------- */
.dsf-ts-stepper {
    display: flex;
    background: #fff;
    border-bottom: 1px solid var(--dsf-ts-line);
    flex-shrink: 0;
    overflow-x: auto;
    scrollbar-width: none;
}

.dsf-ts-stepper::-webkit-scrollbar { display: none; }

.dsf-ts-stepper__step {
    flex: 1;
    min-width: 110px;
    border: 0;
    background: none;
    padding: .6rem .5rem .55rem;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
    cursor: pointer;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    white-space: nowrap;
}

.dsf-ts-stepper__step::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -1px;
    height: 3px;
    background: transparent;
}

.dsf-ts-stepper__num {
    width: 22px;
    height: 22px;
    border: 1px solid var(--dsf-ts-line);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .72rem;
    font-weight: 700;
    flex-shrink: 0;
}

/* Schrittanzeige nach derselben Logik wie der Rest: der AKTUELLE Schritt
   ist "hier bist du" (Auswahlfarbe), ERLEDIGTE sind ein Erfolg (gruen).
   Rot hatte hier nichts verloren — es ist die Fehlerfarbe, und der Kunde
   sah sie dauerhaft auf dem Schritt, an dem er gerade arbeitet. */
.dsf-ts-stepper__step.is-active { color: var(--dsf-ts-select); }
.dsf-ts-stepper__step.is-active::after { background: var(--dsf-ts-select); }
.dsf-ts-stepper__step.is-active .dsf-ts-stepper__num {
    background: var(--dsf-ts-select);
    border-color: var(--dsf-ts-select);
    color: #fff;
}

.dsf-ts-stepper__step.is-done { color: var(--dsf-ts-green-dark); }
.dsf-ts-stepper__step.is-done .dsf-ts-stepper__num {
    background: var(--dsf-ts-green);
    border-color: var(--dsf-ts-green);
    color: #fff;
}

.dsf-ts-stepper__step:disabled { cursor: not-allowed; opacity: .55; }

/* ---------- Journey-Body: Preview + Panel ---------- */
.dsf-ts-jbody {
    flex: 1;
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    min-height: 0;
}

.dsf-ts-preview {
    background:
        radial-gradient(ellipse at 50% 38%, rgba(200, 16, 46, .07), transparent 62%),
        linear-gradient(180deg, #eef1f5 0%, #e4e8ee 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: relative;
    padding: 1.5rem;
    border-right: 1px solid var(--dsf-ts-line);
    min-height: 0;
}

.dsf-ts-preview__stage {
    width: min(360px, 82%);
    max-height: 100%;
}

.dsf-ts-preview__stage svg {
    width: 100%;
    height: auto;
    filter: drop-shadow(0 18px 28px rgba(20, 20, 22, .22));
}

/* Vorne/Hinten steht direkt UEBER dem Trikotbild.
   Zwei Anlaeufe bis hierher: unten am Spaltenrand lag der Umschalter bei
   hohen Fenstern ausserhalb des sichtbaren Bereichs, danach klebte er
   absolut auf 3.6rem — und stand damit weit ueber dem mittig zentrierten
   Foto in der Luft. Jetzt laeuft er im normalen Fluss der Spalte mit und
   sitzt als erstes Element der zentrierten Gruppe unmittelbar auf dem
   Bild. Mobil bleibt er unter dem Foto (eigene Regel im Media-Query
   weiter unten): dort ist der Daumen unten. */
/* Am Desktop loest sich die Leiste auf: ihre beiden Kinder werden direkt
   Kinder der Vorschau, und alle bisherigen Regeln gelten unveraendert
   weiter (Umschalter ueber dem Foto per order:-1, Vorschau-Knopf gar nicht
   sichtbar). Erst mobil wird sie zur echten Leiste. */
.dsf-ts-preview__bar { display: contents; }


.dsf-ts-preview__toggle {
    order: -1;
    /* Derselbe Abstand, den das Trikot zu Hose und Stutzen hat
       (.dsf-ts-photostage gap: .7rem) — dann sitzt der Umschalter im
       gleichen Raster wie alles andere auf der Buehne. Vorher waren es
       .55rem, und er klebte sichtbar naeher am Foto als die Teile
       untereinander. */
    margin-bottom: .7rem;
    display: flex;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    z-index: 2;
}

.dsf-ts-preview__toggle button {
    border: 0;
    background: none;
    padding: .5rem 1.1rem;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
    cursor: pointer;
}

/* Vorne/Hinten ist eine ANSICHT, keine Aktion — gleiche Auswahlfarbe wie
   alle anderen Umschalter. */
.dsf-ts-preview__toggle button.is-active {
    background: var(--dsf-ts-select);
    color: #fff;
}

/* TW-Ausstattungszeile unter einer Torwart-Kaderzeile */
.dsf-ts-squad__twrow {
    display: flex;
    align-items: center;
    gap: .9rem;
    flex-wrap: wrap;
    margin: -.2rem 0 .45rem;
    padding: .45rem .7rem .45rem 2.4rem;
    background: var(--dsf-ts-info-soft);
    border-left: 3px solid var(--dsf-ts-info);
    border-radius: 0;
    font-size: .82rem;
}

.dsf-ts-squad__twlabel {
    font-family: var(--dsf-ts-sub);
    font-size: .72rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-squad__twrow label {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: 0;
    font-weight: 600;
}

.dsf-ts-squad__twrow select {
    padding: .3rem .5rem;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
    background: #fff;
    font-size: .82rem;
}

.dsf-ts-pcard .dsf-ts-squad__twrow {
    margin: .5rem 0 0;
    padding-left: .7rem;
    border-radius: 0;
}

/* Groessen & Mengen je Set-Teil im Farben-Schritt */
.dsf-ts-partsizes__head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    margin: .7rem 0 .35rem;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-partsizes__status b { font-weight: 700; }
.dsf-ts-partsizes__status .is-ok { color: var(--dsf-ts-green, #4a8f3c); }
.dsf-ts-partsizes__status .is-off { color: var(--dsf-ts-red); }

.dsf-ts-partsizes { margin-bottom: .3rem; }

.dsf-ts-partsizes__hint {
    margin: .25rem 0 0;
    font-size: .78rem;
    color: var(--dsf-ts-muted);
}

/* Paket-Kontingent: steht direkt unter der Zaehlzeile ("0 / 14"), die es
   erklaert. Als ruhige Notiz mit Marke — vorher war es ein loser Satz
   unterhalb der Chips, der wie eine Warnung wirkte und weit weg von der
   Zahl stand, um die es geht. */
.dsf-ts-partsizes__more {
    /* zweite Zeile der Kopfzeile — volle Breite unter Label und Zaehler */
    flex: 0 0 100%;
    display: flex;
    align-items: baseline;
    text-transform: none;
    letter-spacing: 0;
    gap: .45rem;
    margin: 0 0 .5rem;
    padding: .4rem .55rem;
    font-size: .78rem;
    line-height: 1.35;
    color: var(--dsf-ts-info);
    background: var(--dsf-ts-info-soft);
    border-left: 3px solid var(--dsf-ts-info);
}

.dsf-ts-partsizes__more-tag {
    flex: 0 0 auto;
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    opacity: .75;
}

.dsf-ts-partsizes__more-text b { font-weight: 700; }

.dsf-ts-partsizes__tools {
    display: flex;
    align-items: center;
    gap: .7rem;
    margin-top: .35rem;
    flex-wrap: wrap;
}

.dsf-ts-partsizes__tools .dsf-ts-btn {
    padding: .4rem .8rem;
    font-size: .78rem;
}

/* Groessen-Empfehlung ("Rest auf …", "Größen wie Trikot übernehmen"):
   steht direkt unter der Groessenwahl, weil sie die naechste Handlung ist —
   der Nachbestell-Hinweis ist reine Information und rutscht darunter.

   Nur die Knoepfe sind leicht gruen, kein umgebender Kasten und keine
   erklaerende Zeile: die offene Menge steht schon im Zaehler ueber den
   Chips, und mobil kostet jede Zusatzzeile Platz, den die Groessen-Chips
   brauchen. Gruen statt rot, weil rot in diesem Schritt "fehlt noch" und
   "gesperrt" bedeutet — hier geht es um den Weg zum Haken.

   Beide Auffuell-Wege sehen gleich aus. Vorher trug nur die eigene
   Groessenskala eine Auszeichnung, die gespiegelte nicht. */
.dsf-ts-btn--fill {
    border-color: #cbe0ba;
    background: #f4f9ef;
    color: var(--dsf-ts-green-dark);
}

.dsf-ts-btn--fill:hover,
.dsf-ts-btn--fill:focus-visible {
    border-color: var(--dsf-ts-green-dark);
    background: var(--dsf-ts-green-dark);
    color: #fff;
}

/* Mobil duerfen die Knoepfe enger stehen — bei fuenf Groessen sind es
   sonst schnell drei Zeilen ueber dem Nachbestell-Hinweis. */
@media (max-width: 575px) {
    .dsf-ts-partsizes__tools {
        gap: .35rem;
        margin-top: .3rem;
    }

    .dsf-ts-partsizes__tools .dsf-ts-btn {
        padding: .32rem .55rem;
        font-size: .72rem;
    }
}

/* Kein Produktfoto hinterlegt */
.dsf-ts-photostage__empty {
    padding: 3rem 2rem;
    border: 1px dashed var(--dsf-ts-line);
    border-radius: 0;
    background: #fff;
    color: var(--dsf-ts-muted);
    font-size: .9rem;
    text-align: center;
    max-width: 340px;
}

/* Veredelung: Gruppen-Ueberschriften Vorne/Hinten */
.dsf-ts-finsection {
    margin: 1.3rem 0 .5rem;
    font-family: var(--dsf-ts-sub);
    font-size: .82rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
    border-bottom: 1px solid var(--dsf-ts-line);
    padding-bottom: .3rem;
}

/* Pflichtfeld Vereinsname leer. Die :focus-Varianten muessen mit dabei sein:
   die Fehlerpruefung setzt den Fokus ins Feld, und die Fokus-Regel steht
   spaeter im Stylesheet — sie hat die rote Markierung sonst sofort wieder
   ueberschrieben, das Feld sah aus wie jedes andere aktive Feld. */
.dsf-ts-teamtext input.has-error,
.dsf-ts-teamtext textarea.has-error,
.dsf-ts-teamtext input.has-error:focus,
.dsf-ts-teamtext textarea.has-error:focus {
    border-color: var(--dsf-ts-red);
    box-shadow: 0 0 0 3px rgba(200, 16, 46, .18);
    background: #fdf1ef;
}

/* hidden-Attribut muss gegen display:flex gewinnen */
.dsf-ts-preview__toggle[hidden],
.dsf-ts-preview__mode[hidden] { display: none; }

/* Foto/Zeichnung-Umschalter (nur sichtbar, wenn ein Artikelfoto existiert) */
.dsf-ts-preview__mode {
    position: absolute;
    bottom: 1.1rem;
    left: 1.1rem;
    display: flex;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    z-index: 2;
}

.dsf-ts-preview__mode button {
    border: 0;
    background: none;
    padding: .5rem .9rem;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
    cursor: pointer;
}

.dsf-ts-preview__mode button.is-active {
    background: var(--dsf-ts-dark, #141416);
    color: #fff;
}

/* Echtes Artikelfoto in der Vorschau */
.dsf-ts-photostage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .7rem;
    width: 100%;
}

/* Rahmen um das Foto: Anker fuer das Veredelungs-Overlay.
   container-type braucht eine explizite Breite, sonst kollabiert
   der inline-block auf 0 (Size-Containment). */
.dsf-ts-photostage__frame {
    position: relative;
    display: block;
    width: min(100%, 440px);
    container-type: inline-size;
}

/* Nur das Produktfoto selbst — NICHT die Veredelungs-Overlays (.dsf-ts-photofin):
   width:100% + weisser Kasten wuerden sonst z. B. das Wappen-Overlay
   bildschirmfuellend machen (hoehere Spezifitaet als die --logo-Regel) */
.dsf-ts-photostage img:not(.dsf-ts-photofin) {
    width: 100%;
    height: auto;
    max-height: 56vh;
    object-fit: contain;
    background: #fff;
    border-radius: 0;
    box-shadow: 0 18px 28px rgba(20, 20, 22, .15);
    display: block;
}

/* Beflockungs-Schrift: Anton (OFL), selbst gehostet — kein Google-CDN */
@font-face {
    font-family: 'Anton';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('anton-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Anton';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('anton-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Veredelung beispielhaft auf dem Originalfoto (Positionen wie ueblich).
   Bewusst OHNE Schatten — die Vorschau soll den Druck zeigen, wie er
   gedruckt wird (flach, eine Farbe). */
.dsf-ts-photofin {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    color: #fff;
    font-family: 'Anton', var(--dsf-ts-head);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: .06em;
    line-height: 1;
    white-space: nowrap;
    pointer-events: none;
    /* inline-block, damit mehrzeilige Schriftzuege auf ihre laengste
       Zeile schrumpfen statt die Frame-Breite einzunehmen */
    display: inline-block;
}

/* Mehrzeiliger Schriftzug: Zeilen untereinander, zentriert. Der
   Container ist inline-block und schrumpft damit auf die laengste Zeile —
   genau die Breite, die fitZoneText messen muss. */
.dsf-ts-photofin__line {
    display: block;
    text-align: center;
    line-height: 1.28;
}

.dsf-ts-photofin--backtop {
    top: 16%;
    font-size: clamp(.68rem, 4.2cqw, 1.15rem);
    letter-spacing: .1em;
}

.dsf-ts-photofin--number {
    top: 26%;
    font-size: clamp(2.4rem, 24cqw, 6.5rem);
}

.dsf-ts-photofin--backbottom {
    top: 58%;
    font-size: clamp(.68rem, 4.2cqw, 1.15rem);
    letter-spacing: .1em;
}

.dsf-ts-photofin--frontnumber {
    left: 30%;
    top: 24%;
    transform: none;
    font-size: clamp(1rem, 8cqw, 2rem);
}

/* Wappen auf der Brust-Herzseite (aus Betrachtersicht rechts der Mitte) */
.dsf-ts-photofin--logo {
    left: 56%;
    top: 22%;
    transform: none;
    width: clamp(28px, 13cqw, 68px);
    height: auto;
    object-fit: contain;
    background: none;
    border-radius: 0;
    box-shadow: none;
    filter: none;
}

/* Sponsorlogo mittig auf der Brust (Fallback-Position ohne Claude-Zone) */
.dsf-ts-photofin--sponsor {
    top: 40%;
    transform: translateX(-50%);
    width: clamp(46px, 30cqw, 150px);
    height: auto;
    object-fit: contain;
    background: none;
    border-radius: 0;
    box-shadow: none;
    filter: none;
}

/* Teil-Kacheln (Hose, Stutzen, TW-Teile): exakt so breit wie das
   Hauptfoto — links/rechts buendig, die Kacheln teilen sich die Breite */
.dsf-ts-photoparts {
    display: flex;
    gap: .8rem;
    justify-content: center;
    width: min(100%, 440px);
}

.dsf-ts-photoparts figure {
    margin: 0;
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
}

/* Eine einzelne Kachel (z. B. nur die lange TW-Hose) bekommt GENAU die
   Breite, die sie auch als eine von zweien haette.

   Vorher standen hier 55 %, waehrend zwei Kacheln sich je rund 48,5 %
   teilen. Die Kachel ist quadratisch — mehr Breite heisst also auch mehr
   Hoehe, die Reihe wuchs um rund 28 px, und weil die Vorschau eine
   senkrecht zentrierte Spalte ist, schob sich alles darueber um die Haelfte
   davon nach oben. Das war das Springen des Vorne/Hinten-Umschalters beim
   Wechsel auf den Torwart.

   calc(50% - .4rem) = halbe Reihe minus halber Spaltenabstand — dieselbe
   Rechnung, die flex bei zwei Kacheln anstellt. */
.dsf-ts-photoparts figure:only-child { flex: 0 0 calc(50% - .4rem); }

.dsf-ts-photoparts img {
    width: 100%;
    aspect-ratio: 1 / 1;
    height: auto;
    object-fit: contain;
    background: #fff;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
}

.dsf-ts-photoparts figcaption {
    margin-top: .25rem;
    font-size: .74rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-photostage small {
    color: var(--dsf-ts-muted);
    font-size: .75rem;
    text-align: center;
    max-width: 420px;
    line-height: 1.45;
}

/* Echtes Artikelbild in der Ausstattungs-Kachel */
.dsf-ts-gear__icon img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #fff;
    border-radius: 0;
}

.dsf-ts-preview__hint {
    position: absolute;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    /* Text und (i)-Knopf in EINER Flucht: Flexbox statt Baseline-Gefrickel */
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    /* Dunkelblau statt Schwarz: die Leiste sagt "das hier ist eine
       Darstellung, kein Druckbild" — also ein Hinweis, und Hinweise tragen
       im Konfigurator das Auswahl-Blau. Schwarz wirkte wie eine
       System-Einblendung des Browsers. */
    background: var(--dsf-ts-select);
    color: #fff;
    font-size: .76rem;
    padding: .35rem .8rem;
    letter-spacing: .04em;
    white-space: nowrap;
    line-height: 1;
}

/* Einklapp-Knopf: nur mobil sichtbar (Media-Query unten) */
/* Den Vorschau-Knopf gibt es nur mobil (Desktop: display:none). Er war
   weiss auf weissem Kasten und damit kaum als Bedienelement zu erkennen.

   Jetzt dunkelblau mit weisser Schrift. Zwei Gruende:
   - Lesbarkeit: 12,7:1 statt 2,91:1 bei Weiss auf dem Aktions-Gruen.
   - Rangordnung: das Gruen gehoert dem Weiter-Knopf, der Hauptaktion des
     Schritts. Die Vorschau auf- und zuzuklappen ist eine Bedienung, keine
     Fortsetzung — dunkelblau ordnet sie zum "mehr"-Chip und den anderen
     abgesetzten Elementen. */
/* Der Wisch-Anteaser gehoert allein in die mobile Doppelansicht: am
   Schreibtisch gibt es die Pfeile weiterhin, und dort wischt niemand. */
.dsf-ts-preview__swipe { display: none; }

.dsf-ts-preview__collapse {
    display: none;
    position: absolute;
    top: .5rem;
    right: .6rem;
    border: 1px solid var(--dsf-ts-select);
    background: var(--dsf-ts-select);
    color: #fff;
    font-family: var(--dsf-ts-sub);
    font-weight: 600;
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    padding: .45rem .7rem;
    cursor: pointer;
    z-index: 2;
}

/* ---------- Anteaser "es geht noch weiter" (nur mobil) ----------
   Ein Trikotsatz besteht aus mehreren Teilen; mobil passt immer nur eines
   auf den Bildschirm. Unter Trikot-Farbe und -Groessen kommen Hose,
   Stutzen und die Torwart-Ausstattung — ohne Hinweis sieht der Bildschirm
   nach "fertig" aus, und der Kunde tippt auf Weiter.

   Der Pfeil sitzt rechts am Rand, ueber dem Inhalt, aber UNTER der
   Navileiste. Das JS blendet ihn nur ein, wenn wirklich noch etwas
   darunter liegt. */
.dsf-ts-morehint { display: none; }

@media (max-width: 767px) {
    .dsf-ts-morehint {
        /* Text oben, Pfeil DARUNTER — nebeneinander wurde die Pille sonst
           unnoetig breit und schob sich weit ins Bild. Gestapelt ist sie nur
           so breit wie die Beschriftung. */
        display: flex;
        flex-direction: column;
        align-items: center;
        /* Straff: der Pfeil sitzt direkt an der Schrift, nicht darunter
           abgesetzt. Der Abstand kam vorher aus der Zeilenhoehe des
           Pfeilzeichens, nicht aus dem gap — deshalb steht line-height
           weiter unten auf .8. */
        gap: 0;
        position: absolute;
        right: .5rem;
        /* Startwert, bis updateMoreHint() die Navileiste nachgemessen hat.
           Bewusst hoch angesetzt: lieber einmal zu weit oben als auf dem
           Weiter-Knopf. */
        bottom: calc(9.5rem + env(safe-area-inset-bottom, 0px));
        z-index: 4;
        width: auto;
        max-width: 60vw;
        /* Straff, aber noch treffbar: Text und Pfeil ergeben zusammen rund
           30 px, das waere als Ziel zu klein. 36 px kosten hier zwei Pixel
           Optik und machen den Unterschied zwischen "getippt" und
           "danebengetippt". */
        min-height: 36px;
        justify-content: center;
        padding: .2rem .5rem;
        /* Abgesetzt wie die Mengen- und Hinweiskaesten: weiss mit
           dunkelblauem Rahmen, kantig statt rund — dasselbe Muster, das im
           Konfigurator ueberall "hier steht eine Information" bedeutet. */
        border: 1.5px solid var(--dsf-ts-select);
        border-radius: 0;
        background: #fff;
        box-shadow: 0 4px 12px rgba(20, 20, 22, .16);
        color: var(--dsf-ts-select);
        font-family: var(--dsf-ts-sub);
        cursor: pointer;
        animation: dsf-ts-morehint 2.4s ease-in-out infinite;
    }
    .dsf-ts-morehint[hidden] { display: none; }
    /* Im DOM steht der Pfeil zuerst (er traegt die Bedeutung, wenn die
       Beschriftung mal fehlt) — angezeigt wird er unter dem Text. Bei
       "nach oben" dreht sich die Reihenfolge: der Pfeil gehoert dann ueber
       den Text, sonst zeigt er vom Ziel weg. */
    .dsf-ts-morehint__pfeil {
        order: 2;
        font-size: .95rem;
        /* Der sichtbare Abstand kam aus der Zeilenhoehe dieses Zeichens,
           nicht aus dem gap — hier wird er zusammengezogen. */
        line-height: .8;
    }
    /* Gleiche Spalte, nur die Reihenfolge kippt: order 0 stellt den Pfeil
       vor den Text (bei gleichem order entscheidet die DOM-Reihenfolge, und
       dort steht er zuerst). column-reverse waere hier falsch — es dreht
       ALLE Kinder und liess den Pfeil wieder unten landen. */
    .dsf-ts-morehint.is-hoch .dsf-ts-morehint__pfeil { order: 0; }
    .dsf-ts-morehint__text {
        font-size: .66rem;
        font-weight: 700;
        line-height: 1.1;
        letter-spacing: .04em;
        text-transform: uppercase;
        color: var(--dsf-ts-select);
        /* Ein ungewoehnlich langer Teilname darf die Pille nicht ueber den
           halben Bildschirm ziehen. */
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        min-width: 0;
    }

    @keyframes dsf-ts-morehint {
        0%, 70%, 100% { transform: translateY(0); }
        80%           { transform: translateY(4px); }
        90%           { transform: translateY(0); }
    }

    /* Zeigt er nach oben, huepft er auch nach oben. */
    .dsf-ts-morehint.is-hoch { animation-name: dsf-ts-morehint-hoch; }

    @keyframes dsf-ts-morehint-hoch {
        0%, 70%, 100% { transform: translateY(0); }
        80%           { transform: translateY(-4px); }
        90%           { transform: translateY(0); }
    }

    @media (prefers-reduced-motion: reduce) {
        .dsf-ts-morehint { animation: none; }
    }
}

/* ---------- Step-Panel ---------- */
.dsf-ts-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: #fff;
    /* Bezugsrahmen fuer den Anteaser-Pfeil (.dsf-ts-morehint) */
    position: relative;
}

.dsf-ts-panel__scroll {
    flex: 1;
    overflow-y: auto;
    padding: clamp(1.1rem, 2.5vw, 2rem);
    min-height: 0;
}

/* Springt der Anteaser auf einen Haltepunkt, soll dessen Ueberschrift nicht
   an der Oberkante kleben — direkt unter der Vorschau sah sie aus, als waere
   sie halb abgeschnitten. scroll-margin-top gibt ihr die Luft, ohne am
   Layout etwas zu aendern.

   Angesprungen wird die ganze Gruppe, nicht nur ihre Ueberschrift — deshalb
   braucht .dsf-ts-colorgroup den Wert selbst. */
.dsf-ts-panel__scroll .dsf-ts-colorgroup,
.dsf-ts-panel__scroll .dsf-ts-colorgroup > h4,
.dsf-ts-panel__scroll .dsf-ts-partsizes__head,
.dsf-ts-panel__scroll .dsf-ts-twpart,
.dsf-ts-panel__scroll .dsf-ts-twgear__title,
.dsf-ts-panel__scroll .dsf-ts-opt {
    scroll-margin-top: 1.25rem;
}

.dsf-ts-panel__title {
    font-family: var(--dsf-ts-head);
    font-size: clamp(1.5rem, 2.6vw, 2.1rem);
    text-transform: uppercase;
    margin: 0 0 .3rem;
    color: var(--dsf-ts-ink);
}

.dsf-ts-panel__sub {
    color: var(--dsf-ts-muted);
    font-size: .92rem;
    margin: 0 0 1.4rem;
    line-height: 1.5;
}

/* Hinweis, wenn ein Teil keine bestellbare Groesse hat — frueher blieb die
   Stelle einfach leer und wirkte wie ein Fehler. */
.dsf-ts-note {
    color: var(--dsf-ts-muted);
    font-size: .86rem;
    line-height: 1.5;
    margin: .5rem 0 0;
    padding: .5rem .7rem;
    background: rgba(128, 128, 128, .1);
    border-left: 3px solid var(--dsf-ts-muted);
}

/* ---------- Footer-Navigation der Journey ---------- */
.dsf-ts-jnav {
    border-top: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: .8rem clamp(1.1rem, 2.5vw, 2rem);
    /* iPhone-Notch/Home-Indicator nicht ueberdecken */
    padding-bottom: calc(.8rem + env(safe-area-inset-bottom, 0px));
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-shrink: 0;
}

.dsf-ts-jnav__info {
    font-size: .82rem;
    color: var(--dsf-ts-muted);
    line-height: 1.35;
}

.dsf-ts-jnav__info strong { color: var(--dsf-ts-ink); }

/* Weiter, solange im Schritt noch etwas fehlt: sichtbar zurueckgenommen,
   aber ANKLICKBAR. Ein echtes disabled waere hier falsch — der Klick ist
   ja die Hilfe: er nennt die Luecke und springt hin. Ein toter Knopf
   liesse den Kunden ratlos zurueck. */
.dsf-ts-btn--primary.is-unfilled {
    background: #c9ced6;
    border-color: #c9ced6;
    color: #f4f6f8;
}

.dsf-ts-btn--primary.is-unfilled:hover,
.dsf-ts-btn--primary.is-unfilled:focus-visible {
    background: #b9bfc9;
    border-color: #b9bfc9;
    color: #fff;
}

/* Zwei Fassungen derselben Zeile: am Schreibtisch die ausfuehrliche mit
   Paketpreis und Sternchen-Hinweis (dort ist Platz und sie hat sich
   bewaehrt), mobil eine einzeilige Kurzfassung. Umgeschaltet wird per
   Media-Query statt per Fensterbreite im JS — dann stimmt es auch beim
   Drehen des Geraets sofort. */
.dsf-ts-jnav__kurz { display: none; }

/* ---------- Auswahl-Kacheln (Sets, Farben) ---------- */
.dsf-ts-choice-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: .9rem;
}

.dsf-ts-choice {
    border: 2px solid var(--dsf-ts-line);
    background: #fff;
    cursor: pointer;
    padding: 0;
    text-align: left;
    display: flex;
    flex-direction: column;
    transition: border-color .15s ease, box-shadow .15s ease;
    position: relative;
    font: inherit;
    color: inherit;
}

.dsf-ts-choice:hover { border-color: #b9c6d8; box-shadow: var(--dsf-ts-shadow); }

.dsf-ts-choice.is-selected { border-color: var(--dsf-ts-select); }

.dsf-ts-choice.is-selected::after {
    content: "✓";
    position: absolute;
    top: -2px;
    right: -2px;
    width: 26px;
    height: 26px;
    background: var(--dsf-ts-select);
    color: #fff;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .9rem;
}

.dsf-ts-choice__media {
    aspect-ratio: 1 / 1;
    background: var(--dsf-ts-bg-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .9rem;
    border-bottom: 1px solid var(--dsf-ts-line);
}

.dsf-ts-choice__media svg, .dsf-ts-choice__media img { max-width: 100%; max-height: 100%; }

/* Sportart-Kacheln: Piktogramm statt Kit-Vorschau */
.dsf-ts-choice__media--sport { color: var(--dsf-ts-red); }
.dsf-ts-choice__media--sport .dsf-ts-sporticon { width: 62%; height: auto; }

.dsf-ts-choice__body { padding: .7rem .8rem .8rem; }

.dsf-ts-choice__name {
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .95rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    display: block;
    color: var(--dsf-ts-ink);
}

.dsf-ts-choice__meta {
    font-size: .8rem;
    color: var(--dsf-ts-muted);
    display: block;
    margin-top: .15rem;
}

.dsf-ts-choice__price {
    font-family: var(--dsf-ts-head);
    font-size: 1.25rem;
    color: var(--dsf-ts-ink);
    display: block;
    margin-top: .3rem;
}

.dsf-ts-choice__price small { font-family: var(--dsf-ts-sub); font-size: .68rem; color: var(--dsf-ts-muted); }

/* ---------- Farb-Swatches ---------- */
.dsf-ts-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: .7rem;
}

.dsf-ts-swatch {
    width: 54px;
    height: 54px;
    border: 2px solid var(--dsf-ts-line);
    cursor: pointer;
    position: relative;
    padding: 0;
    background: none;
}

.dsf-ts-swatch__fill {
    position: absolute;
    inset: 4px;
}

.dsf-ts-swatch.is-selected { border-color: var(--dsf-ts-select); }

.dsf-ts-swatch.is-selected::after {
    content: "✓";
    position: absolute;
    top: -8px;
    right: -8px;
    width: 20px;
    height: 20px;
    background: var(--dsf-ts-select);
    color: #fff;
    font-size: .72rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1;
}

.dsf-ts-swatch[data-light="1"] .dsf-ts-swatch__fill { border: 1px solid var(--dsf-ts-line); }

.dsf-ts-colorgroup { margin-bottom: 1.5rem; }

/* ---------- Torwart-Ausstattung (Farben-Schritt) ---------- */
.dsf-ts-twgear {
    margin-top: 1.75rem;
    border: 1px solid var(--dsf-ts-line);
    /* Der Streifen markiert eine ROLLE (Torwart), keinen Fehler — deshalb
       die Auswahlfarbe. Rot bleibt Fehlern vorbehalten. */
    border-left: 3px solid var(--dsf-ts-select);
    background: var(--dsf-ts-bg-soft);
    padding: 1rem 1.05rem 1.1rem;
}

.dsf-ts-twgear__title {
    font-family: var(--dsf-ts-head);
    font-size: 1.3rem;
    text-transform: uppercase;
    color: var(--dsf-ts-ink);
    margin: 0 0 .25rem;
}

.dsf-ts-twgear__pants {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    margin: .35rem 0 1.1rem;
}

.dsf-ts-twgear__opt {
    border: 2px solid var(--dsf-ts-line);
    background: #fff;
    padding: .65rem 1.1rem;
    font-family: var(--dsf-ts-sub);
    font-size: .88rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--dsf-ts-ink);
    cursor: pointer;
    min-height: 48px;
}

.dsf-ts-twgear__opt.is-active {
    border-color: var(--dsf-ts-select);
    background: var(--dsf-ts-select-soft);
    font-weight: 700;
}

.dsf-ts-twgear__hint {
    font-size: .78rem;
    color: var(--dsf-ts-muted);
    margin: .5rem 0 0;
}

/* Gesperrte Farbe (Konflikt mit Spielerhose/-stutzen) */
.dsf-ts-swatch.is-conflict {
    opacity: .4;
    cursor: not-allowed;
    position: relative;
}

.dsf-ts-swatch.is-conflict::before {
    content: "";
    position: absolute;
    inset: 4px;
    background: linear-gradient(135deg, transparent 45%, var(--dsf-ts-danger) 45% 55%, transparent 55%);
    z-index: 1;
}

/* Hinweis, wenn die Abhebe-Regel die komplette Palette sperrt */
.dsf-ts-twgear__warn {
    margin: .5rem 0 0;
    padding: .5rem .7rem;
    border-left: 3px solid var(--dsf-ts-danger);
    background: #fdf3f1;
    color: #7a2c20;
    font-size: .78rem;
    line-height: 1.45;
}

.dsf-ts-twgear__warn strong { font-weight: 700; }

.dsf-ts-colorgroup h4 {
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .88rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--dsf-ts-ink);
    margin: 0 0 .6rem;
}

/* ---------- Kader-Tabelle ---------- */
.dsf-ts-squad { border: 1px solid var(--dsf-ts-line); }

/* Spaltenliste kommt als CSS-Variable vom JS (haengt von den aktiven
   Veredelungen ab); mobil greift die kompakte Variante --dsf-squad-cols-m */
.dsf-ts-squad__head, .dsf-ts-squad__row {
    display: grid;
    grid-template-columns: var(--dsf-squad-cols, 2.2rem minmax(90px, .9fr) minmax(130px, 1.4fr) minmax(70px, .7fr) 2.6rem);
    gap: .5rem;
    align-items: center;
}

.dsf-ts-squad__head {
    background: var(--dsf-ts-bg-soft);
    border-bottom: 1px solid var(--dsf-ts-line);
    padding: .55rem .75rem;
    font-family: var(--dsf-ts-sub);
    font-size: .74rem;
    font-weight: 500;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-squad__row {
    padding: .45rem .75rem;
    border-bottom: 1px solid #eef0f3;
}

.dsf-ts-squad__row:last-child { border-bottom: 0; }

.dsf-ts-squad__row.has-error { background: #fdf1ef; }

.dsf-ts-squad__idx {
    font-family: var(--dsf-ts-head);
    color: var(--dsf-ts-muted);
    font-size: 1.05rem;
    text-align: center;
}

.dsf-ts-squad input[data-field="name"] { font-size: .88rem; letter-spacing: .01em; }

.dsf-ts-squad input, .dsf-ts-squad select {
    width: 100%;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
    padding: .45rem .55rem;
    font-size: .92rem;
    background: #fff;
    color: var(--dsf-ts-ink);
}

.dsf-ts-squad input:focus, .dsf-ts-squad select:focus {
    outline: none;
    border-color: var(--dsf-ts-select);
    box-shadow: 0 0 0 2px rgba(38, 50, 74, .16);
}

.dsf-ts-squad input.is-invalid { border-color: var(--dsf-ts-danger); }

.dsf-ts-squad__del {
    border: 0;
    background: none;
    color: var(--dsf-ts-muted);
    cursor: pointer;
    font-size: 1.05rem;
    padding: .3rem;
    line-height: 1;
}

.dsf-ts-squad__del:hover { color: var(--dsf-ts-danger); }

.dsf-ts-squad-tools {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    margin-top: .8rem;
    align-items: center;
}

.dsf-ts-squad-count {
    margin-left: auto;
    font-size: .85rem;
    color: var(--dsf-ts-muted);
}

.dsf-ts-squad-count strong { color: var(--dsf-ts-ink); }

/* ---------- Kader: Kopf mit Modus-Umschalter (Tabelle/Karten) ---------- */
.dsf-ts-squad-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.dsf-ts-squadmode {
    display: flex;
    border: 1px solid var(--dsf-ts-line);
    flex-shrink: 0;
}

.dsf-ts-squadmode__btn {
    border: 0;
    background: #fff;
    padding: .45rem .9rem;
    font-family: var(--dsf-ts-sub);
    font-size: .76rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
    cursor: pointer;
}

.dsf-ts-squadmode__btn.is-active {
    background: var(--dsf-ts-select);
    color: #fff;
}

/* Kader-Bloecke: Torhueter stehen getrennt ueber den Feldspielern —
   anderes Trikot, oft feste Nummer. In einer durchlaufenden Liste gingen
   sie unter. */
.dsf-ts-squad__group {
    /* Gleiche Innenkante wie Kopfzeile und Zeilen (.75rem) — sonst klebt
       die Ueberschrift am Tabellenrand. */
    padding: 1.1rem .75rem .45rem;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--dsf-ts-select);
}
.dsf-ts-squad__group:first-child { padding-top: .8rem; }

.dsf-ts-squad__row.is-keeper { background: var(--dsf-ts-select-soft); }

/* Torwart-Markierungen */
.dsf-ts-squad__tw {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-size: .58rem;
    letter-spacing: .06em;
    color: var(--dsf-ts-select);
    line-height: 1;
}

.dsf-ts-squad__keeper {
    width: 20px;
    height: 20px;
    accent-color: var(--dsf-ts-select);
    justify-self: center;
    cursor: pointer;
}

/* "TW" markiert eine Rolle im Kader — Auswahlfarbe statt Signalrot. */
.dsf-ts-sum__twtag {
    display: inline-block;
    background: var(--dsf-ts-select);
    color: #fff;
    font-family: var(--dsf-ts-sub);
    font-size: .62rem;
    letter-spacing: .06em;
    padding: .1rem .35rem;
    vertical-align: middle;
}

/* ---------- Kader: Karten-Modus (ein Spieler pro Karte) ---------- */
.dsf-ts-pcards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: .8rem;
}

.dsf-ts-pcard {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
}

.dsf-ts-pcard.is-keeper { border-color: var(--dsf-ts-select); }

.dsf-ts-pcard__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: .55rem .8rem;
    background: var(--dsf-ts-bg-soft);
    border-bottom: 1px solid var(--dsf-ts-line);
}

.dsf-ts-pcard.is-keeper .dsf-ts-pcard__head {
    background: var(--dsf-ts-select-soft);
}

.dsf-ts-pcard__head strong {
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .88rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--dsf-ts-ink);
}

.dsf-ts-pcard__del {
    border: 0;
    background: none;
    color: var(--dsf-ts-muted);
    cursor: pointer;
    font-size: 1.25rem;
    line-height: 1;
    padding: .25rem .4rem;
}

.dsf-ts-pcard__del:hover { color: var(--dsf-ts-danger); }

.dsf-ts-pcard__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .6rem .7rem;
    padding: .75rem .8rem .85rem;
}

.dsf-ts-pcard__grid label { display: block; }

.dsf-ts-pcard__grid label span {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-size: .68rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
    margin-bottom: .25rem;
}

.dsf-ts-pcard__grid input[type="text"],
.dsf-ts-pcard__grid select {
    width: 100%;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
    padding: .55rem .55rem;
    font-size: 16px; /* iOS: kein Auto-Zoom */
    background: #fff;
    color: var(--dsf-ts-ink);
}

.dsf-ts-pcard__grid input:focus, .dsf-ts-pcard__grid select:focus {
    outline: none;
    border-color: var(--dsf-ts-select);
    box-shadow: 0 0 0 2px rgba(38, 50, 74, .16);
}

.dsf-ts-pcard__wide { grid-column: 1 / -1; }

.dsf-ts-pcard__toggle {
    grid-column: 1 / -1;
    display: flex !important;
    align-items: center;
    gap: .55rem;
    cursor: pointer;
    padding-top: .1rem;
}

.dsf-ts-pcard__toggle input {
    width: 20px;
    height: 20px;
    accent-color: var(--dsf-ts-select);
}

.dsf-ts-pcard__toggle span {
    display: inline !important;
    margin: 0 !important;
    font-size: .8rem !important;
    color: var(--dsf-ts-ink) !important;
}

.dsf-ts-pcard.has-error { border-color: var(--dsf-ts-danger); }

/* Hinweiskasten im Kader-Schritt */
/* "Diese Aktion umfasst 14 Spielersets + 1 Torwartset" — eine Auskunft
   ueber den Umfang, kein Problem. Rot gerahmt las sich das wie eine
   Fehlermeldung ueber dem Kader. */
.dsf-ts-tierhint {
    /* Luft nach UNTEN: der Kasten klebte sonst auf der Kadertabelle und
       wirkte wie deren Kopfzeile statt wie ein eigener Hinweis. */
    margin: 1rem 0 1.4rem;
    border: 1px solid var(--dsf-ts-line);
    border-left: 3px solid var(--dsf-ts-info);
    background: var(--dsf-ts-info-soft);
    padding: .7rem .9rem;
    font-size: .86rem;
    color: #33546b;
    line-height: 1.45;
}

.dsf-ts-tierhint strong { color: #12475f; }

/* Warnton — gleiche Form wie der Info-Kasten, andere Farbe. Bewusst
   dieselbe Palette wie der Hinweis an der Warenkorbposition, damit
   Konfigurator und Warenkorb dieselbe Sprache sprechen. */
.dsf-ts-tierhint--warn {
    border-color: #fde68a;
    border-left-color: #f59e0b;
    background: #fef9e7;
    color: #5b4500;
}

.dsf-ts-tierhint--warn strong { color: #5b4500; }

/* ---------- Veredelungs-Optionen ---------- */
.dsf-ts-opt {
    border: 1px solid var(--dsf-ts-line);
    margin-bottom: .8rem;
    background: #fff;
}

.dsf-ts-opt__head {
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .8rem .95rem;
    cursor: pointer;
}

.dsf-ts-opt__check {
    width: 22px;
    height: 22px;
    border: 2px solid var(--dsf-ts-line);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: .8rem;
    font-weight: 700;
    transition: background-color .12s ease, border-color .12s ease;
}

/* NUR der eigene Haken: seit die Zusatzleistung IN der Logo-Box sitzt,
   traf ein Nachfahren-Selektor auch deren Haken — die Unter-Option sah
   dadurch angehakt aus, obwohl sie es nicht war. */
.dsf-ts-opt.is-on > .dsf-ts-opt__head > .dsf-ts-opt__check {
    background: var(--dsf-ts-select);
    border-color: var(--dsf-ts-select);
}

/* Zwei verschiedene Zustaende, bewusst getrennt:

   is-locked  = Pflicht. Der Haken laesst sich nicht entfernen. Das heisst
                aber NICHT, dass es nichts zu tun gaebe — der Vereinsname
                ist Pflicht, und der Kunde tippt ihn trotzdem selbst.
                Deshalb bleibt der Haken hier in der Auswahlfarbe.

   is-fixed   = unveraenderbar. Hier gibt es gar nichts zu entscheiden und
                nichts einzugeben (z. B. das Sponsorlogo, das automatisch
                platziert wird). NUR dieser Fall wird grau dargestellt.

   Grau bekommt bewusst nur der Haken. Den ganzen Kasten abzublenden wuerde
   auch die Begruendung ("Fester Bestandteil der Aktion") schlechter lesbar
   machen — und die soll man ja gerade lesen. */
.dsf-ts-opt.is-locked .dsf-ts-opt__head { cursor: default; }

.dsf-ts-opt.is-fixed.is-on > .dsf-ts-opt__head > .dsf-ts-opt__check {
    background: var(--dsf-ts-muted);
    border-color: var(--dsf-ts-muted);
    opacity: .55;
}

.dsf-ts-opt.is-locked > .dsf-ts-opt__head > .dsf-ts-opt__check {
    cursor: default;
}

.dsf-ts-opt__label { flex: 1; min-width: 0; }

.dsf-ts-opt__label strong {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    /* Fix in px + !important: unabhaengig von Theme-Root UND etwaigen
       Theme-Regeln mit hoeherer Spezifitaet */
    font-size: 15px !important;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--dsf-ts-ink);
}

/* Beschreibung bewusst klein und leise — die Option selbst (Titel +
   Preis) traegt die Entscheidung, der Text ist nur Zusatzinfo.
   Fix in px: auf dem Shop-Theme rechnete rem auf ~18px hoch. */
.dsf-ts-opt__label small {
    color: var(--dsf-ts-muted);
    font-size: 15px !important;
    line-height: 1.35;
    display: block;
    margin-top: .15rem;
}

/* Das Maß ist eine Randnotiz, keine Ueberschrift: normale Staerke, gleiche
   Farbe wie die Beschreibung. Es steht ohnehin nur unter einer bereits
   aktivierten Veredelung — wer es sieht, hat sich schon entschieden.
   Selektor mit Element-Teil, weil sonst `.dsf-ts-opt__label small`
   (Klasse + Element) gewinnt und Farbe/Groesse hier wirkungslos waeren. */
.dsf-ts-opt__label small.dsf-ts-opt__size {
    color: var(--dsf-ts-muted);
    font-size: 14px !important;
    font-weight: 400;
    line-height: 1.35;
    display: block;
    margin-top: .2rem;
}

/* Der Zustand der Veredelung (inklusive/Pflicht/optional) — eine
   Randnotiz wie das Mass, gleiche Anmutung. Bewusst NICHT blau: das ist
   kein Wegweiser, sondern eine Eigenschaft. */
.dsf-ts-opt__label small.dsf-ts-opt__status {
    color: var(--dsf-ts-muted);
    font-size: 14px !important;
    font-weight: 400;
    line-height: 1.35;
    display: block;
    margin-top: .2rem;
}

/* "Das trägst du gleich ein": Wegweiser, keine Beschreibung. Deshalb in
   Blau abgesetzt (wie alle Hinweise im Plugin) statt im Grau der
   Beschreibungszeile — sonst geht der Satz genau dort unter, wo er
   gebraucht wird. Element-Teil im Selektor, sonst gewinnt
   `.dsf-ts-opt__label small`. */
.dsf-ts-opt__label small.dsf-ts-opt__next {
    color: var(--dsf-ts-info);
    font-size: 14px !important;
    font-weight: 500;
    line-height: 1.35;
    display: block;
    margin-top: .25rem;
}

.dsf-ts-upload__warn {
    margin: .5rem 0 0;
    padding: .6rem .75rem;
    border-left: 3px solid var(--dsf-ts-red);
    background: #fff6f6;
    font-size: 14px;
    line-height: 1.4;
    color: var(--dsf-ts-ink);
}

.dsf-ts-opt__price {
    font-family: var(--dsf-ts-head);
    font-size: 1.15rem;
    color: var(--dsf-ts-ink);
    white-space: nowrap;
}

/* "inklusive" ist eine gute Nachricht, kein Warnhinweis: Rot liest sich
   wie ein Fehler. Gruen sagt "kostet nichts extra". */
/* Eigener, dunklerer Gruenton: das CTA-Gruen (#66a834) haette auf
   Weiss zu wenig Kontrast fuer kleinen Text. */
.dsf-ts-opt__price.is-free { color: #2e7d32; font-weight: 600; }

.dsf-ts-opt__body {
    display: none;
    border-top: 1px solid #eef0f3;
    padding: .9rem .95rem 1rem;
}

.dsf-ts-opt.is-on > .dsf-ts-opt__body { display: block; }

/* Datenschutz-Hinweis an einer Veredelungs-Option: leise, aber immer
   sichtbar — auch wenn die Option (noch) nicht aktiv ist. */
.dsf-ts-opt__privacy {
    margin: 0;
    padding: .5rem .95rem .7rem;
    font-size: .74rem;
    line-height: 1.4;
    /* Hart gesetzt: eine Datenschutz-Fussnote darf nie wie eine Warnung
       aussehen. Ueber die Variable allein war der Ton je nach Theme rot. */
    color: #6b7280;
    border-top: 1px dashed var(--dsf-ts-line);
}
.dsf-ts-opt__body .dsf-ts-opt__privacy { border-top: 0; padding: .5rem 0 0; }

/* Zusatzleistung IN der Logo-Box (Datencheck): eingerueckt und leicht
   abgesetzt, damit sie als Angebot ZUM Logo lesbar bleibt und nicht als
   weitere Druckstelle. */
/* Zusatzleistung IN der Logo-Box: GRUEN statt Rot. Das ist ein Angebot,
   das etwas besser macht — kein Warnhinweis. */
.dsf-ts-opt--sub {
    margin: .8rem 0 0;
    border-left: 3px solid var(--dsf-ts-green);
    background: #f6faf2;
}

.dsf-ts-opt--sub.is-on > .dsf-ts-opt__head > .dsf-ts-opt__check {
    background: var(--dsf-ts-green);
    border-color: var(--dsf-ts-green);
}

.dsf-ts-opt--sub .dsf-ts-opt__head { padding: .7rem .8rem; }

.dsf-ts-opt--sub .dsf-ts-opt__label strong { font-size: .84rem; }

.dsf-ts-opt--sub .dsf-ts-opt__body { padding: .7rem .8rem .8rem; }

.dsf-ts-opt--sub .dsf-ts-opt__privacy { padding: .5rem .8rem .6rem; }

/* Ergebnis des Basis-Datenchecks unter dem Upload-Feld. Bewusst ruhig:
   Es ist eine Auskunft, keine Fehlermeldung — nur der Warn-Fall bekommt
   Farbe, damit er sich abhebt. */
.dsf-ts-check {
    margin: .5rem 0 0;
    padding: .55rem .7rem;
    border-left: 3px solid var(--dsf-ts-line);
    background: #f6f7f8;
    font-size: .82rem;
    line-height: 1.45;
    color: var(--dsf-ts-muted);
}
.dsf-ts-check strong { display: block; color: var(--dsf-ts-ink); font-weight: 600; }
.dsf-ts-check ul { margin: .3rem 0 0; padding-left: 1.05rem; }
.dsf-ts-check li { margin: .12rem 0; }
.dsf-ts-check li.is-warn { color: var(--dsf-ts-danger); }
.dsf-ts-check--ok { border-left-color: #2e7d32; }
.dsf-ts-check--warn { border-left-color: var(--dsf-ts-danger); background: #fdf3f4; }

/* Upload-Feld */
.dsf-ts-upload {
    /* Bezugspunkt fuer den Loeschen-Knopf in der Ecke. Ohne das haengt er
       am naechsten positionierten Vorfahren — irgendwo im Panel. */
    position: relative;
    display: block;
    border: 2px dashed var(--dsf-ts-line);
    background: var(--dsf-ts-bg-soft);
    padding: 1.2rem 1rem;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.dsf-ts-upload:hover, .dsf-ts-upload.is-drag {
    border-color: var(--dsf-ts-select);
    background: #f2f5fa;
}

.dsf-ts-upload input[type="file"] { display: none; }

.dsf-ts-upload__icon { font-size: 1.6rem; color: var(--dsf-ts-red); }

.dsf-ts-upload__text { font-size: .88rem; color: var(--dsf-ts-muted); margin-top: .3rem; }

.dsf-ts-upload__text strong { color: var(--dsf-ts-select); }

/* Datei liegt vor — das ist ein Erfolg. Rot umrandet mit rosa Flaeche sah
   der fertige Upload aus wie eine Fehlermeldung. */
.dsf-ts-upload.has-file {
    border-style: solid;
    border-color: var(--dsf-ts-green);
    background: #f4faef;
}

/* Loeschen-Knopf im Upload-Kasten. Er liegt IM label, deshalb muss er
   sich klar davon abheben und gross genug zum Treffen sein (44 px sind
   das Mindestmaß fuer einen Finger). */
.dsf-ts-upload__clear {
    position: absolute;
    top: .35rem;
    right: .35rem;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    color: var(--dsf-ts-muted);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
    border-radius: 0;
    z-index: 2;
}

.dsf-ts-upload__clear:hover {
    border-color: var(--dsf-ts-danger, #b3261e);
    color: var(--dsf-ts-danger, #b3261e);
}

/* Wahl "So lassen / Freistellen" unter dem hochgeladenen Wappen.
   Ein geschlossenes Wappen wird beim Hochladen automatisch freigestellt,
   ein Schriftzug nicht — dort entscheidet der Verein, und zwar mit einem
   Klick und beliebig oft, weil das Original liegen bleibt. */
.dsf-ts-logostil {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin: .55rem 0 0;
}

.dsf-ts-logostil__label {
    font-family: var(--dsf-ts-sub);
    font-size: .74rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

/* ACHTUNG, hier steckte der Fehler: --dsf-ts-text gibt es in diesem
   Stylesheet NICHT. Damit war beim aktiven Knopf der Hintergrund
   ungueltig (also durchsichtig) und die Schrift weiss — weiss auf weiss.
   Der Knopf war da, man sah ihn nur nicht. Die Textfarbe heisst hier
   --dsf-ts-ink, die Auswahlfarbe --dsf-ts-select. */
.dsf-ts-logostil button {
    font: inherit;
    font-size: .82rem;
    padding: .3rem .7rem;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    color: var(--dsf-ts-ink);
    cursor: pointer;
    border-radius: 0;
}

.dsf-ts-logostil button:hover:not(:disabled) { border-color: var(--dsf-ts-ink); }
.dsf-ts-logostil button.is-active {
    background: var(--dsf-ts-select, #1f2d3d);
    border-color: var(--dsf-ts-select, #1f2d3d);
    color: #fff;
}
.dsf-ts-logostil button:disabled { opacity: .55; cursor: default; }

/* Der Hinweis gehoert in eine eigene Zeile: nebeneinander wurde er bei
   schmalen Panels zwischen die Knoepfe gequetscht. */
.dsf-ts-logostil__hint {
    flex: 1 0 100%;
    font-size: .8rem;
    line-height: 1.45;
    color: var(--dsf-ts-muted);
}

/* Druck-Hinweis unter dem Logo-Upload: Datei wird 1:1 gedruckt */
.dsf-ts-upload__note {
    margin: .5rem 0 0;
    padding: .5rem .7rem;
    border-left: 3px solid var(--dsf-ts-info);
    background: var(--dsf-ts-info-soft);
    font-size: .78rem;
    line-height: 1.45;
    color: var(--dsf-ts-muted);
}

.dsf-ts-upload__note strong { color: var(--dsf-ts-ink, #1b1b1d); }

.dsf-ts-upload__preview {
    max-height: 72px;
    margin: 0 auto .4rem;
    display: block;
}

/* ---------- Auswahl-Weiche (Trikotsatz vs. Ausrüstung) ---------- */
.dsf-ts-choice-grid--modes { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

.dsf-ts-choice__media--gear { color: var(--dsf-ts-red); }

.dsf-ts-gearicons {
    display: flex;
    gap: .5rem;
    align-items: center;
    justify-content: center;
    width: 100%;
}

.dsf-ts-gearicons svg { width: 30%; height: auto; }

/* Ausruestungs-Weg + Sportart-Wahl: einspaltig, ohne Trikot-Vorschau */
.dsf-ts-journey.is-gear .dsf-ts-jbody,
.dsf-ts-journey.is-fullpanel .dsf-ts-jbody { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.dsf-ts-journey.is-gear .dsf-ts-preview,
.dsf-ts-journey.is-fullpanel .dsf-ts-preview { display: none; }

/* ---------- Sportart-/Set-Bildkacheln ---------- */
.dsf-ts-sportcards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.2rem;
    max-width: 880px;
}

.dsf-ts-sportcard {
    border: 2px solid var(--dsf-ts-line);
    background: #fff;
    padding: 0;
    text-align: left;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    font: inherit;
    color: inherit;
    position: relative;
    transition: border-color .15s ease, box-shadow .18s ease, transform .18s ease;
}

.dsf-ts-sportcard:hover {
    border-color: #b9c6d8;
    box-shadow: var(--dsf-ts-shadow-lift);
    transform: translateY(-3px);
}

.dsf-ts-sportcard.is-selected { border-color: var(--dsf-ts-select); }

.dsf-ts-sportcard__media {
    display: block;
    /* Quadratisch — wie die Sortiment-Kacheln in Schritt 1 (choice__media).
       Vorher 16/10: das schnitt bei stehenden Motiven (Spieler in ganzer
       Figur) oben und unten ab und liess die Kacheln je nach Bildformat
       unterschiedlich hoch wirken. */
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-bottom: 1px solid var(--dsf-ts-line);
    background: var(--dsf-ts-bg-soft);
}

.dsf-ts-sportcard__media img,
.dsf-ts-sportcard__media svg {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.dsf-ts-sportcard__body {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    padding: 1rem 1.05rem 1.1rem;
    flex: 1;
}

.dsf-ts-sportcard__body strong {
    font-family: var(--dsf-ts-head);
    font-size: 1.55rem;
    text-transform: uppercase;
    color: var(--dsf-ts-ink);
    line-height: 1;
}

.dsf-ts-sportcard__body small {
    color: var(--dsf-ts-muted);
    font-size: .88rem;
    line-height: 1.45;
}

/* Preisblock der Satz-Kachel — drei Zeilen untereinander:
   Streichpreis, Angebotspreis, Erklaerung. Nebeneinander verschwamm auf
   schmalen Kacheln, welche Zahl was bedeutet. */
.dsf-ts-sportcard__price {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .1rem;
    font-family: var(--dsf-ts-head);
    font-size: 1.25rem;
    color: var(--dsf-ts-ink);
}

/* UVP und Aktionspreis stehen NEBENeinander in einer Zeile. Der UVP wird
   nicht durchgestrichen — er steht als Bezugsgroesse daneben. */
.dsf-ts-sportcard__pricerow {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .5rem;
}

/* UVP zum Vergleich: leiser als der Angebotspreis, damit klar ist,
   welche Zahl gilt */
.dsf-ts-sportcard__rrp {
    font-family: var(--dsf-ts-sub);
    font-size: .8rem;
    font-weight: 400;
    color: var(--dsf-ts-muted);
    line-height: 1.2;
    text-decoration: none;
}

/* Der Preis, der gilt — in der Aktionsfarbe.
   Selektor mit Element-Teil, weil sonst `.dsf-ts-sportcard__body strong`
   bzw. `... small` (Klasse + Element) gewinnt und Farbe und Groesse hier
   wirkungslos blieben. */
.dsf-ts-sportcard__body strong.dsf-ts-sportcard__now {
    font-family: var(--dsf-ts-head);
    font-size: 1.5rem;
    font-weight: 700;
    text-transform: none;
    color: var(--dsf-ts-red);
    line-height: 1.1;
}

/* Was im Preis steckt */
.dsf-ts-sportcard__body small.dsf-ts-sportcard__scope {
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    color: var(--dsf-ts-muted);
    line-height: 1.3;
    white-space: normal;
}

.dsf-ts-sportcard__cta { margin-top: .6rem; align-self: stretch; }

/* ---------- Vereinsname-Eingabe (teamtext) ---------- */
/* Ein- und mehrzeiliges Feld teilen sich das Aussehen */
.dsf-ts-teamtext input,
.dsf-ts-teamtext textarea {
    width: 100%;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
    padding: .6rem .65rem;
    font-size: 16px;
    color: var(--dsf-ts-ink);
}

/* KEINE min-height: die Hoehe kommt aus dem rows-Attribut, das beim Tippen
   mitwaechst (einzeilig starten, bis 3 Zeilen). Eine feste Mindesthoehe
   haette das Feld immer dreizeilig aussehen lassen. */
.dsf-ts-teamtext textarea {
    resize: none;
    overflow: hidden;
    line-height: 1.35;
    font-family: inherit;
    transition: height .12s ease;
}

.dsf-ts-teamtext__hint {
    margin: .35rem 0 0;
    font-size: .78rem;
    line-height: 1.4;
    color: var(--dsf-ts-muted);
}

/* Fokus in der Auswahlfarbe — ein Eingabefeld, in dem der Cursor steht,
   ist kein Fehler. Rot bleibt dem Fehlerzustand vorbehalten. */
.dsf-ts-teamtext input:focus,
.dsf-ts-teamtext textarea:focus {
    outline: none;
    border-color: var(--dsf-ts-select);
    box-shadow: 0 0 0 2px rgba(38, 50, 74, .16);
}

/* ---------- Gespeicherte Designs ---------- */
.dsf-ts-designs {
    margin-top: 1.6rem;
    border: 1px solid var(--dsf-ts-line);
    background: var(--dsf-ts-bg-soft);
    padding: .9rem .95rem 1rem;
}

.dsf-ts-designs h4 {
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .88rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--dsf-ts-ink);
    margin: 0 0 .6rem;
}

.dsf-ts-designs__row {
    display: flex;
    align-items: center;
    gap: .7rem;
    background: #fff;
    border: 1px solid var(--dsf-ts-line);
    padding: .5rem .65rem;
    margin-bottom: .45rem;
}

.dsf-ts-designs__row:last-child { margin-bottom: 0; }

.dsf-ts-designs__badge {
    flex-shrink: 0;
    background: var(--dsf-ts-select);
    color: #fff;
    font-family: var(--dsf-ts-sub);
    font-size: .64rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    padding: .25rem .5rem;
}

.dsf-ts-designs__badge.is-gear { background: var(--dsf-ts-black); }

.dsf-ts-designs__name {
    flex: 1;
    min-width: 0;
    font-weight: 700;
    font-size: .92rem;
    color: var(--dsf-ts-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dsf-ts-designs__name small {
    font-weight: 400;
    color: var(--dsf-ts-muted);
    margin-left: .45rem;
}

.dsf-ts-designs__del {
    border: 0;
    background: none;
    color: var(--dsf-ts-muted);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    padding: .3rem .4rem;
    flex-shrink: 0;
}

.dsf-ts-designs__del:hover { color: var(--dsf-ts-danger); }

.dsf-ts-designsave {
    display: flex;
    gap: .6rem;
    margin: 1rem 0 .2rem;
}

.dsf-ts-designsave input {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
    padding: .6rem .65rem;
    font-size: 16px;
    color: var(--dsf-ts-ink);
}

.dsf-ts-designsave input:focus {
    outline: none;
    border-color: var(--dsf-ts-select);
    box-shadow: 0 0 0 2px rgba(38, 50, 74, .16);
}

/* ---------- Erfolgs-Hub ---------- */
.dsf-ts-success {
    max-width: 480px;
    margin: clamp(1rem, 8vh, 4rem) auto 0;
    text-align: center;
}

.dsf-ts-success__check {
    width: 64px;
    height: 64px;
    margin: 0 auto 1.1rem;
    background: var(--dsf-ts-green);
    color: #fff;
    font-size: 2rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

.dsf-ts-success h2 {
    font-family: var(--dsf-ts-head);
    font-size: clamp(1.7rem, 3vw, 2.3rem);
    text-transform: uppercase;
    color: var(--dsf-ts-ink);
    margin: 0 0 .5rem;
}

.dsf-ts-success p {
    color: var(--dsf-ts-muted);
    font-size: .95rem;
    line-height: 1.55;
    margin: 0 0 1.5rem;
}

.dsf-ts-success__actions {
    display: flex;
    flex-direction: column;
    gap: .6rem;
}

.dsf-ts-success__actions .dsf-ts-btn { width: 100%; }

/* Team-Link (Nachbestellung): teilbarer Link zur gespeicherten Konfig */
.dsf-ts-teamlink {
    margin-top: 1.1rem;
    border: 1px solid var(--dsf-ts-line);
    /* Auch das ist ein Hinweis, kein Fehler — blau wie die uebrigen
       Info-Kaesten. (Der Warnkasten beim Logo-Upload behaelt sein Rot: dort
       stimmt etwas mit der Datei nicht.) */
    border-left: 3px solid var(--dsf-ts-info);
    background: var(--dsf-ts-bg-soft, #f7f7f8);
    padding: .85rem 1rem;
    text-align: left;
}
.dsf-ts-teamlink strong {
    display: block;
    font-family: var(--dsf-ts-sub);
    text-transform: uppercase;
    letter-spacing: .05em;
    font-size: .82rem;
    margin-bottom: .3rem;
}
.dsf-ts-teamlink p { margin: 0 0 .6rem; font-size: .82rem; color: var(--dsf-ts-muted); line-height: 1.5; }
.dsf-ts-teamlink__row { display: flex; gap: .5rem; }
.dsf-ts-teamlink__row input {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: .5rem .6rem;
    font-size: .8rem;
    color: var(--dsf-ts-ink, #1b1b1d);
}
.dsf-ts-teamlink__row .dsf-ts-btn { flex-shrink: 0; width: auto; }

/* ---------- Ausrüstung (Add-ons) ---------- */
.dsf-ts-gear {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    margin-bottom: .9rem;
}

.dsf-ts-gear__head {
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: .85rem .95rem;
    border-bottom: 1px solid #eef0f3;
}

.dsf-ts-gear__icon {
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    color: var(--dsf-ts-red);
    background: var(--dsf-ts-bg-soft);
    border: 1px solid var(--dsf-ts-line);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px;
}

.dsf-ts-gear__icon svg { width: 100%; height: 100%; }

.dsf-ts-gear__label { flex: 1; min-width: 0; }

.dsf-ts-gear__label strong {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .98rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--dsf-ts-ink);
}

.dsf-ts-gear__label small {
    color: var(--dsf-ts-muted);
    font-size: .82rem;
    line-height: 1.35;
    display: block;
    margin-top: .1rem;
}

.dsf-ts-gear__price {
    font-family: var(--dsf-ts-head);
    font-size: 1.2rem;
    color: var(--dsf-ts-ink);
    white-space: nowrap;
    text-align: right;
}

.dsf-ts-gear__price small {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-size: .64rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-gear__sizes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
    gap: .5rem;
    padding: .8rem .95rem;
}

.dsf-ts-gear__size {
    border: 1px solid var(--dsf-ts-line);
    padding: .45rem .55rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}

.dsf-ts-gear__size > span {
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    font-size: .85rem;
    color: var(--dsf-ts-ink);
}

.dsf-ts-gear__stepper {
    display: flex;
    align-items: center;
    gap: .15rem;
}

.dsf-ts-gear__stepper button {
    width: 30px;
    height: 30px;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    color: var(--dsf-ts-ink);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.dsf-ts-gear__stepper button:hover { border-color: var(--dsf-ts-select); color: var(--dsf-ts-select); }

.dsf-ts-gear__stepper output {
    min-width: 26px;
    text-align: center;
    font-weight: 700;
    font-size: .95rem;
    font-variant-numeric: tabular-nums;
}

.dsf-ts-gear__tools {
    padding: 0 .95rem .85rem;
}

/* ---------- Zusammenfassung ---------- */
.dsf-ts-sum { border: 1px solid var(--dsf-ts-line); margin-bottom: 1rem; }

.dsf-ts-sum__row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: .65rem .9rem;
    border-bottom: 1px solid #eef0f3;
    font-size: .92rem;
}

.dsf-ts-sum__row:last-child { border-bottom: 0; }

.dsf-ts-sum__row--head {
    background: var(--dsf-ts-bg-soft);
    font-family: var(--dsf-ts-sub);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-size: .8rem;
    color: var(--dsf-ts-muted);
}

.dsf-ts-sum__row--total {
    background: var(--dsf-ts-black);
    color: #fff;
    font-family: var(--dsf-ts-head);
    font-size: 1.25rem;
}

.dsf-ts-sum__row--total small {
    font-family: var(--dsf-ts-sub);
    font-size: .68rem;
    opacity: .75;
    display: block;
}

.dsf-ts-sum__qty { color: var(--dsf-ts-muted); white-space: nowrap; }

.dsf-ts-sum__price { white-space: nowrap; font-weight: 700; }

.dsf-ts-consent {
    display: flex;
    /* umbrechen, damit die Fehlerzeile eine eigene Zeile unter dem Text
       bekommt statt sich neben das Kaestchen zu quetschen */
    flex-wrap: wrap;
    gap: .7rem;
    align-items: flex-start;
    border: 1px solid var(--dsf-ts-line);
    background: var(--dsf-ts-bg-soft);
    padding: .85rem .95rem;
    margin: 1rem 0 1.2rem;
    cursor: pointer;
}

.dsf-ts-consent input {
    margin-top: .2rem;
    width: 18px;
    height: 18px;
    accent-color: var(--dsf-ts-select);
    flex-shrink: 0;
}

.dsf-ts-consent.has-error {
    border-color: var(--dsf-ts-danger);
    background: #fdf2f2;
    animation: dsf-ts-nudge .3s ease 2;
}

@keyframes dsf-ts-nudge {
    0%, 100% { transform: translateX(0); }
    50% { transform: translateX(4px); }
}

@media (prefers-reduced-motion: reduce) {
    .dsf-ts-consent.has-error { animation: none; }
}

.dsf-ts-consent span {
    font-size: .85rem;
    color: var(--dsf-ts-muted);
    line-height: 1.5;
}

/* ---------- Toast / Fehlerhinweise ---------- */
/* Als schmales Band oben, unter der Schrittleiste — das JS setzt die
   genaue Hoehe (top) aus der Unterkante der Leiste.
   Dritter Anlauf: unten lag die Meldung ueber der Navigationsleiste und
   verdeckte die Schaltflaeche, um die es ging. Mittig stand sie mitten im
   Inhalt und verdeckte auf der Zusammenfassung den Nachbestell-Hinweis.
   Oben verdeckt sie nichts, ist aber im Blickfeld. Pflichtfeld-Fehler
   laufen ohnehin nicht mehr hierueber, sondern stehen am Feld selbst
   (.dsf-ts-fielderr). */
/* ---------- Hinweis-Fenster ----------
   Frueher ein dunkles Band am oberen Rand. Es sah aus wie eine Mitteilung
   des Browsers und gehoerte optisch nicht zum Konfigurator.

   Jetzt eine Karte in der Bildmitte, im Haus-Muster: weiss, kantig,
   farbiger Streifen links — dasselbe, was die Mengen- und Paket-Kaesten
   schon benutzen. Dazu ein Zeichen, eine Zeile, die die Art der Meldung
   benennt, und ein Kreuz zum Wegtippen.

   pointer-events steht auf none, solange sie unsichtbar ist: eine
   ausgeblendete Karte darf keine Klicks abfangen. Sichtbar nimmt sie
   Klicks an — sonst waere das Kreuz nicht zu treffen. */
.dsf-ts-toast {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, calc(-50% + 10px));
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    width: min(92vw, 420px);
    /* Pflicht: ohne border-box kaemen Innenabstand und der 4-px-Streifen
       auf die 92vw OBENDRAUF — auf einem 390er Display war die Karte damit
       398 px breit und ragte links wie rechts aus dem Bild. */
    box-sizing: border-box;
    background: #fff;
    color: var(--dsf-ts-text);
    border-left: 4px solid var(--dsf-ts-info);
    padding: .95rem 1.1rem;
    font-size: .88rem;
    line-height: 1.45;
    text-align: left;
    z-index: 2147483647;
    opacity: 0;
    pointer-events: none;
    transition: opacity .18s ease, transform .18s ease;
    box-shadow: 0 18px 50px rgba(20, 20, 22, .28);
}

.dsf-ts-toast.is-visible {
    opacity: 1;
    transform: translate(-50%, -50%);
    pointer-events: auto;
}

.dsf-ts-toast__icon {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--dsf-ts-info-soft);
    color: var(--dsf-ts-info);
    font-family: var(--dsf-ts-sub);
    font-weight: 700;
    font-size: .95rem;
}

.dsf-ts-toast__body { min-width: 0; }

.dsf-ts-toast__title {
    display: block;
    font-family: var(--dsf-ts-sub);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    font-size: .68rem;
    color: var(--dsf-ts-muted);
    margin-bottom: .2rem;
}

.dsf-ts-toast__text { display: block; overflow-wrap: anywhere; }

.dsf-ts-toast__close {
    flex: 0 0 auto;
    align-self: flex-start;
    border: 0;
    background: none;
    cursor: pointer;
    color: var(--dsf-ts-muted);
    font-size: 1.25rem;
    line-height: 1;
    /* Optisch ein kleines Kreuz, als Ziel aber gross genug fuer einen
       Daumen — deshalb Innenabstand statt Breite. */
    padding: .2rem .1rem .4rem .5rem;
    touch-action: manipulation;
}

.dsf-ts-toast__close:hover { color: var(--dsf-ts-text); }

/* Fehler direkt am Feld: eigene Zeile im markierten Kasten. Kein
   schwebendes Element — der Kunde liest dort, wo er handeln muss. */
.dsf-ts-fielderr {
    flex-basis: 100%;
    margin: .15rem 0 0;
    font-size: .82rem;
    font-weight: 600;
    color: var(--dsf-ts-danger);
    line-height: 1.45;
}

/* Die Art der Meldung faerbt nur den Streifen und das Zeichen — der Kasten
   bleibt weiss. Ein vollflaechig roter Kasten schreit; hier reicht die
   Kante, um "Achtung" zu sagen, und der Text bleibt in jedem Fall gut
   lesbar (dunkel auf weiss). */
.dsf-ts-toast--error { border-left-color: var(--dsf-ts-danger); }
.dsf-ts-toast--error .dsf-ts-toast__icon {
    background: #fdecec;
    color: var(--dsf-ts-danger);
}

.dsf-ts-toast--success { border-left-color: var(--dsf-ts-green); }
.dsf-ts-toast--success .dsf-ts-toast__icon {
    background: #eef7e8;
    /* Nicht das CTA-Gruen: auf hellem Grund kaeme es nur auf rund 2,6:1.
       Dieser dunklere Ton liegt bei ueber 5:1. */
    color: #4a7a2c;
}

/* ---------- Spinner ---------- */
.dsf-ts-spinner {
    width: 22px;
    height: 22px;
    border: 3px solid rgba(255, 255, 255, .35);
    border-top-color: #fff;
    border-radius: 50%;
    animation: dsf-ts-spin .7s linear infinite;
    display: inline-block;
    vertical-align: middle;
}

@keyframes dsf-ts-spin { to { transform: rotate(360deg); } }

/* =====================================================================
   3. RESPONSIVE
   ===================================================================== */

@media (max-width: 991px) {
    .dsf-ts-hero__inner { grid-template-columns: 1fr; }
    .dsf-ts-hero__visual { order: -1; }
    .dsf-ts-hero__visual svg, .dsf-ts-hero__visual img { width: min(230px, 60%); }

    /* "Gesamt inkl. MwSt." im GESAMTEN Mobil-Layout fix 10px — nicht nur
       unter 576px (das Theme rechnet rem sonst gross) */
    .dsf-ts-jh__total small { font-size: 10px !important; }

    /* Vorschau kompakt, Hoehe folgt dem Inhalt (Foto = 52vw) — einklappbar.
       56dvh waren zu viel: auf einem 725-px-Display blieben dem Bedienbereich
       nur noch 197 px, also ein Guckloch, durch das man 2200 px Inhalt
       scrollen musste. 42dvh mit Deckel gibt rund ein Drittel davon zurueck,
       ohne dass das Trikot zu klein wird. */
    .dsf-ts-jbody { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
    .dsf-ts-preview {
        border-right: 0;
        border-bottom: 1px solid var(--dsf-ts-line);
        padding: .6rem .8rem .75rem;
        height: auto;
        max-height: clamp(200px, 42dvh, 340px);
        min-height: 0;
        overflow: hidden;
        transition: padding .2s ease;
    }
    .dsf-ts-preview__stage { width: auto; height: auto; display: flex; justify-content: center; }
    .dsf-ts-preview__stage svg { width: auto; max-height: 34dvh; }
    /* Der Hinweis-(i) fehlte mobil — jetzt als kleiner Button oben links
       (nur das Icon; der Erklaertext liegt im Popover). Der dunkle
       Leisten-Hintergrund + Padding entfallen, damit NUR der weisse
       (i)-Kreis sichtbar ist. Desktop unveraendert. */
    .dsf-ts-preview__hint {
        position: absolute;
        top: .55rem;
        /* Deutlich vom Rand abruecken — ganz links ging das (i) optisch
           unter. transform:none ist Pflicht: das Basis-translateX(-50%)
           zog den Knopf sonst um die halbe Breite nach links. */
        left: 1.1rem;
        transform: none;
        z-index: 3;
        margin: 0;
        display: inline-flex;
        background: none;
        padding: 0;
    }
    .dsf-ts-preview__hinttext { display: none; }
    .dsf-ts-preview__infobtn { margin-left: 0; }

    /* Mobil steht der Umschalter UNTER dem Foto — dort ist der Daumen.
       Dafuer muss die Desktop-Umsortierung (order: -1) zurueckgenommen
       werden, sonst rutscht er auch hier ueber das Bild.

       Der Vorschau-Knopf steht jetzt DANEBEN, in derselben Flucht und mit
       derselben Hoehe. Vorher klebte er oben rechts in der Ecke: erreichbar,
       solange die Vorschau zu war, aber im offenen Zustand ausgerechnet
       dann weit weg, wenn man sie schliessen will. */
    .dsf-ts-preview__bar {
        /* Drei Spalten: leer | Vorne/Hinten | Vorschau-Knopf.
           Der Umschalter steht dadurch WIRKLICH mittig unter dem Trikot —
           nicht nur mittig im Rest, der neben dem Knopf uebrig bleibt —,
           und der Vorschau-Knopf sitzt ganz rechts. Beide in derselben
           Zeile, also auf gleicher Hoehe.

           Ist die Vorschau zugeklappt, faellt der Umschalter weg; der
           Vorschau-Knopf rutscht dann in die mittlere Spalte und steht
           dort zentriert. */
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        align-items: stretch;
        gap: .4rem;
        width: 100%;
        max-width: 100%;
        margin: .55rem 0 0;
        order: 0;
        /* Vorne/Hinten und der Vorschau-Knopf kamen beide nur auf 30 px —
           gleich gross, aber zu klein fuer einen Daumen. Die Hoehe steht
           deshalb an der LEISTE: so wachsen beide zusammen und bleiben
           bündig, statt dass einer den anderen überragt. */
        min-height: 38px;
    }
    /* Die leere erste Spalte — sie haelt dem Umschalter die Mitte frei. */
    .dsf-ts-preview__bar::before { content: ''; }

    /* Umschalter UND Spielerzeile richten sich an der Mitte des TRIKOTS
       aus, nicht an der Mitte der Vorschau. Beide sind mittig in ihrem
       Kasten; der gemessene Versatz (siehe positionPreviewArrows) schiebt
       sie auf die Trikotmitte. Ohne Messwert bleibt es bei 0 — dann sind
       sie mittig wie bisher. */
    .dsf-ts-preview__toggle {
        order: 0;
        width: auto;
        margin: 0;
        justify-self: center;
        transform: translateX(var(--dsf-ts-trikotmitte, 0px));
    }

    .dsf-ts-preview__player [data-ref="plabel"] {
        transform: translateX(var(--dsf-ts-trikotmitte, 0px));
    }
    .dsf-ts-preview__mode { bottom: .4rem; left: .4rem; }
    /* Aus dem Eck-Knopf wird ein normales Element der Leiste — gleiche
       Hoehe und gleiche Schriftgroesse wie Vorne/Hinten. */
    .dsf-ts-preview__collapse {
        display: inline-flex;
        align-items: center;
        position: static;
        top: auto;
        right: auto;
        /* Ausdruecklich in die DRITTE Spalte, ganz rechts. Ohne die feste
           Spalte waere er beim Zuklappen in die Mitte gerutscht: dann
           faellt der Umschalter weg, und das naechste Gitterfeld ist die
           mittlere Spalte. Eingeklappt soll er aber genauso rechts stehen
           wie aufgeklappt. */
        grid-column: 3;
        justify-self: end;
        padding: .5rem .9rem;
        font-size: .78rem;
        letter-spacing: .08em;
    }

    /* Teaser: der Knopf wackelt kurz, damit sichtbar wird, dass die
       Vorschau auf- und zugeklappt werden kann. Das JS setzt die Klasse
       alle 7 Sekunden neu und hoert nach drei Runden bzw. nach der ersten
       Benutzung auf. */
    .dsf-ts-preview__collapse.is-teaser {
        animation: dsf-ts-teaser .7s ease-in-out;
    }

    @keyframes dsf-ts-teaser {
        0%, 100% { transform: translateX(0); }
        15%      { transform: translateX(-3px); }
        30%      { transform: translateX(3px); }
        45%      { transform: translateX(-2px); }
        60%      { transform: translateX(2px); }
        75%      { transform: translateX(-1px); }
    }

    /* Eingeklappt faellt nur die HOEHE weg, nicht der seitliche Rand:
       ohne ihn klebte der Vorschau-Knopf an der Displaykante, waehrend er
       aufgeklappt seinen Abstand hatte — beim Auf- und Zuklappen sprang er
       also seitlich. Jetzt steht er in beiden Zustaenden gleich. */
    .dsf-ts-preview.is-collapsed {
        height: 0;
        min-height: 44px;
        padding: 0 .8rem;
        overflow: hidden;
    }
    .dsf-ts-preview.is-collapsed .dsf-ts-preview__stage,
    .dsf-ts-preview.is-collapsed .dsf-ts-preview__mode,
    .dsf-ts-preview.is-collapsed .dsf-ts-preview__player,
    .dsf-ts-preview.is-collapsed .dsf-ts-preview__toggle { display: none; }
    /* Eingeklappt bleibt nur der Vorschau-Knopf uebrig. Die Vorschau ist
       eine zentrierte Spalte, also sitzt die Leiste von selbst mittig — es
       braucht kein top/transform mehr, und damit auch keine eigenen
       Wackel-Keyframes, die die Zentrierung nachhalten muessten. */
    .dsf-ts-preview.is-collapsed .dsf-ts-preview__bar { margin: 0; }
}

@media (max-width: 575px) {
    .dsf-ts-jh { flex-wrap: wrap; row-gap: .3rem; padding: .55rem .75rem; }
    .dsf-ts-jh__campaign { display: none; }
    .dsf-ts-jh__total strong { font-size: 1.3rem; }
    /* Fix in px: Label unabhaengig von der Theme-Root-Groesse 10px */
    .dsf-ts-jh__total small { font-size: 10px !important; }

    /* Kompakt-Stepper: inaktive Schritte zeigen nur ihre Nummer, der aktive
       seinen Namen — so passt die ganze Journey ohne Ueberlappung ins Bild. */
    .dsf-ts-stepper__step { min-width: 0; flex: 0 0 auto; padding: .55rem .55rem .5rem; font-size: .74rem; }
    .dsf-ts-stepper__step.is-active { flex: 1 1 auto; }
    .dsf-ts-stepper__step:not(.is-active) .dsf-ts-stepper__label { display: none; }

    .dsf-ts-squad__head, .dsf-ts-squad__row {
        grid-template-columns: var(--dsf-squad-cols-m, var(--dsf-squad-cols, 1.6rem minmax(72px, .9fr) minmax(90px, 1.3fr) minmax(58px, .6fr) 2.4rem));
        gap: .35rem;
    }

    .dsf-ts-squad__head { font-size: .66rem; padding: .45rem .5rem; }
    .dsf-ts-squad__row { padding: .35rem .5rem; }
    /* Blockueberschrift auf die schmalere Innenkante mitziehen */
    .dsf-ts-squad__group { padding: .9rem .5rem .4rem; }
    .dsf-ts-squad__group:first-child { padding-top: .65rem; }

    /* 16px Mindestgroesse: verhindert den iOS-Auto-Zoom beim Fokussieren */
    .dsf-ts-squad input, .dsf-ts-squad select { padding: .5rem .45rem; font-size: 16px; }

    /* Groessere Touch-Targets */
    .dsf-ts-squad__del { font-size: 1.3rem; padding: .5rem .4rem; }
    .dsf-ts-opt__head { padding: .95rem .8rem; }
    .dsf-ts-opt__label small { font-size: 13px !important; }
    .dsf-ts-opt__price { font-size: .95rem; }

    /* Set-/Auswahlkacheln: mobil horizontal statt riesiger Quadrate */
    .dsf-ts-choice-grid { grid-template-columns: 1fr; gap: .7rem; }
    .dsf-ts-choice { flex-direction: row; align-items: stretch; }
    .dsf-ts-choice__media {
        aspect-ratio: 1 / 1;
        width: 96px;
        flex-shrink: 0;
        border-bottom: 0;
        border-right: 1px solid var(--dsf-ts-line);
        padding: .6rem;
    }
    .dsf-ts-choice__body { align-self: center; }

    /* Daumen-freundliche Navigation: Weiter-Button dominiert */
    .dsf-ts-jnav { flex-wrap: wrap; gap: .6rem; }
    .dsf-ts-jnav__info { flex-basis: 100%; order: 2; font-size: .76rem; }

    /* Mobil nur die Kurzfassung — und die bleibt EINZEILIG. Bricht ein
       sehr langer Satzname doch um, schneidet die Ellipse ab; die Hoehe
       der Leiste bleibt damit berechenbar. */
    .dsf-ts-jnav__lang { display: none; }
    .dsf-ts-jnav__kurz {
        display: block;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .dsf-ts-jnav .dsf-ts-btn--primary { flex: 1; min-height: 48px; }
    .dsf-ts-jnav .dsf-ts-btn--line { min-height: 48px; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
    .dsf-ts-card, .dsf-ts-btn, .dsf-ts-choice, .dsf-ts-toast { transition: none; }
    .dsf-ts-card:hover { transform: none; }
}

/* Muster-Aktion: Hinweisbox im Bestell-Schritt (Bestellung deaktiviert) */
.dsf-ts-demohint {
    margin: 0 0 1.1rem;
    padding: .85rem 1.1rem;
    background: #fdf6e3;
    border: 1px solid #e8d9a0;
    border-left: 4px solid #d9a800;
    color: #6b5a12;
    font-size: .88rem;
    line-height: 1.5;
}

/* Ruecken-Position (oben/unten) fuer Namen & Vereinsname */
.dsf-ts-finpos {
    display: flex;
    align-items: center;
    gap: .8rem;
    flex-wrap: wrap;
    margin-top: .75rem;
}
.dsf-ts-finpos__label {
    font-size: .8rem;
    color: var(--dsf-ts-muted);
}
.dsf-ts-finpos__btns {
    display: inline-flex;
    border: 1px solid var(--dsf-ts-line);
}
.dsf-ts-finpos__btns button {
    border: 0;
    background: #fff;
    padding: .45rem .8rem;
    font-size: .78rem;
    font-family: var(--dsf-ts-font-head, inherit);
    text-transform: uppercase;
    letter-spacing: .04em;
    cursor: pointer;
    color: var(--dsf-ts-muted);
}
/* Schreibweise-Buttons NICHT versalisieren — "Wie eingegeben" soll genau
   so lesbar sein (nicht "WIE EINGEGEBEN"); GROSSBUCHSTABEN steht bereits
   gross im Text. Gilt fuer alle betroffenen Positionen. */
.dsf-ts-fincase .dsf-ts-finpos__btns button { text-transform: none; letter-spacing: .01em; }

.dsf-ts-finpos__btns button + button {
    border-left: 1px solid var(--dsf-ts-line);
}
.dsf-ts-finpos__btns button.is-active {
    background: var(--dsf-ts-select);
    color: #fff;
}

/* Waehrend die Journey offen ist: schwebende Drittanbieter-Widgets
   (Trusted Shops/eTrusted-Badge, Accessibility-Buttons) ausblenden —
   sie wuerden sonst ueber dem Konfigurator liegen. */
body.dsf-ts-journey-open [id*="trustbadge"],
body.dsf-ts-journey-open [class*="trustbadge"],
body.dsf-ts-journey-open [id*="etrusted"],
body.dsf-ts-journey-open [class*="etrusted"],
body.dsf-ts-journey-open iframe[src*="trustedshops"],
body.dsf-ts-journey-open iframe[title*="Trusted"],
body.dsf-ts-journey-open [id*="eye-able"],
body.dsf-ts-journey-open [id*="eyeAble"],
body.dsf-ts-journey-open [class*="eye-able"],
body.dsf-ts-journey-open [id*="uc-"][role="dialog"] {
    display: none !important;
}

/* Reset-Button im Journey-Kopf — gleiche Hoehe wie der X-Button (40px) */
.dsf-ts-jh__reset {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    color: var(--dsf-ts-muted);
    height: 40px;
    display: inline-flex;
    align-items: center;
    padding: 0 .7rem;
    /* KEIN eigener Rand — sonst ist die Luecke rechts um genau diesen Wert
       breiter als links, und die Kopfzeile steht schief. Den Abstand setzt
       allein der gap der Kopfzeile, fuer alle Elemente denselben. (Mobil
       galt das schon seit v0.99.119; am Schreibtisch stand der Wert noch.) */
    font-size: .78rem;
    letter-spacing: .04em;
    cursor: pointer;
    white-space: nowrap;
}
.dsf-ts-jh__reset:hover { border-color: var(--dsf-ts-select); color: var(--dsf-ts-select); }
@media (max-width: 767px) {
    .dsf-ts-jh__reset span { display: none; } /* mobil nur das ↺-Symbol */
    /* Mobil nur das Symbol, in derselben Kachelgroesse wie der
       Schliessen-Knopf. Den Abstand zu ihm setzt der gap der Kopfzeile —
       siehe die Grundregel von .dsf-ts-jh__reset. */
    .dsf-ts-jh__reset {
        width: 40px;
        height: 40px;
        padding: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        font-size: 1.15rem;
    }
}

/* (i)-Hinweis an der Live-Vorschau */
/* (i)-Button: weisser Kreis mit rotem „i“ — sichtbar auf hellem UND
   dunklem Untergrund (Desktop-Hinweisleiste wie mobile Vorschauflaeche) */
.dsf-ts-preview__infobtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    margin-left: 0;
    /* Zentrieren heisst hier: die GLYPHE mittig, nicht die Zeilenbox. Das
       kursive "i" hat mehr Ober- als Unterlaenge und sass dadurch 1,5 px
       zu hoch. Die 1,5 px oben sind ausgemessen (3,98 zu 4,02). */
    padding: 1.5px 0 0;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 50%;
    background: #fff;
    /* Ein Hinweis ist kein Fehler — Infoblau statt Rot. */
    color: var(--dsf-ts-info);
    font-size: .72rem;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(0,0,0,.18);
}
.dsf-ts-preview__infobtn:hover { border-color: var(--dsf-ts-info); }

/* Fehlendes Feld nach Validierung: hinscrollen + dezent aufblinken —
   duenner Rahmen und heller Rotton wie beim Widerrufs-Hinweis, nicht der
   fette Outline-Kasten von frueher. */
.dsf-ts-flash {
    animation: dsfTsFlash 1.1s ease-in-out 2;
    outline: 1px solid transparent;
    outline-offset: 2px;
}

@keyframes dsfTsFlash {
    0%, 100% { outline-color: transparent; background-color: transparent; }
    50% { outline-color: var(--dsf-ts-danger); background-color: #fdf2f2; }
}

@media (prefers-reduced-motion: reduce) {
    .dsf-ts-flash { animation: none; outline-color: var(--dsf-ts-danger); }
}

/* Popover: saubere WEISSE Karte mit rotem Akzent statt schwarzem Kasten */
.dsf-ts-preview__infopop {
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    display: block;
    width: 300px;
    max-width: 74vw;
    background: #fff;
    /* harter Fallback: --dsf-ts-text ist nicht in jedem Theme gesetzt,
       sonst erbt der Text das Weiss der Hinweisleiste und ist unsichtbar */
    color: var(--dsf-ts-ink, #1b1b1d);
    border: 1px solid var(--dsf-ts-line);
    /* Ein Hinweis ist kein Fehler — deshalb der blaue Streifen, wie beim
       (i)-Knopf davor und bei den Hinweiskaesten im Bedienbereich. Rot
       gehoert dem, was schiefgeht. */
    border-left: 3px solid var(--dsf-ts-info);
    padding: .7rem .9rem;
    font-size: .76rem;
    line-height: 1.5;
    /* nowrap der Hinweis-Leiste NICHT erben — sonst laeuft der Text
       als eine Zeile aus der Box (Screenshot-Bug) */
    white-space: normal;
    text-align: left;
    text-transform: none;
    letter-spacing: 0;
    box-shadow: 0 12px 30px rgba(20,20,22,.18);
}

.dsf-ts-preview__infopop[hidden] { display: none; }

/* Spieler-Umschalter unter der Vorschau: FESTES Grid ‹ | Label | › —
   die Pfeile bleiben exakt an ihrer Position, egal wie lang der
   Spielername im Label ist (kein Springen beim Durchschalten) */
/* Die Pfeile stehen LINKS UND RECHTS am Trikot, auf beiden Geraeten. Am
   Desktop sassen sie frueher unter dem Bild in einer Zeile mit dem Label —
   weit weg von dem, was sie blaettern.

   Ihre Hoehe kommt aus positionPreviewArrows(): dort wird die Mitte des
   Trikotfotos gemessen und danach FESTGEHALTEN, solange der Schritt laeuft.
   Damit bleiben sie stehen, auch wenn das naechste Foto anders hoch ist —
   sonst haette man beim Durchklicken einem wandernden Knopf hinterherzielen
   muessen. Das Label behaelt seine eigene Zeile darunter. */
.dsf-ts-preview__player {
    display: grid;
    grid-template-columns: 1fr;
    align-items: center;
    gap: .5rem;
    width: 100%;
    margin: .6rem auto 0;
    font-size: .82rem;
    color: var(--dsf-ts-muted);
}

.dsf-ts-preview__player button {
    position: absolute;
    /* Rueckfall, bis das JS die echte Foto-Mitte kennt (verhindert top:auto) */
    top: 45%;
    transform: translateY(-50%);
    z-index: 2;
    background: rgba(255, 255, 255, .92);
}

.dsf-ts-preview__player [data-ref="pprev"] { left: 1rem; }
.dsf-ts-preview__player [data-ref="pnext"] { right: 1rem; }
.dsf-ts-preview__player [data-ref="plabel"] {
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.dsf-ts-preview__player b { color: var(--dsf-ts-select); }

/* ===================================================================
   Doppelansicht am Schreibtisch: Vorder- und Rueckseite nebeneinander.

   "Aufm Desktop die beiden Trikotansichten nebeneinander stellen. Dann
    kannst du die Durchschalten-Pfeile wieder links und rechts neben die
    Spieler 1/15 stellen."

   Genau das macht .is-duo: die Pfeile verlassen ihre absolute Lage neben
   dem Foto (an welchem der beiden sollten sie auch kleben?) und ruecken
   zurueck in die Spielerzeile.
   =================================================================== */
/* Die Buehne ist auf 360 px begrenzt — richtig fuer EIN Trikot, viel zu
   eng fuer zwei nebeneinander. Nachgemessen blieben davon 158 px je
   Trikot uebrig, obwohl die Vorschau 600 px breit war: "Das ist etwas
   sehr klein." Bei der Doppelansicht bekommt die Buehne deshalb die volle
   Breite. */
.dsf-ts-preview.is-duo .dsf-ts-preview__stage {
    width: 100%;
    max-width: 100%;
}

/* Die Hinweis-Pille "Live-Vorschau — Beispieldarstellung" haengt ABSOLUT
   oben in der Spalte, sie ist kein Kopf im Fluss. Der Inhalt darunter wird
   mittig ausgerichtet — und schob sich im flachen Fenster unter die Pille
   (gemessen 18 px). Mit einer Konstante war das nicht zu erwischen: je
   kleiner das Trikot, desto langsamer verschwand die Ueberdeckung.
   Deshalb bekommt die Spalte oben so viel Innenabstand, wie die Pille
   belegt. Dann kann der Inhalt gar nicht mehr darunter geraten. */
.dsf-ts-preview.is-duo {
    padding-top: 3.2rem;
}

/* Der Aufbau, den er vorgegeben hat:
     Reihe 1  Trikot vorne + hinten   (gross)
     Reihe 2  Short + Stutzen
     Reihe 3  "Spieler 2/18"
   Die Buehne bleibt also eine SPALTE — nur die beiden Trikotseiten bilden
   eine eigene Reihe. Ohne diese Trennung standen alle vier Bilder
   nebeneinander, und jedes war halb so gross wie noetig. */
.dsf-ts-photostage--duo {
    flex-direction: column;
    align-items: center;
    /* "Kannst du mir hier noch etwas mehr Platz zwischen den Trikotansichten
       und den Hosen / Stutzen schaffen? Da ist mir die Subline zu nahe am
       Bild."
       Der Grund: VORNE/HINTEN haengt ABSOLUT unter dem Bild und belegt
       damit keine eigene Hoehe. Der Abstand von 1rem war kleiner als das,
       was die Beschriftung nach unten ausgreift — sie klebte oben am Bild
       und unten an den Kacheln zugleich. Der Abstand muss also die
       Beschriftung MITTRAGEN, nicht nur die beiden Reihen trennen. */
    gap: 2.8rem;
}

.dsf-ts-photostage__seiten {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    justify-content: center;
    /* Enger Abstand mit Absicht: jeder Millimeter Luecke geht direkt von
       der Trikotbreite ab. 1.2rem reichen, damit die beiden Seiten nicht
       ineinanderlaufen. */
    gap: 1.2rem;
    width: 100%;
}

.dsf-ts-photostage--duo .dsf-ts-photostage__frame {
    position: relative;
    /* Die Trikots teilen sich die Breite und duerfen gross werden — sie
       sind der Grund, warum jemand hinschaut. Der 440-px-Deckel der
       Grundregel bleibt: darueber hinaus wuerden kleine Wawi-Fotos nur
       unscharf hochgerechnet. */
    flex: 0 1 48%;
    width: 48%;
    /* Drei Deckel, der kleinste gewinnt:
         48%    — die halbe Buehne, damit beide Seiten nebeneinander passen
         440px  — darueber wuerden kleine Wawi-Fotos nur unscharf skaliert
         Hoehe  — der wichtige. Seine Frage: "Die Vorschau passt sich der
                  Bildschirmgroesse an oder?" Der Breite ja, der HOEHE bis
                  hierher nicht: gemessen mit hochformatigen Fotos (3:4,
                  wie echte Produktbilder) ragten im flachen Fenster ab
                  640 px Hoehe erst die Buehne, ab 560 px auch Hose und
                  Stutzen unten aus der Spalte heraus.
                  Die Formel ist aus genau dieser Messung abgeleitet: die
                  Spalte muss Trikot + Teile + Zaehlung tragen, das sind
                  rund 1,9 × Trikotbreite plus die festen Zeilen darunter.
                  Ab 800 px Fensterhoehe greift die Bremse gar nicht — dort
                  gewinnen weiterhin die 48 %. Darunter greift sie gerade
                  so weit, dass Teile und Zaehlung frei stehen. Beide
                  Stuetzstellen sind im Test festgenagelt. */
    max-width: min(48%, 440px, max(150px, calc(52dvh - 151px)));
    min-width: 0;
}

/* Gilt am Schreibtisch genauso: duoAngleichen() gibt jedem Rahmen das
   Seitenverhaeltnis seines Bildes, das Bild fuellt ihn exakt aus. Nur so
   bleiben die Veredelungs-Overlays (Prozent des Rahmens) auf dem Textil.

   .is-fixiert setzt dieselbe Regel fuer die EINZELansicht — der Torwart
   ohne Rueckseite bekommt die gemerkte Hoehe der Doppelansicht, damit beim
   Blaettern nichts springt. */
.dsf-ts-photostage__frame.is-fixiert img:not(.dsf-ts-photofin),
.dsf-ts-photostage--duo .dsf-ts-photostage__frame img:not(.dsf-ts-photofin) {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Hose und Stutzen darunter: sie zeigen die Farbe, nicht den Aufdruck —
   deshalb deutlich kleiner als die Trikots. */
.dsf-ts-photostage--duo .dsf-ts-photoparts {
    display: flex;
    flex-direction: row;
    justify-content: center;
    gap: 1.2rem;
    width: 100%;
    /* Dieselben drei Deckel wie beim Trikot, nur um den Faktor 62/48
       groesser gerechnet. Wichtig: die Teile MUESSEN mitschrumpfen. Wuerde
       nur das Trikot kleiner und die Teilreihe bliebe stehen, waere unten
       genau so viel abgeschnitten wie vorher — nur mit kleinerem Trikot. */
    max-width: min(62%, 570px, max(194px, calc(67dvh - 195px)));
}

.dsf-ts-photostage--duo .dsf-ts-photoparts figure {
    flex: 0 1 34%;
    max-width: 34%;
}

/* Beschriftung je Seite — ohne sie waere nicht klar, welches Bild welches
   ist, sobald der Umschalter weg ist. */
.dsf-ts-photostage--duo .dsf-ts-photostage__seite {
    white-space: nowrap;
    position: absolute;
    left: 50%;
    /* Auch nach unten weiter weg vom Bild — bei -1.15rem lag die Oberkante
       der Schrift nur 6 px unter der Bildkante. */
    bottom: -1.6rem;
    transform: translateX(-50%);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-preview.is-duo .dsf-ts-photostage {
    margin-bottom: 1.2rem;   /* Platz fuer die Seitenbeschriftung */
}

/* Pfeile zurueck in die Zeile: drei Spalten, Label in der Mitte */
.dsf-ts-preview.is-duo .dsf-ts-preview__player {
    grid-template-columns: auto 1fr auto;
    justify-items: center;
    max-width: 340px;
}

.dsf-ts-preview.is-duo .dsf-ts-preview__player button {
    position: static;
    transform: none;
    top: auto;
    left: auto;
    right: auto;
}
.dsf-ts-preview__player button {
    width: 34px;
    height: 34px;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
    /* Dunkelblau statt Fliesstext-Schwarz: die Pfeile sind Bedienelemente
       und gehoeren damit zur selben Familie wie der Vorschau-Knopf und der
       "mehr"-Chip. Als schwarze Zeichen sahen sie aus wie Satzzeichen. */
    color: var(--dsf-ts-select);
}
.dsf-ts-preview__player button:hover { border-color: var(--dsf-ts-select); color: var(--dsf-ts-select); }

/* Zusammenfassung: Zusatznotiz klein & dezent */
.dsf-ts-sum__note {
    display: inline;
    font-size: .72rem;
    font-weight: 400;
    color: var(--dsf-ts-muted);
    white-space: nowrap;
}

/* Groessen-Chips: Grid mit einheitlicher Spaltenbreite — alle Chips
   gleich gross und buendig ausgerichtet, egal wie lang der Groessenname
   ist ("S" vs. "2XL" vs. "152/158") */
.dsf-ts-gearchips {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
    gap: .5rem;
    padding: .9rem 1.1rem;
}
.dsf-ts-gearchip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .2rem;
    width: 100%;
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: .5rem .2rem;
    min-height: 42px;
    cursor: pointer;
    font-family: inherit;
    font-size: .86rem;
    color: var(--dsf-ts-text);
    transition: border-color .15s ease, background .15s ease;
}
.dsf-ts-gearchip:hover { border-color: var(--dsf-ts-select); }
/* Label hat Vorrang vor allem anderen — der Groessenname muss IMMER
   komplett lesbar sein ("2XL", "31-34"), notfalls schrumpfen +/- */
.dsf-ts-gearchip__label {
    flex: 1 1 auto;
    min-width: 0;
    text-align: center;
    font-weight: 700;
    letter-spacing: .02em;
    white-space: nowrap;
}
.dsf-ts-gearchip__qty { flex: 0 0 auto; font-size: .78rem; }
.dsf-ts-gearchip__plus,
.dsf-ts-gearchip__minus {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 1 22px;
    width: 22px;
    height: 26px;
    font-size: 1rem;
    line-height: 1;
    color: var(--dsf-ts-muted);
}
.dsf-ts-gearchip__minus { visibility: hidden; }
.dsf-ts-gearchip.is-active {
    background: var(--dsf-ts-select);
    border-color: var(--dsf-ts-select);
    color: #fff;
}
.dsf-ts-gearchip.is-active .dsf-ts-gearchip__plus,
.dsf-ts-gearchip.is-active .dsf-ts-gearchip__minus { color: rgba(255,255,255,.85); }
.dsf-ts-gearchip.is-active .dsf-ts-gearchip__minus { visibility: visible; }
.dsf-ts-gearchip.is-active .dsf-ts-gearchip__minus:hover,
.dsf-ts-gearchip.is-active .dsf-ts-gearchip__plus:hover { color: #fff; transform: scale(1.15); }

.dsf-ts-gear__tools { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.dsf-ts-gear__sub { font-size: .88rem; color: var(--dsf-ts-text); }
.dsf-ts-gear__sub strong { color: var(--dsf-ts-red); }

@media (max-width: 767px) {
    .dsf-ts-gearchip { min-height: 46px; } /* Daumen-Ziel */
}

/* =====================================================================
   Zusammenfassung v2 — ruhige Karten, konsistente Schriftgrade
   ===================================================================== */
.dsf-ts-sum2 {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-bottom: 1.25rem;
}
.dsf-ts-sum2__sec {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: 1rem 1.2rem 0.55rem;
}
.dsf-ts-sum2__sec h3 {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 .55rem;
    font-family: var(--dsf-ts-font-head, inherit);
    font-size: .82rem;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}
.dsf-ts-sum2__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 .35rem;
    background: var(--dsf-ts-select);
    color: #fff;
    font-size: .72rem;
    letter-spacing: 0;
}
.dsf-ts-sum2__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .5rem 0;
}
.dsf-ts-sum2__row + .dsf-ts-sum2__row { border-top: 1px solid var(--dsf-ts-line); }
.dsf-ts-sum2__label {
    font-size: .84rem;
    color: var(--dsf-ts-text);
}
.dsf-ts-sum2__label em {
    display: block;
    font-style: normal;
    font-size: .74rem;
    color: var(--dsf-ts-muted);
}
.dsf-ts-sum2__value {
    font-size: .88rem;
    font-weight: 600;
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.dsf-ts-sum2__value small {
    font-weight: 400;
    font-size: .74rem;
    color: var(--dsf-ts-muted);
}
.dsf-ts-sum2__value .dsf-ts-sum2__multi { white-space: normal; font-weight: 500; font-size: .82rem; line-height: 1.7; }
.dsf-ts-sum2__free { color: #2e7d32; font-weight: 700; }
.dsf-ts-sum2__dot {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 1px solid rgba(0,0,0,.18);
    margin-right: .4rem;
    vertical-align: -1px;
}

/* Summen-Block */
.dsf-ts-sum2__totalbox {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: .45rem 1.2rem 0;
}
.dsf-ts-sum2__total {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin: .45rem -1.2rem 0;
    padding: .9rem 1.2rem;
    background: var(--dsf-ts-black);
    color: #fff;
}
.dsf-ts-sum2__total span { font-size: .9rem; font-weight: 600; }
.dsf-ts-sum2__total small {
    display: block;
    font-size: .72rem;
    font-weight: 400;
    color: rgba(255,255,255,.65);
}
.dsf-ts-sum2__total strong {
    font-family: var(--dsf-ts-font-head, inherit);
    font-size: 1.45rem;
    letter-spacing: .02em;
    font-variant-numeric: tabular-nums;
}

/* Kader kompakt als Karten-Grid */
.dsf-ts-sum2__players {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: .45rem;
    padding-bottom: .65rem;
}
.dsf-ts-sum2__player {
    display: flex;
    align-items: center;
    gap: .45rem;
    border: 1px solid var(--dsf-ts-line);
    background: var(--dsf-ts-bg-soft, #f7f7f8);
    padding: .45rem .6rem;
    font-size: .8rem;
    min-width: 0;
}
/* Rueckennummer im Kader-Ueberblick: eine Angabe, kein Alarm. 15 rote
   Nummern nebeneinander lasen sich wie 15 Fehler. */
.dsf-ts-sum2__player b {
    font-variant-numeric: tabular-nums;
    color: var(--dsf-ts-select);
    flex-shrink: 0;
}
.dsf-ts-sum2__player span {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
}
.dsf-ts-sum2__player small { color: var(--dsf-ts-muted); flex-shrink: 0; }
.dsf-ts-sum2__player em {
    font-style: normal;
    font-size: .66rem;
    font-weight: 700;
    background: var(--dsf-ts-select);
    color: #fff;
    padding: .1rem .3rem;
    flex-shrink: 0;
}

@media (max-width: 767px) {
    .dsf-ts-sum2__sec, .dsf-ts-sum2__totalbox { padding-left: .9rem; padding-right: .9rem; }
    .dsf-ts-sum2__total { margin-left: -.9rem; margin-right: -.9rem; padding-left: .9rem; padding-right: .9rem; }
    .dsf-ts-sum2__players { grid-template-columns: 1fr 1fr; }
}

/* Leere Options-Koerper (z. B. inklusive Rueckennummer) nicht anzeigen */
/* Auch im aktiven Zustand: ein LEERER Body (Dienstleistungen haben keine
   Eingabefelder) wuerde sonst Polsterung und Trennlinie beisteuern — der
   Datenschutz-Hinweis darunter sprang beim Setzen des Hakens nach unten.
   Spezifitaet muss die is-on-Regel schlagen, deshalb derselbe Aufbau. */
.dsf-ts-opt__body:empty,
.dsf-ts-opt.is-on > .dsf-ts-opt__body:empty { display: none; }

/* Spieler-Umschalter: Pfeile fix UNTER dem Text (kein Springen) */
.dsf-ts-preview__player [data-ref="plabel"] { min-height: 1.2em; }

/* Gestylter Bestaetigungs-Dialog (statt nativem confirm) */
.dsf-ts-dialog {
    position: fixed;
    inset: 0;
    z-index: 2147483646;
    background: rgba(20, 20, 22, .55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    /* Auch hier kein Doppeltipp-Zoom — sonst zentriert sich der Kasten auf
       einen Ausschnitt, den der Kunde gar nicht sieht. */
    touch-action: manipulation;
}
.dsf-ts-dialog__box {
    background: #fff;
    width: 100%;
    max-width: 420px;
    padding: 1.5rem 1.5rem 1.25rem;
    box-shadow: 0 18px 50px rgba(0, 0, 0, .3);
    border-top: 4px solid var(--dsf-ts-red);
}
.dsf-ts-dialog__title {
    margin: 0 0 .6rem;
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--dsf-ts-text);
    text-transform: none;
}
.dsf-ts-dialog__box p {
    margin: 0 0 1.25rem;
    font-size: .95rem;
    line-height: 1.55;
    color: var(--dsf-ts-text);
}
.dsf-ts-dialog__actions {
    display: flex;
    justify-content: flex-end;
    gap: .6rem;
    flex-wrap: wrap;
}

/* Positions-Toggle: Hinweis auf Auto-Tausch — bewusst klein */
.dsf-ts-finpos__hint {
    flex-basis: 100%;
    font-size: .66rem;
    line-height: 1.35;
    color: var(--dsf-ts-muted);
}

/* Druck-Stil (Schriftart + Druckfarbe) im Veredelungs-Schritt */
.dsf-ts-printstyle {
    border: 1px solid var(--dsf-ts-line);
    border-radius: 0;
    padding: .9rem 1rem .7rem;
    background: #fff;
}

.dsf-ts-printstyle__row {
    display: flex;
    align-items: center;
    gap: .9rem;
    flex-wrap: wrap;
    margin-bottom: .7rem;
}

.dsf-ts-printstyle__label {
    min-width: 110px;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-printstyle__btns {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
}

.dsf-ts-printstyle__font,
.dsf-ts-printstyle__case {
    border: 1px solid var(--dsf-ts-line);
    background: #fff;
    padding: .45rem .9rem;
    font-size: 1rem;
    border-radius: 0;
    cursor: pointer;
}

.dsf-ts-printstyle__case { font-size: .82rem; letter-spacing: .04em; }

.dsf-ts-printstyle__font.is-active,
.dsf-ts-printstyle__case.is-active {
    border-color: var(--dsf-ts-select);
    box-shadow: 0 0 0 2px rgba(38, 50, 74, .18);
}

/* Fest definierte Hausschrift (keine Wahl): Name in der Schrift selbst */
.dsf-ts-printstyle__fixedfont {
    font-size: 1.25rem;
    letter-spacing: .04em;
    text-transform: uppercase;
}

/* Kontrast-Sperre: Farbe sichtbar, aber nicht klickbar */
.dsf-ts-swatch.is-blocked {
    opacity: .3;
    cursor: not-allowed;
    position: relative;
}

.dsf-ts-swatch.is-blocked::after {
    content: '';
    position: absolute;
    inset: 4px;
    background: linear-gradient(135deg, transparent 45%, rgba(200, 16, 46, .85) 45%, rgba(200, 16, 46, .85) 55%, transparent 55%);
    border-radius: 50%;
    pointer-events: none;
}

/* =====================================================================
   Mobile-Haertung (v0.37): kein horizontaler Overflow, ruhige
   Druckvorschau, kompakte Groessen-Chips & Kadertabelle
   ===================================================================== */
@media (max-width: 991px) {
    /* Wo der Inhalt unter der Vorschau weglaeuft, MUSS eine Kante sichtbar
       sein — sonst wirkt der abgeschnittene Text wie eine Ueberlagerung. */
    .dsf-ts-panel__scroll.is-scrolled {
        box-shadow: inset 0 7px 7px -7px rgba(0,0,0,.28);
        border-top: 1px solid var(--dsf-ts-line);
    }

    /* Die Navigationsleiste belegt dauerhaft rund 118 px — auf einem kleinen
       Display ist das ein Sechstel des Bedienbereichs. Solange der Schritt
       offen ist UND es noch etwas zu scrollen gibt, liegt sie deshalb UEBER
       dem Inhalt (der Bedienbereich behaelt die volle Hoehe) und faehrt von
       unten ein, je naeher das Seitenende kommt — das JS setzt den Versatz.
       Deckend, nicht durchsichtig: halbtransparent lag Schrift auf Schrift.
       Klicks nimmt sie erst an, wenn sie fast ganz da ist. */
    /* Der Bedienbereich federt am Rand (siehe bindGummiband). Damit der
       verschobene Inhalt dabei nicht in die Kopfzeile laeuft, wird er hier
       beschnitten. */
    .dsf-ts-panel { position: relative; overflow: hidden; }

    /* Waehrend des Federns darf der Browser die Geste nicht zusaetzlich an
       die Seite darunter weiterreichen. */
    .dsf-ts-panel__scroll { overscroll-behavior-y: contain; }

    .dsf-ts-jnav {
        transition: transform .22s ease-out;
    }

    .dsf-ts-jnav.is-ghost {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        /* Ueber allem, was im Bedienbereich liegt. Ohne den Wert schlugen
           positionierte Kleinteile mit eigenem z-index (die Haken auf den
           Farbkacheln, z-index 1) durch die Leiste durch. */
        z-index: 4;
        box-shadow: 0 -8px 16px rgba(0, 0, 0, .10);
        pointer-events: none;
    }

    .dsf-ts-jnav.is-ghost.is-fassbar { pointer-events: auto; }

    /* Luft am Ende des Inhalts, solange die Leiste darueber liegt — sonst
       verdeckt die eingefahrene Leiste die letzte Zeile. Der Wert hier ist
       nur der Rueckfall; den echten setzt das JS aus der gemessenen
       Leistenhoehe, weil die Infozeile je nach Satzname umbricht. */
    .dsf-ts-panel__scroll.is-navfloat { padding-bottom: 7.6rem; }

    /* Journey darf NIE breiter als der Viewport werden — breite Inhalte
       muessen im eigenen Container umbrechen oder scrollen.
       100vw waere hier falsch: die Einheit rechnet die Breite einer
       klassischen Scrollleiste MIT und macht den Kasten dadurch breiter
       als sein eigener Container. 100% misst den Container selbst. */
    .dsf-ts-jbody { max-width: 100%; }
    .dsf-ts-panel { overflow-x: hidden; }

    /* Grid-/Flex-Kinder duerfen schrumpfen (min-width:auto von Inputs
       ist DER Klassiker fuer Seiten, die breiter als das Display sind) */
    .dsf-ts-squad__row > *, .dsf-ts-squad__head > * { min-width: 0; }
    .dsf-ts-squad input, .dsf-ts-squad select { width: 100%; max-width: 100%; }

    /* Vorschau erst ab dem Veredelungs-Schritt — bei Set-/Farbwahl zeigt
       sie mobil noch nichts Relevantes und frisst nur Bildschirmhoehe.
       Auf der Erfolgsseite (im Warenkorb) ebenfalls weg. */
    .dsf-ts-journey.is-prefinishing .dsf-ts-preview,
    .dsf-ts-journey.is-success .dsf-ts-preview { display: none; }

    /* Info-Popover mobil am (i) oben links ausrichten (nicht zentriert —
       sonst laeuft es links aus dem Bild) */
    .dsf-ts-preview__infopop {
        left: 0;
        transform: none;
        max-width: 82vw;
    }

    /* Druckvorschau mobil = platzsparend: Trikot links, Hose/Stutzen als
       kleine Thumbnails RECHTS daneben gestapelt (unten-rechts), darunter
       das Spieler-Label. Spart Hoehe gegenueber Kacheln-unter-dem-Foto. */
    .dsf-ts-photostage small { display: none; }
    .dsf-ts-photostage {
        flex-direction: row;
        align-items: flex-end;
        justify-content: center;
        gap: .5rem;
    }

    /* Hose/Stutzen: kleine Thumbnails, vertikal gestapelt rechts vom Trikot */
    .dsf-ts-photoparts { display: flex; flex-direction: column; justify-content: flex-end; gap: .4rem; width: auto; margin: 0; }
    .dsf-ts-photoparts figure, .dsf-ts-photoparts figure:only-child { flex: 0 0 auto; width: 44px; }
    .dsf-ts-photoparts img { width: 44px; height: 44px; aspect-ratio: auto; cursor: zoom-in; }
    .dsf-ts-photoparts figcaption { font-size: .48rem; margin-top: .1rem; letter-spacing: .02em; }

    /* WICHTIG: Der Frame hat container-type:inline-size und braucht daher
       eine EXPLIZITE Breite — mit width:auto kollabierte er auf 0 und die
       Vorschau zeigte nur noch frei schwebende Nummern ohne Trikotfoto. */
    .dsf-ts-photostage__frame { width: min(46vw, 200px); margin: 0; }

    /* Mobil dieselbe Anordnung wie am Desktop, nur groessere Knoepfe:
       36 px lagen unter der 44-px-Empfehlung fuer Touch-Ziele und wirkten
       neben dem Foto wie eine Randnotiz. Der Rueckfall-Wert fuer top
       beruecksichtigt hier die kompaktere Buehne. */
    .dsf-ts-preview__player button {
        top: calc(.4rem + min(23vw, 100px));
        width: 44px;
        height: 44px;
        font-size: 1.35rem;
    }
    .dsf-ts-preview__player [data-ref="pprev"] { left: .4rem; }
    .dsf-ts-preview__player [data-ref="pnext"] { right: .4rem; }

    /* ==================================================================
       MOBILE DOPPELANSICHT (sein Entwurf)

       "1. Trikot vorne und hinten nebeneinander in der Vorschau. Rechts
            daneben Hose und Stutzen wie gehabt.
        2. Es entfallen die Richtungspfeile, da wir die Ansicht slidebar
            machen und dies auch durch ein Icon anteasern, welches in der
            Zeile, wo die Spielerset-Zaehlung stattfindet, erscheint.
        3. Den Vorschau-CTA zentral auf die Abschlusslinie des
            Vorschaufensters."

       Die Anordnung ist eine ANDERE als am Schreibtisch: dort stehen Hose
       und Stutzen UNTER den Trikots, hier rechts daneben. Deshalb muessen
       die Desktop-Regeln der Doppelansicht hier ausdruecklich
       zurueckgenommen werden — sie haengen an .dsf-ts-photostage--duo und
       gewinnen sonst ueber die einfachen Mobil-Regeln.
       ================================================================== */
    .dsf-ts-photostage--duo {
        flex-direction: row;
        align-items: flex-end;
        gap: .45rem;
    }

    /* Die beiden Trikotseiten teilen sich die Breite, die die Pfeile
       freigegeben haben. flex-basis 0 statt auto: sonst bestimmt die
       natuerliche Bildbreite die Aufteilung und die schmalere Seite
       bekommt weniger ab. */
    .dsf-ts-photostage__seiten {
        flex: 1 1 0;
        min-width: 0;
        gap: .35rem;
        align-items: flex-end;
        width: auto;
    }

    /* In der Doppelansicht setzt duoAngleichen() Breite UND Hoehe je
       Rahmen so, dass beide Ansichten gleich hoch sind und jeder Rahmen
       das Seitenverhaeltnis SEINES Bildes hat. Das Bild fuellt ihn dann
       exakt aus — Voraussetzung dafuer, dass die Veredelungs-Overlays
       (Prozent des Rahmens) auf dem Textil bleiben. */
    .dsf-ts-photostage--duo .dsf-ts-photostage__frame img:not(.dsf-ts-photofin) {
        width: 100%;
        height: 100%;
        object-fit: contain;
    }

    .dsf-ts-photostage--duo .dsf-ts-photostage__frame {
        flex: 1 1 0;
        width: auto;
        min-width: 0;
        /* Hoehenabhaengiger Deckel, dieselbe Technik wie am Schreibtisch.
           Er ersetzt das overflow:hidden der Vorschau (siehe unten): statt
           zu hohen Inhalt ABZUSCHNEIDEN, wird das Bild so klein, dass er
           gar nicht erst entsteht. Auf den ueblichen Telefonen greift der
           Deckel nicht — bei 390x844 ist die Breite mit 154 px die
           knappere Grenze; er bremst erst bei sehr flachen Fenstern
           (Landscape, halber Bildschirm). */
        max-width: min(100%, calc(31dvh - 50px));
    }

    /* Hose/Stutzen bleiben die kleine Spalte rechts — unveraendert zu
       heute, das war ausdruecklich sein "wie gehabt". */
    .dsf-ts-photostage--duo .dsf-ts-photoparts {
        flex: 0 0 auto;
        flex-direction: column;
        justify-content: flex-end;
        width: auto;
        max-width: none;
        gap: .4rem;
    }
    .dsf-ts-photostage--duo .dsf-ts-photoparts figure {
        flex: 0 0 auto;
        width: 44px;
        max-width: 44px;
    }

    /* Der (i)-Knopf wandert in die rechte Spalte, ueber Hose und Stutzen.
       Dort ist Platz: die Teil-Kacheln sind an der Unterkante der Trikots
       ausgerichtet, oben in ihrer Spalte bleibt Luft. Weil sie ausserdem
       schmaler sind als der Knopf breit ist, steht er buendig ueber ihnen
       und nimmt der Kopfzeile ihre Daseinsberechtigung. */
    .dsf-ts-preview.is-duo .dsf-ts-preview__hint {
        top: .45rem;
        bottom: auto;
        left: auto;
        right: .5rem;
        margin: 0;
    }
    /* Damit der Knopf die Kacheln unter keinen Umstaenden beruehrt — auch
       nicht, wenn eine dritte dazukommt (TW-Set: lange Hose, kurze Hose,
       Stutzen) —, haelt die Spalte seine Hoehe oben frei. Reservieren ist
       hier billiger als nachmessen: die Kacheln sind ohnehin kleiner als
       die Trikots, die Reserve kostet also keine sichtbare Groesse. */
    .dsf-ts-preview.is-duo .dsf-ts-photoparts { margin-top: 1.8rem; }

    /* VORNE/HINTEN mobil kleiner und dichter — auf 390 px waere die
       Desktop-Beschriftung ein Drittel so breit wie das Trikot. */
    .dsf-ts-photostage--duo .dsf-ts-photostage__seite {
        bottom: -.95rem;
        font-size: .5rem;
        letter-spacing: .02em;
    }
    /* Platz fuer die Beschriftung unter den Bildern */
    .dsf-ts-preview.is-duo .dsf-ts-photostage { margin-bottom: .95rem; }

    /* Punkt 2, zweiter Anlauf. Erst waren die Pfeile ganz weg — sein
       Befund: "Des weiteren wird nicht klar, dass man swipen kann. Kannst
       du links und rechts, zum teasernden Text auch dauerhaft Pfeile nach
       links und rechts anzeigen? Die man auch klicken kann?"

       Berechtigt: ein Text, der nur alle sieben Sekunden aufblitzt, ist
       kein verlaesslicher Hinweis, und wer die Geste nicht kennt, hat gar
       keine Bedienmoeglichkeit mehr.

       Wichtig ist, WO sie stehen: nicht mehr ueber der Buehne (dort haben
       sie frueher das Trikot verdeckt), sondern in der Zaehlungs-Zeile
       darunter. Dort kosten sie den Trikots KEINEN Millimeter Breite —
       die Zeile ist ohnehin da. */
    .dsf-ts-preview.is-duo .dsf-ts-preview__player button {
        position: static;
        top: auto;
        left: auto;
        right: auto;
        transform: none;
        width: 34px;
        height: 34px;
        padding: 0;
        margin: 0;
        overflow: visible;
        clip-path: none;
        border: 1px solid var(--dsf-ts-line);
        font-size: 1.1rem;
        line-height: 1;
    }

    /* ... und an ihrer Stelle steht die Zeile so:
         "Swipe links"        Spieler 2/8        "Swipe rechts"
       Die Zaehlung mittig — und damit genau ueber dem Vorschau-Knopf, der
       ebenfalls mittig auf der Unterkante sitzt. Die drei Spalten stehen
       ausdruecklich im Gitter (grid-column), nicht ueber die Reihenfolge
       im HTML: dort stehen zwischen den Hinweisen noch die beiden
       ausgeblendeten Pfeile. */
    /* Fuenf Spalten: Pfeil | Hinweis | Zaehlung | Hinweis | Pfeil.
       Die beiden 1fr-Spalten sind gleich breit und die beiden Pfeile auch
       — dadurch landet die Zaehlung von selbst in der Mitte und damit
       genau ueber dem Vorschau-Knopf. */
    .dsf-ts-preview.is-duo .dsf-ts-preview__player {
        display: grid;
        grid-template-columns: auto 1fr auto 1fr auto;
        align-items: center;
        gap: .3rem;
        width: 100%;
        /* Der 340-px-Deckel stammt aus der Schreibtisch-Regel. Mobil hielt
           er die Pfeile bei 430 px Display 45 px vom Rand weg — "recht weit
           außen" war anders gemeint. */
        max-width: none;
    }
    .dsf-ts-preview.is-duo .dsf-ts-preview__player [data-ref="pprev"] {
        grid-row: 1;
        grid-column: 1;
        justify-self: start;
    }
    .dsf-ts-preview.is-duo .dsf-ts-preview__player [data-ref="pnext"] {
        grid-row: 1;
        grid-column: 5;
        justify-self: end;
    }
    .dsf-ts-preview.is-duo .dsf-ts-preview__player [data-ref="plabel"] {
        /* grid-row und grid-column ausdruecklich bei ALLEN fuenf Elementen:
           die automatische Platzierung arbeitet nur vorwaerts, und die
           Reihenfolge im HTML ist eine andere als die im Bild. Ohne das
           rutschte der linke Hinweis in eine zweite Zeile (gemessen 17 px
           tiefer). */
        grid-row: 1;
        grid-column: 3;
        justify-self: center;
        /* Die Verschiebung auf die Trikotmitte galt fuer EIN Trikot. Bei
           zweien ist die Mitte der Vorschau die richtige Mitte. */
        transform: none;
    }

    .dsf-ts-preview.is-duo .dsf-ts-preview__swipe {
        display: block;
        font-size: .58rem;
        letter-spacing: .04em;
        white-space: nowrap;
        /* "in einem hellen grau" — deutlich zurueckgenommen gegenueber der
           Zaehlung, es ist ein Hinweis, keine Angabe. */
        color: #9aa1ab;
        /* "ab und zu aufblitzen lassen": die meiste Zeit unsichtbar. Wer
           die Geste kennt, soll sie nicht dauernd vorgehalten bekommen. */
        opacity: 0;
        animation: dsf-ts-blitz 7s ease-in-out infinite;
    }
    .dsf-ts-preview.is-duo .dsf-ts-preview__swipe--l {
        grid-row: 1;
        grid-column: 2;
        justify-self: start;
        margin-left: .3rem;
    }
    .dsf-ts-preview.is-duo .dsf-ts-preview__swipe--r {
        grid-row: 1;
        grid-column: 4;
        justify-self: end;
        margin-right: .3rem;
        /* Nacheinander statt gleichzeitig — so liest man beide Richtungen
           als zwei Moeglichkeiten und nicht als eine Beschriftung. */
        animation-delay: 3.5s;
    }

    /* Sichtbar rund 1,2 s von 7 s. Der kleine Versatz macht aus dem
       Einblenden eine angedeutete Bewegung in die jeweilige Richtung. */
    @keyframes dsf-ts-blitz {
        0%, 6%    { opacity: 0; }
        10%, 20%  { opacity: .95; }
        26%, 100% { opacity: 0; }
    }
    @media (prefers-reduced-motion: reduce) {
        .dsf-ts-preview.is-duo .dsf-ts-preview__swipe {
            animation: none;
            opacity: .7;
        }
    }

    /* ---- Punkt 3: der Vorschau-Knopf sitzt auf der Abschlusslinie -----
       "den Vorschau CTA würde ich zentral auf die 'Abschlusslinie' des
        Vorschaufensters packen und ebenso wackeln lassen, wie gehabt. so
        kann man das vorschaufenster elegant, wie gehabt, ein und
        ausklappen lassen."
       Er verlaesst damit die Leiste und haengt mittig auf der Unterkante,
       zur Haelfte drueber, zur Haelfte drunter. */
    .dsf-ts-preview.is-duo .dsf-ts-preview__collapse {
        position: absolute;
        left: 50%;
        bottom: 0;
        transform: translate(-50%, 50%);
        grid-column: auto;
        justify-self: auto;
        z-index: 4;
        white-space: nowrap;
        box-shadow: 0 3px 10px rgba(20, 20, 22, .18);
    }

    /* Die Leiste ist damit leer — sie darf keine Hoehe mehr belegen.
       Sonst bliebe unter der Zaehlung ein 38 px hoher blinder Streifen. */
    .dsf-ts-preview.is-duo .dsf-ts-preview__bar {
        min-height: 0;
        margin: 0;
    }
    .dsf-ts-preview.is-duo .dsf-ts-preview__bar::before { display: none; }

    /* Platz unter der Zaehlung, damit der Knopf sie nicht ueberdeckt: er
       ragt mit seiner halben Hoehe in die Vorschau hinein, und die
       Zaehlung steht genau dort, wo er sitzt — beide mittig.

       z-index an der VORSCHAU, nicht nur am Knopf: Vorschau und Panel sind
       Geschwister. Ohne eigenen Stapelwert malt das Panel als spaeteres
       Element ueber die untere Haelfte des Knopfes — im Screenshot war von
       "VORSCHAU" nur die obere Haelfte zu sehen. Ein z-index am Knopf
       allein hilft nicht: er wirkt nur INNERHALB der Vorschau. */
    .dsf-ts-preview.is-duo {
        /* Die 3.2rem oben sind eine reine DESKTOP-Massnahme (dort haengt
           die Hinweis-Pille absolut ueber dem Inhalt). Mobil sitzt die
           Pille an anderer Stelle — hier waren die 51 px nur verschenkte
           Hoehe, im zugeklappten Zustand wurde der Streifen dadurch 96
           statt 44 px hoch.
           Der (i)-Knopf stand dem im Weg (er haengt mobil oben links und
           lag damit auf dem Trikot). Sein Vorschlag loest genau das:
           "Ich würde das Info zeichen mit zu den Hosen Stutzen packen, so
           dass man wieder platz spart." Der Knopf zieht also nach rechts
           ueber die Teil-Kacheln (Regel weiter unten) — und damit kann die
           Kopfzeile ganz weg. */
        padding-top: .45rem;
        /* "Nach oben bei der aufgeklappten Vorschau immer noch etwas Platz
           vom Vorschau-CTA nach oben." Gemessen 15 px zwischen der
           Spielerzeile und der Knopf-Oberkante. 1.3rem lassen 8 px — genug,
           dass sich Zaehlung und Knopf nicht beruehren, mehr nicht. */
        padding-bottom: 1.3rem;
        z-index: 5;
        /* Der Knopf haengt zur Haelfte UNTER der Vorschau — er darf also
           nicht abgeschnitten werden. Gemessen war genau das der Grund,
           warum im ersten Anlauf nur die obere Haelfte von "VORSCHAU" zu
           sehen war: nicht die Stapelreihenfolge, sondern das
           overflow:hidden, mit dem die Vorschau mobil ihre max-height
           einhaelt.
           Beides zusammen geht nicht, also faellt hier die Klammer weg —
           die Hoehe wird stattdessen ueber den Bilddeckel oben begrenzt.
           Das ist ohnehin das bessere Mittel: es macht den Inhalt kleiner,
           statt ihn abzuschneiden. */
        overflow: visible;
        max-height: none;
    }

    /* Wackeln wie gehabt — aber mit der Zentrierung im Transform, sonst
       springt der Knopf beim ersten Bild der Animation nach rechts. */
    .dsf-ts-preview.is-duo .dsf-ts-preview__collapse.is-teaser {
        animation: dsf-ts-teaser-mitte .7s ease-in-out;
    }
    @keyframes dsf-ts-teaser-mitte {
        0%, 100% { transform: translate(-50%, 50%); }
        15%      { transform: translate(calc(-50% - 3px), 50%); }
        30%      { transform: translate(calc(-50% + 3px), 50%); }
        45%      { transform: translate(calc(-50% - 2px), 50%); }
        60%      { transform: translate(calc(-50% + 2px), 50%); }
        75%      { transform: translate(calc(-50% - 1px), 50%); }
    }

    /* Eingeklappt bleibt der Knopf auf der Kante stehen — genau das macht
       das Auf- und Zuklappen ruhig: er wandert nicht, die Vorschau faehrt
       hinter ihm zusammen.
       overflow:hidden muss dafuer weg (es wuerde die untere Haelfte des
       Knopfes abschneiden); dass nichts durchscheint, uebernehmen die
       display:none-Regeln der Kinder — inklusive der Hinweis-Pille, die
       bisher nur vom overflow verdeckt wurde. */
    /* Zugeklappt darf von der Zaehlungs-Zeile NICHTS uebrig bleiben —
       weder die Zaehlung noch die Wisch-Hinweise noch die Pfeile.
       Sein Bild zeigte alle drei ueber dem eingeklappten Streifen.
       Ursache war Spezifitaet, nicht Logik: die Regel
       ".dsf-ts-preview.is-collapsed .dsf-ts-preview__player{display:none}"
       weiter oben ist genauso stark wie meine Doppelansicht-Regel
       ".dsf-ts-preview.is-duo .dsf-ts-preview__player{display:grid}" —
       und meine steht spaeter, also gewann sie. Drei Klassen schlagen
       zwei. */
    .dsf-ts-preview.is-duo.is-collapsed .dsf-ts-preview__player { display: none; }

    /* "Würdest du die zugeklappte Vorschau nicht noch mehr zuklappen? Ein
       paar Pixel kann man dort noch wegnehmen oder?"
       Nachgemessen: der Streifen war 45 px hoch, davon 31 px blanke Luft
       ueber dem Knopf. Die 44 px stammen aus der Zeit, als der Knopf IM
       Streifen sass und der die Hoehe halten musste. Jetzt haengt er auf
       der Kante — der Streifen muss nur noch seine obere Haelfte tragen.
       26 px lassen ihm 13 px Luft nach oben; darunter wuerde er die
       Schrittleiste beruehren. */
    /* "Zugeklappt ist mir nach oben nicht im gleichen Abstand wie nach
       unten, unten zur Überschrift müsste es etwas mehr sein. Minimal."
       Gemessen: 14 px nach oben zur Schrittleiste, 6 px nach unten zur
       Ueberschrift.

       ERSTER ANLAUF WAR FALSCH: ein Aussenabstand am Streifen. Der schob
       das Panel weg und riss eine 14-px-Luecke auf — genau dort, wo der
       Knopf mit seinem Schlagschatten endet. Sein Befund: "wie eine Kante
       mit Schlagschatten. Das ist nicht schoen." Zu Recht, es sah aus wie
       ein Sims unter dem Knopf.

       Der Abstand gehoert also NACH INNEN: das Panel beginnt buendig am
       Streifen, nur sein Inhalt rueckt nach unten. Dann gibt es keine
       zweite Kante, und die Ueberschrift hat trotzdem Luft. */
    .dsf-ts-preview.is-duo.is-collapsed {
        min-height: 26px;
        overflow: visible;
        /* Zugeklappt braucht weder der (i)-Knopf noch die Zaehlung Platz —
           beide sind ausgeblendet. Ohne diese Zeile bliebe der Streifen um
           beide Innenabstaende zu hoch. */
        padding-top: 0;
        padding-bottom: 0;
    }
    .dsf-ts-preview.is-duo.is-collapsed .dsf-ts-preview__hint { display: none; }

    /* Der Knopf ragt 12 px unter den Streifen. Ohne diese Reserve begaenne
       die Ueberschrift 6 px darunter — zu dicht. 2rem ergeben rund 20 px
       Abstand zur Knopf-Unterkante, gegen 14 px nach oben. */
    .dsf-ts-preview.is-duo.is-collapsed + .dsf-ts-panel .dsf-ts-panel__scroll {
        padding-top: 2rem;
    }
    .dsf-ts-photostage img:not(.dsf-ts-photofin) {
        width: 100%;
        height: auto;
        max-height: none;
        margin: 0 auto;
        box-shadow: 0 8px 16px rgba(20, 20, 22, .12);
    }

    /* Zusammenfassung: lange Werte (z. B. Druck-Stil-Zeile) umbrechen
       statt ueber den Viewport hinauszulaufen */
    .dsf-ts-sum2__row { flex-wrap: wrap; }
    .dsf-ts-sum2__label { min-width: 0; }
    .dsf-ts-sum2__value { white-space: normal; overflow-wrap: anywhere; max-width: 100%; }

    /* Spieler-Umschalter kompakt */
    .dsf-ts-preview__player { font-size: .74rem; margin-top: .5rem; }

    /* Buttons in der Vorschau: klare Abstaende, ordentliche Touch-Ziele */
    .dsf-ts-preview__collapse { font-size: .64rem; padding: .4rem .6rem; }
    .dsf-ts-preview__toggle button { padding: .5rem 1.1rem; font-size: .72rem; }
}

@media (max-width: 575px) {
    /* Groessen-Chips: kompaktere Kacheln, aber weiterhin einheitlich gross
       und mit VOLL lesbarem Groessennamen */
    .dsf-ts-gearchips { padding: .6rem .6rem; gap: .4rem; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); }
    .dsf-ts-gearchip { min-height: 40px; font-size: .8rem; }

    /* Geschlossene Veredelungs-Option = EINE Zeile: Titel + Preis. Die
       Beschreibung erscheint erst beim Antippen. So sieht der Kunde auf
       einen Blick, was es ueberhaupt gibt, statt sich durch Fliesstext zu
       scrollen. Aktive Optionen behalten ihre Erklaerung. */
    .dsf-ts-opt:not(.is-on) .dsf-ts-opt__label small { display: none; }
    .dsf-ts-opt__head { align-items: center; }
    .dsf-ts-opt__label strong { line-height: 1.3; }

    /* Naeher an den Rand: auf schmalen Displays ist jeder Millimeter
       Inhaltsbreite spuerbar. Nicht bis auf 0 — ein schmaler Streifen
       bleibt, sonst klebt der Text am Displayrand. */
    .dsf-ts-panel { padding-left: .5rem; padding-right: .5rem; }
    .dsf-ts-journey__body { padding-left: .35rem; padding-right: .35rem; }
    .dsf-ts-squad { margin-left: -.15rem; margin-right: -.15rem; }
}

/* Druckfarben-Zeilen: Label und Swatches untereinander — so springt beim
   Klicken nichts um, wenn sich der gewaehlte Farbname im Label aendert */
.dsf-ts-printstyle__row--stack {
    flex-direction: column;
    align-items: flex-start;
    gap: .5rem;
}
.dsf-ts-printstyle__row--stack .dsf-ts-printstyle__label { min-width: 0; }

/* (i)-Button + einklappbarer Hinweiskasten (z. B. Kader-Erklaertexte) */
.dsf-ts-squadtitle { display: flex; align-items: center; gap: .5rem; }
.dsf-ts-squadtitle .dsf-ts-panel__title { margin: 0; }

.dsf-ts-infobtn {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    /* wie beim Vorschau-Button: die Glyphe mittig, nicht die Zeilenbox */
    padding: 1.5px 0 0;
    border: 1px solid var(--dsf-ts-line);
    border-radius: 50%;
    background: #fff;
    color: var(--dsf-ts-muted);
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-weight: 700;
    font-size: .8rem;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.dsf-ts-infobtn:hover, .dsf-ts-infobtn[aria-expanded="true"] {
    border-color: var(--dsf-ts-info);
    color: var(--dsf-ts-info);
}

.dsf-ts-infopop {
    border: 1px solid var(--dsf-ts-line);
    /* gehoert zum (i): Infoblau, nicht Rot */
    border-left: 3px solid var(--dsf-ts-info);
    background: var(--dsf-ts-bg-soft, #f7f7f8);
    padding: .7rem .9rem;
    margin: .2rem 0 .9rem;
    font-size: .84rem;
    color: var(--dsf-ts-muted);
    line-height: 1.5;
}
.dsf-ts-infopop p { margin: 0 0 .35rem; }
.dsf-ts-infopop p:last-child { margin-bottom: 0; }

/* Vorschau-Lightbox: Foto + Veredelungs-Overlays bildschirmfuellend.
   Der geklonte Frame behaelt seine %-Overlays — nur die Breite waechst. */
.dsf-ts-photolb {
    position: fixed;
    inset: 0;
    z-index: 2147483645;
    background: rgba(15, 15, 17, .85);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4vmin;
    cursor: zoom-out;
}
.dsf-ts-photolb .dsf-ts-photostage__frame {
    /* Nur der Startwert. Die endgueltige Breite rechnet openPhotoLightbox()
       aus dem Seitenverhaeltnis des Fotos, damit es in BEIDE Richtungen in
       den Bildschirm passt. Ein width:auto ginge nicht: der Rahmen ist ein
       Container (container-type: inline-size), und darin faellt eine
       inhaltsabhaengige Breite auf 0 zusammen — nachgemessen. */
    width: min(92vw, 76vh, 760px) !important;
    margin: 0 !important;
    cursor: default;
}
.dsf-ts-photolb .dsf-ts-photostage__frame img:not(.dsf-ts-photofin) {
    width: 100%;
    height: auto;
    max-height: none;
    cursor: default;
    /* Der Schlagschatten der kleinen Vorschau wirkt gross wie ein
       grauer Rand um das Foto. */
    box-shadow: none;
    /* display:block steht sonst nur in der Regel fuer .dsf-ts-photostage img
       — und dieser Vorfahr fehlt dem geklonten Rahmen. Das Foto war dadurch
       ein Inline-Element und schleppte die Grundlinien-Luecke mit: der
       Rahmen war 4 px hoeher als das Bild. Weil die Veredelungs-Overlays in
       Prozent DES RAHMENS sitzen, sassen sie damit in der grossen Ansicht
       ein Stueck zu hoch. Gemessen und nachgeprueft. */
    display: block;
    background: #fff;
}

/* Die Seitenbeschriftung sitzt sonst NUR in der Doppelansicht absolut
   (.dsf-ts-photostage--duo .dsf-ts-photostage__seite). Im geklonten Rahmen
   fehlt dieser Vorfahr — dadurch rutschte "Vorne"/"Hinten" als gewoehnlicher
   Text unter das Foto an den linken Rand und machte den Rahmen 22 px hoeher
   als das Bild. Beides gemessen. */
.dsf-ts-photolb .dsf-ts-photostage__seite {
    position: absolute;
    left: 50%;
    bottom: -2rem;
    transform: translateX(-50%);
    white-space: nowrap;
    font-family: var(--dsf-ts-sub);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .82);
}
/* Einzelbild-Lightbox (Hose/Stutzen per Klick gross) */
.dsf-ts-photolb__single {
    margin: 0;
    background: #fff;
    padding: 1rem;
    max-width: min(88vw, 460px);
    text-align: center;
}
.dsf-ts-photolb__single img {
    width: 100%;
    height: auto;
    max-height: 74vh;
    object-fit: contain;
}
.dsf-ts-photolb__single figcaption {
    margin-top: .6rem;
    font-family: var(--dsf-ts-sub);
    font-size: .8rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--dsf-ts-muted);
}

.dsf-ts-photolb__close {
    position: absolute;
    top: .9rem;
    right: 1rem;
    width: 44px;
    height: 44px;
    border: 1px solid rgba(255, 255, 255, .4);
    background: rgba(0, 0, 0, .45);
    color: #fff;
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
}
.dsf-ts-photolb__close:hover { background: rgba(0, 0, 0, .7); }

/* Portalseite: JTL-Breadcrumb + Theme-Seitentitel ausblenden (CSS-Fallback
   zur JS-Bereinigung; greift in Browsern mit :has()-Support sofort, ohne
   Flackern vor DOMContentLoaded). */
body:has(#dsf-ts-page) .breadcrumb-container,
body:has(#dsf-ts-page) nav.breadcrumb,
body:has(#dsf-ts-page) ol.breadcrumb,
body:has(#dsf-ts-page) .breadcrumbs,
body:has(#dsf-ts-page) nav[aria-label="breadcrumb"] {
    display: none !important;
}

/* =====================================================================
   Landing-Feinschliff (v0.74): Hero-Foto statt Zeichnung, saubere
   Zeilenumbrueche der Headline, mobiler Sticky-CTA
   ===================================================================== */
/* Keine automatische Silbentrennung in der Hero-Headline ("TRI-KOTSATZ") —
   Umbrueche nur an Wortgrenzen, Zeilen ausbalanciert */
.dsf-ts-hero__title {
    hyphens: manual;
    -webkit-hyphens: manual;
    overflow-wrap: normal;
    word-break: normal;
    text-wrap: balance;
}

/* Echtes Artikelfoto im Hero/den Karten: weisse Produktkarte mit
   Schatten statt der flachen Zeichnung */
.dsf-ts-landingphoto {
    display: block;
    width: min(340px, 80%);
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background: #fff;
    padding: 1.25rem;
    border-radius: 10px;
    box-shadow: 0 24px 40px rgba(0, 0, 0, .35);
}

.dsf-ts-set-jersey .dsf-ts-landingphoto,
[data-dsf-ts-path-media] .dsf-ts-landingphoto {
    width: 100%;
    box-shadow: none;
    padding: .75rem;
}

/* Mobiler Sticky-CTA: Konfigurator-Start immer erreichbar
   ------------------------------------------------------------------
   Als Leiste ueber die ganze Breite am unteren Rand lag er UNTER dem
   Trusted-Shops-Siegel (unten rechts) und dem Cookie-Schalter (unten
   links) — beide bringen eigene, sehr hohe z-index-Werte mit, gegen die
   man nicht anschreiben sollte: sie muessen sichtbar bleiben.

   Deshalb weicht der CTA ihnen aus, statt mit ihnen zu ringen: die Leiste
   sitzt UEBER der Siegelzone. Deren Hoehe steckt in --dsf-ts-cta-lift und
   laesst sich anpassen, falls ein Siegel groesser wird.

   Grundstellung ist die volle Breite ueber der Siegelzone — die passt auf
   jedem Geraet. Mit der kurzen Beschriftung "Jetzt starten" (gemessen
   191 px) passt der CTA aber auch UNTEN ZWISCHEN die Siegel, und genau
   dort gehoert er hin: auf Daumenhoehe, in einer Reihe mit ihnen.

   Ob das geht, haengt an der Geraetebreite. Zwischen Cookie-Schalter
   (12 + 56 px) und Siegel (74 + 8 px) bleiben W - 166 px, davon gehen
   beidseitig 8 px Luft und der Innenabstand der Leiste ab. Erst ab
   380 px Geraetebreite bleibt die Beschriftung dort sicher einzeilig,
   deshalb schaltet die enge Variante genau dort zu. Darunter (360er
   Android-Geraete) bleibt es bei der vollen Breite — lieber eine breite
   Leiste als ein zweizeiliger Button. */
.dsf-ts-mobilecta {
    --dsf-ts-cta-lift: 112px;
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(var(--dsf-ts-cta-lift) + env(safe-area-inset-bottom, 0px));
    z-index: 60;
    padding: .6rem .9rem;
    background: rgba(18, 20, 24, .94);
    backdrop-filter: blur(6px);
    box-shadow: 0 10px 28px rgba(0, 0, 0, .38);
}

.dsf-ts-mobilecta .dsf-ts-btn {
    display: block;
    width: 100%;
    border-radius: 4px;
    text-align: center;
    white-space: nowrap;
}

/* Ab 380 px: runter auf Siegelhoehe, in die Luecke dazwischen. */
@media (min-width: 380px) {
    .dsf-ts-mobilecta {
        left: 76px;
        right: 90px;
        bottom: calc(10px + env(safe-area-inset-bottom, 0px));
        padding: .35rem;
    }
}

/* Offener Konfigurator liegt VOR dem Sticky-CTA */
body.dsf-ts-journey-open .dsf-ts-mobilecta {
    display: none !important;
}

@media (max-width: 767px) {
    .dsf-ts-mobilecta {
        display: block;
    }

    /* Kompakter Hero: Headline kleiner, Foto kleiner — der CTA rueckt
       ueber die Falz */
    .dsf-ts-hero__title {
        font-size: clamp(1.9rem, 8.5vw, 2.5rem);
    }

    .dsf-ts-hero__lead {
        font-size: .95rem;
    }

    .dsf-ts-hero__visual svg,
    .dsf-ts-hero__visual img,
    .dsf-ts-landingphoto {
        width: min(230px, 62%);
    }

    .dsf-ts-hero__pricetag strong {
        font-size: 1.4rem;
    }

    /* Platz fuer den Sticky-CTA UND die Siegelzone darunter — sonst
       verdeckt die Pille am Seitenende den letzten Absatz. */
    .dsf-ts-page {
        padding-bottom: 12rem;
    }
}

/* ---------------------------------------------------------------
   Nachbestellung: Menge geht ueber den Lagerbestand hinaus
   (nur bei Kampagnen mit Ueberverkauf)
   --------------------------------------------------------------- */
/* Nachbestell-Hinweis: sachliche Information, KEINE Warnung. Orange
   signalisiert "Achtung, Problem" — an dieser Stelle schickt das den
   Kunden eher zur Konkurrenz, obwohl nur eine laengere Lieferzeit
   gemeint ist. Deshalb neutral wie ein Infotext. */
/* Nachbestellung beim Hersteller: eine SACHINFORMATION, kein Problem.
   Blau statt Grau — grau liest sich wie Kleingedrucktes und wurde
   ueberlesen, rot waere ein Fehlalarm. Blau ist die uebliche Info-Farbe. */
.dsf-ts-backorder {
    margin: .5rem 0 0;
    padding: .55rem .7rem;
    border-left: 3px solid var(--dsf-ts-info);
    background: var(--dsf-ts-info-soft);
    color: #33546b;
    font-size: .82rem;
    line-height: 1.45;
}
.dsf-ts-backorder strong { color: #12475f; font-weight: 600; }
/* In der Zusammenfassung ist der Hinweis ein gleichrangiger Block zwischen
   Summenkasten und Kader. Den Abstand macht dort allein der Flex-Gap von
   .dsf-ts-sum2 — ein eigener margin-top kaeme obendrauf und der Kasten
   saesse ungleich zwischen seinen Nachbarn. */
.dsf-ts-backorder--sum { margin-top: 0; }
.dsf-ts-backorder ul {
    margin: .35rem 0 0;
    padding-left: 1.1rem;
}
.dsf-ts-backorder li { margin: .1rem 0; }

/* ---------------------------------------------------------------
   Kader-Kompaktmodus (Aktionen ohne Namensdruck): Nummern gebuendelt
   unter ihrer Groesse statt einer Zeile je Spieler
   --------------------------------------------------------------- */
.dsf-ts-squadcompact { margin-top: .4rem; }
.dsf-ts-squadcompact__group {
    border: 1px solid rgba(128, 128, 128, .28);
    margin-bottom: .55rem;
    background: #fff;
}
.dsf-ts-squadcompact__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .6rem;
    padding: .45rem .65rem;
    background: #f3f4f6;
    border-bottom: 1px solid rgba(128, 128, 128, .22);
    font-size: .86rem;
}
.dsf-ts-squadcompact__head span { color: #6b7078; font-size: .8rem; }
.dsf-ts-squadcompact__nums {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    padding: .6rem .65rem;
}
.dsf-ts-squadcompact__cell {
    display: flex;
    align-items: center;
    gap: .25rem;
    margin: 0;
}
.dsf-ts-squadcompact__idx {
    font-size: .72rem;
    color: #9aa0a8;
    min-width: 1.4rem;
    text-align: right;
}
.dsf-ts-squadcompact__cell input {
    width: 3rem;
    padding: .3rem .25rem;
    text-align: center;
    font-size: 16px;
    font-weight: 700;
    border: 1px solid rgba(128, 128, 128, .45);
    background: #fff;
}
.dsf-ts-squadcompact__cell.is-keeper input {
    border-color: #e08a00;
    background: #fff9ef;
}

/* Fehlerhafte bzw. doppelte Nummer im Kompaktmodus deutlich markieren */
.dsf-ts-squadcompact__cell.has-error input,
.dsf-ts-squadcompact__cell.is-dupe input {
    border-color: #c8102e;
    border-width: 2px;
    background: #fdecec;
    color: #8c0b20;
}
.dsf-ts-squad__row.is-dupe,
.dsf-ts-pcard.is-dupe { background: #fdecec; }
.dsf-ts-squadcompact__lead {
    margin: .1rem 0 .8rem;
    font-size: .88rem;
    color: #5a6068;
    line-height: 1.5;
}

/* Torwart-Zusatz in der Groessen-Statuszeile: gehoert dazu, soll aber
   nicht mit der Feldspieler-Zahl konkurrieren */
.dsf-ts-partsizes__plus {
    color: var(--dsf-ts-muted);
    font-weight: 600;
}

/* =====================================================================
   Kleine Telefone: kurze Displays (iPhone SE, aeltere Androiden)

   Gemessen auf 375 x 667: bis der erste bedienbare Teil des Schrittes
   kam, waren 530 der 667 Pixel verbraucht — Kopfzeile (zweizeilig, weil
   sie umbrach), Stepper und Vorschau. Der Kunde sah also 80 % Rahmen und
   20 % Inhalt und musste jede Groesse blind erscrollen.

   Zwei Stellschrauben, beide nur auf KURZEN Displays. Auf einem hohen
   Telefon bleibt alles wie bisher.
   ===================================================================== */

/* 1. Die Kopfzeile bleibt einzeilig. Sie brach unter 576 px um, wodurch
      die beiden Knoepfe (Zuruecksetzen, Schliessen) eine eigene Zeile
      bekamen — rund 60 px fuer zwei Symbole. */
@media (max-width: 575px) {
    .dsf-ts-jh {
        flex-wrap: nowrap;
        /* EIN Abstand fuer alles in der Kopfzeile — siehe .dsf-ts-jh__reset */
        column-gap: .5rem;
        row-gap: 0;
    }
    /* Der Markenname darf schrumpfen, bevor irgendetwas umbricht */
    .dsf-ts-jh__brand {
        font-size: 1rem;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .dsf-ts-jh__sponsorlogo { max-height: 26px; flex: 0 0 auto; }
    .dsf-ts-jh__total { flex: 0 0 auto; text-align: right; }
    .dsf-ts-jh__total strong { font-size: 1.15rem; }
    .dsf-ts-jh__close, .dsf-ts-jh__reset { flex: 0 0 auto; }
    /* Der Schliessen-Knopf stand bis an den Displayrand. Ein Rahmen, der
       die Kante beruehrt, sieht abgeschnitten aus — und auf Geraeten mit
       gerundeten Ecken ist er es teilweise auch. */
    .dsf-ts-jh { padding-right: .85rem; }
}

/* 2. Auf kurzen Displays gibt die Vorschau Platz ab. Sie bleibt sichtbar
      — sie ist der Grund, warum der Konfigurator Spass macht — aber sie
      nimmt nicht mehr die halbe Seite. Wer sie gross sehen will, klappt
      sie ueber "Vorschau" auf oder tippt sie an. */
@media (max-height: 720px) and (max-width: 991px) {
    .dsf-ts-preview {
        max-height: clamp(150px, 30dvh, 230px);
        padding: .45rem .7rem .5rem;
    }
    .dsf-ts-preview__stage svg,
    .dsf-ts-preview__stage img { max-height: 22dvh; }
    /* "Spieler 1/14" und die Vorne/Hinten-Umschaltung ruecken zusammen */
    .dsf-ts-preview__player { margin: .15rem 0 .2rem; font-size: .72rem; }
    .dsf-ts-preview__mode { margin-top: .2rem; }
    .dsf-ts-preview__mode button { padding: .3rem .8rem; font-size: .72rem; }
    /* Der Stepper darf auf kurzen Displays ebenfalls schmaler werden */
    .dsf-ts-stepper__step { padding: .4rem .5rem .38rem; }
}

/* 3. Sehr kurz UND sehr schmal (unter 640 px Hoehe): die Vorschau startet
      eingeklappt. Der Kunde sieht dann sofort, was er einzugeben hat, und
      holt sich das Bild bei Bedarf dazu. */
@media (max-height: 640px) and (max-width: 767px) {
    .dsf-ts-preview { max-height: clamp(120px, 24dvh, 180px); }
    .dsf-ts-preview__stage svg,
    .dsf-ts-preview__stage img { max-height: 17dvh; }
}

/* =====================================================================
   Typografie der Landingpage (v0.99.89)

   Er zeigte "IN DREI SCHRITTEN ZUM FERTI-GEN SATZ", "Trikots-atz",
   "Torhuetertri-kot" und "Verede-lung". Das ist automatische
   Silbentrennung — und zwar mit den falschen Trennregeln: "Trikots-atz"
   trennt keine deutsche Regel. So etwas entsteht, wenn der Browser
   hyphens:auto anwendet, aber die Sprache der Seite nicht als Deutsch
   erkennt; dann trennt er nach englischen Mustern.

   Gesetzt wird das vom Theme, nicht von uns — bisher hatte nur die
   Hero-Ueberschrift eine Ausnahme, deshalb fiel es dort nicht auf.

   Der Weg ist NICHT, die Trennung "richtig" einzustellen: welche Sprache
   der Shop meldet, haben wir nicht in der Hand, und eine falsch getrennte
   Ueberschrift ist schlimmer als eine Zeile, die frueher umbricht.
   Deshalb auf der ganzen Aktionsseite: keine automatische Trennung.

   Gegen Ueberlaufen bleibt das Netz gespannt — ein einzelnes ueberlanges
   Wort (lange Vereinsnamen!) darf die Seite nie in die Breite ziehen.
   ===================================================================== */
#dsf-ts-page,
#dsf-ts-page * {
    /* Erbt nicht zuverlaessig: Themes setzen hyphens gern direkt auf
       h1-h6 und p, und eine Elementregel schlaegt jede Vererbung. */
    -webkit-hyphens: manual;
    hyphens: manual;
}

/* Ueberschriften brechen NUR an Wortgrenzen — und moeglichst
   gleichmaessig verteilt statt mit einem einzelnen Wort in der letzten
   Zeile. text-wrap kennen aeltere Browser nicht; sie ignorieren es. */
#dsf-ts-page h1,
#dsf-ts-page h2,
#dsf-ts-page h3,
#dsf-ts-page h4,
#dsf-ts-page .dsf-ts-hero__title,
#dsf-ts-page .dsf-ts-section__title,
#dsf-ts-page .dsf-ts-hero__kicker,
#dsf-ts-page .dsf-ts-section__kicker {
    overflow-wrap: normal;
    word-break: normal;
    text-wrap: balance;
}

/* Fliesstext: keine Schusterjungen am Absatzende. break-word greift NUR,
   wenn ein Wort sonst ueber den Rand hinauslaufen wuerde — der normale
   Umbruch bleibt am Leerzeichen. */
#dsf-ts-page p,
#dsf-ts-page li,
#dsf-ts-page .dsf-ts-hero__lead,
#dsf-ts-page .dsf-ts-section__sub,
#dsf-ts-page .dsf-ts-steps__item p,
#dsf-ts-page .dsf-ts-faq__a {
    overflow-wrap: break-word;
    word-break: normal;
    text-wrap: pretty;
}

/* Die drei Ablauf-Schritte: unter 210px je Spalte wird der Text zur
   Buchstabensuppe. Auf schmalen Geraeten deshalb lieber untereinander —
   volle Zeilenbreite statt drei Schaechte. */
@media (max-width: 767px) {
    .dsf-ts-steps {
        grid-template-columns: 1fr;
    }

    .dsf-ts-steps__item {
        padding: 1.15rem 1.1rem 1.2rem;
    }
}

/* Am Tablet und am Desktop bleibt es beim bisherigen Raster: auto-fit
   laesst leere Spuren zusammenfallen, drei Schritte stehen deshalb
   nebeneinander und teilen sich die volle Breite. Daran wird nichts
   gedreht — es war nie das Problem. */
