:root {
        --bg: #070a0f;
        --bg-raised: #10151d;
        --glass: rgba(18, 24, 33, .72);
        --line: #232b38;
        --text: #f4f6fa;
        --text-dim: #97a2b4;
        --accent: #ff3b1f;
        --gold: #f4c150;
        --rail-w: 300px;
        --font-display: 'Oswald', 'Arial Narrow', sans-serif;
        --font-body: 'Inter', system-ui, sans-serif;
        color-scheme: dark;
    }

    /* Sichtbarer Fokus fuer die Tastatur (#078): ein Ring in der Akzentfarbe statt des Browser-Standards, der auf
       dunklem Grund kaum zu sehen ist. :where() hat keine Gewichtung — wo ein Baustein einen eigenen Fokus zeichnet,
       gewinnt der. Nur :focus-visible, also nicht beim Klicken mit der Maus. */
    :where(a, button, summary, input, select, textarea, [tabindex]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    /* Light theme — opt-in via <html data-theme="light"> (toggle + anti-flash script, same
       'zenergy-theme' key as the live site). Only the "real surface" variables flip; the
       accent/gold stay branded (gold is deepened so it still reads on white). Elements that
       sit over a photo (hero, bands, transparent nav) keep fixed light colours in BOTH
       themes — see the rules further down — so they never turn dark-on-dark. */
    :root[data-theme="light"] {
        --bg: #eef1f6;
        --bg-raised: #ffffff;
        --glass: rgba(255, 255, 255, .85);
        --line: #d9dee7;
        --text: #12161d;
        --text-dim: #55606f;
        --gold: #8a6410;
        color-scheme: light;
    }
    /* Hardcoded dark overlays that don't come from a variable, re-tuned for light. */
    :root[data-theme="light"] .sl-modal-day,
:root[data-theme="light"] .sl-modal-opt { background: rgba(0, 0, 0, .03); }
    :root[data-theme="light"] .sl-modal-close { background: rgba(0, 0, 0, .06); }
    :root[data-theme="light"] .sl-modal-overlay,
    :root[data-theme="light"] .sl-info-overlay { background: rgba(25, 30, 40, .42); }
    /* Hero scrim, inverted for light mode — same technique as public/css/theme-light.css's own
       .hero::after override: a dark theme needs a DARK wash so light hero text stays legible
       over a busy photo; light mode needs the OPPOSITE (a light wash) so the now-DARK hero
       text (--text is near-black in light mode) stays legible instead. Without this, the dark
       wash's fade-to-bg endpoint clashes with dark text right where it sits. */
    :root[data-theme="light"] .sl-hero .sl-back::after {
        background: linear-gradient(180deg, rgba(255,255,255,.05) 0%, rgba(255,255,255,.3) 60%, rgba(255,255,255,.7) 85%, var(--bg) 100%);
    }
    * { box-sizing: border-box; }
    html, body { height: 100%; }
    body {
        margin: 0; background: var(--bg); color: var(--text);
        font-family: var(--font-body); line-height: 1.55; overflow: hidden;
    }
    /* ============================ MOTORSPORT DECORATIVE BACKDROP ============================
       Pure-CSS texture for the sections that have no photo of their own (about/groups/challenge
       classes/merch/cta) — faint diagonal speed-line streaks and two
       soft glows in the brand colours. Lives on a fixed, z-index:-1 pseudo-element behind
       EVERYTHING, so it costs nothing structurally and never competes with real content: any
       .sl-group section's own opaque photo layer (now correctly clipped by overflow:hidden)
       simply paints over it, and it only shows through in the flat/plain sections. Colours are
       theme variables via color-mix(), so it re-tints automatically in light mode. */
    body::before {
        content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
        background:
            radial-gradient(820px circle at 6% 10%, color-mix(in srgb, var(--accent) 11%, transparent), transparent 60%) no-repeat,
            radial-gradient(760px circle at 100% 62%, color-mix(in srgb, var(--gold) 9%, transparent), transparent 56%) no-repeat,
            repeating-linear-gradient(115deg,
                transparent 0 46px,
                color-mix(in srgb, var(--text) 4%, transparent) 46px 47px,
                transparent 47px 92px
            );
    }
    h1, h2, h3 { font-family: var(--font-display); margin: 0; letter-spacing: -.01em; }
    a { color: inherit; }

    /* ============================ FLOATING EVENT PANEL (hovers, left, vertically centered) ============================ */
    /* Not a full-height rail — a self-contained card that floats over the left gutter,
       vertically centred, over the full-width page scrolling behind it. Hidden until the
       hero photo has been scrolled past (see .is-visible, toggled by the scroll-sync script
       near the bottom of this layout) — it stays out of the way of the hero's own full-bleed
       moment instead of floating over it from the very first frame. */
    .sl-rail {
        position: fixed; left: 24px; top: 50%;
        width: var(--rail-w); max-height: 94vh; z-index: 30;
        background: var(--glass); backdrop-filter: blur(16px);
        border: 1px solid var(--line); border-radius: 18px; overflow: hidden;
        box-shadow: 0 26px 70px rgba(0,0,0,.6);
        display: flex; flex-direction: column;
        opacity: 0; visibility: hidden; pointer-events: none;
        /* "Drift in" entrance: pivoted from its own left edge, rotated + pulled back + slightly
           shrunk, like a car swerving into its lane, then straightens out to dead-centre as it
           settles — matches the panel's own vertical-centring translateY(-50%), which every
           state below keeps. transform-origin so the rotation pivots at the left edge, not the
           centre. The scale is what gives it a pulse: this cubic-bezier overshoots past 1
           before settling back (same curve driving translateX/rotate to 0), so the panel
           visibly grows a little larger than its final size, then eases back down to it. */
        transform: translateY(-50%) translateX(-90px) rotate(-14deg) scale(.8);
        transform-origin: 0% 50%;
        transition: opacity .3s ease, visibility .5s,
                    transform .6s cubic-bezier(.22, 1.4, .36, 1);
    }
    .sl-rail.is-visible {
        opacity: 1; visibility: visible; pointer-events: auto;
        transform: translateY(-50%) translateX(0) rotate(0deg) scale(1);
    }
    /* Maximized "book a trackday" modal — the SAME .sl-rail element/content as the small
       docked panel above, just centred and enlarged instead of a separate list, so there's
       only ever one event list to keep in sync. Works at EVERY viewport (not just mobile,
       where the panel was never permanently docked to begin with) — see the script's
       [data-rail-modal-open] handler, which now always opens this instead of desktop's old
       shortcut of jumping straight to the next event's own detail modal. Higher specificity
       than .sl-rail.is-visible above (both 0,2,0 — but this one is declared after, so it
       wins the cascade) means it fully overrides the docked position/size regardless of
       whether .is-visible is also present. */
    .sl-rail.is-modal-open {
        top: 50%; left: 50%; right: auto; bottom: auto;
        transform: translate(-50%, -50%) scale(1);
        width: min(92vw, 460px); max-width: 92vw; max-height: 85vh; height: auto;
        opacity: 1; visibility: visible; pointer-events: auto; z-index: 40;
    }
    .sl-rail.is-modal-open .sl-rail-close {
        display: flex; align-items: center; justify-content: center;
        width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--line);
        background: rgba(0,0,0,.25); color: var(--text); font-size: 1.1rem; line-height: 1;
        cursor: pointer; flex-shrink: 0;
    }
    .sl-rail.is-modal-open .sl-rail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: .5rem; }
    .sl-rail.is-modal-open .sl-rail-list { display: flex; flex-direction: column; gap: .2rem; overflow-y: auto; padding: .5rem; }
    /* Closing the modal used to hand the panel straight back to its docked state — and the
       docked state, when the rail is not revealed, is "off at the left edge, rotated and
       shrunk". So the fade-out played over THERE while the reader was looking at the middle
       of the screen. This keeps it where it was for the length of the fade: same centred
       place, a touch smaller, gone. Only used when the panel would not be visible afterwards
       anyway — with the docked panel showing, travelling from the middle to its dock is the
       honest motion and stays. */
    .sl-rail.is-modal-closing {
        top: 50%; left: 50%; right: auto; bottom: auto;
        width: min(92vw, 460px); max-width: 92vw; max-height: 85vh; height: auto;
        transform: translate(-50%, -50%) scale(.96);
        opacity: 0; visibility: visible; pointer-events: none; z-index: 40;
        transition: opacity .22s ease, transform .22s ease;
    }
    .sl-rail-backdrop {
        position: fixed; inset: 0; z-index: 39; background: rgba(4,6,10,.66);
        opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .25s ease, visibility .25s;
    }
    .sl-rail-backdrop.is-open { opacity: 1; visibility: visible; pointer-events: auto; }
    .sl-rail-head { padding: .9rem 1rem .8rem; border-bottom: 1px solid var(--line); }
    .sl-rail-close { display: none; } /* shown via .sl-rail.is-modal-open .sl-rail-close above */
    .sl-rail-head img { height: 24px; display: block; margin-bottom: .7rem; }
    .sl-rail-kicker {
        font-family: var(--font-display); color: var(--accent); font-weight: 700;
        letter-spacing: .14em; text-transform: uppercase; font-size: .68rem;
    }
    .sl-rail-title { font-size: 1.05rem; text-transform: uppercase; margin-top: .1rem; }
    /* No internal scroll — the list is compact enough to show every event at once (see the
       rail's docblock). overflow:hidden guarantees no scrollbar ever appears. */
    .sl-rail-list { flex: 1; overflow: hidden; padding: .35rem; }
    .sl-rail-item {
        display: flex; align-items: center; gap: .65rem; padding: .42rem .55rem; border-radius: 9px;
        text-decoration: none; color: var(--text); transition: background .15s, transform .15s;
    }
    .sl-rail-item:hover { background: var(--bg-raised); transform: translateX(2px); }
    .sl-rail-date {
        flex-shrink: 0; width: 40px; text-align: center; font-family: var(--font-display);
        line-height: 1; color: var(--text);
    }
    .sl-rail-date b { font-size: 1.2rem; display: block; font-weight: 700; }
    .sl-rail-date span { font-size: .58rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); }
    .sl-rail-body { min-width: 0; }
    .sl-rail-name {
        font-family: var(--font-display); font-size: .82rem; text-transform: uppercase; line-height: 1.15;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .sl-rail-series { font-size: .66rem; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .sl-rail-badge {
        margin-left: auto; flex-shrink: 0; font-size: .58rem; font-weight: 700; letter-spacing: .1em;
        text-transform: uppercase; color: var(--accent); border: 1px solid var(--accent);
        border-radius: 999px; padding: .12rem .45rem;
    }
    .sl-rail-badge-past { color: var(--text-dim); border-color: var(--text-dim); }
    /* Speedpakke (season pass) rail entries — gold-tinted, distinct from single events. */
    .sl-rail-pass { background: linear-gradient(90deg, rgba(244,193,80,.10), transparent); }
    .sl-rail-pass:hover { background: linear-gradient(90deg, rgba(244,193,80,.18), transparent); }
    .sl-rail-pass .sl-rail-series { color: var(--gold); }
    /* Past events — dimmed only (a "past" badge already labels them), open only the "event
       is over" modal (see JS). */
    .sl-rail-item.is-past { opacity: .48; }
    .sl-rail-empty { padding: 1.5rem 1.25rem; color: var(--text-dim); font-size: .85rem; }

    /* ============================ MAIN PARALLAX SCROLL COLUMN ============================ */
    .sl-scroll {
        position: absolute; inset: 0; overflow-x: hidden; overflow-y: auto;
        scroll-behavior: smooth;
    }
    /* Real, JS-driven depth parallax — NOT the static perspective/translateZ/scale trick this
       used to be. That CSS-only version was measured to produce a background that scrolls at
       the EXACT same on-screen rate as the foreground (translateZ + scale is a fixed, one-time
       projection — it changes how big/distorted the layer LOOKS, not how fast it tracks
       scroll; there is no native mechanism that makes it lag). A tiny rAF-batched scroll
       listener (see the script near the bottom of this layout) sets .sl-back's translateY to
       a FRACTION of its .sl-group's own on-screen travel, so it visibly trails the foreground
       as you scroll. Only ~3 groups exist on the page — this is nowhere near enough work to
       jank. .sl-back is sized taller than its box (see below) so the lag never exposes an
       empty edge at the top/bottom of the section. */
    .sl-group { position: relative; overflow: hidden; }
    .sl-back {
        /* 15% oversize top/bottom — the JS below clamps its translateY to this same 15% of
           the group's own height, so the stronger parallax offset can never expose an empty
           edge at any scroll position. */
        position: absolute; left: 0; right: 0; top: -15%; height: 130%;
        background-size: cover; background-position: center; z-index: -1; will-change: transform;
    }
    .sl-fore { position: relative; z-index: 1; }

    /* Content stays a normal full-width page; on desktop it just keeps clear of the floating
       panel via padding-left (the parallax .sl-back layer stays full-bleed — it's a sibling,
       not affected by this content padding). */
    .sl-wrap { max-width: 1180px; margin: 0 auto; padding: 0 2.5rem; }
    @media (min-width: 901px) {
        .sl-wrap { padding-left: calc(var(--rail-w) + 72px); }
    }

    /* Hero — swapped to the ORIGINAL (live) design's treatment, not a boxed panel: content
       sits bottom-aligned directly over the full-bleed photo, contrast comes from a vertical
       scrim that fades to the page's own --bg at the bottom (same technique as .hero::after
       in layouts/public.blade.php) rather than a glass card. Seamless, theme-aware (fades to
       whichever --bg the current theme has), and doesn't clip/frame the photo at all. */
    .sl-hero { min-height: 100vh; display: flex; align-items: flex-end; }
    .sl-hero .sl-fore { padding-bottom: 4.5rem; }
    .sl-hero .sl-back::after {
        content: ""; position: absolute; inset: 0;
        background: linear-gradient(180deg, rgba(0,0,0,.15) 0%, rgba(0,0,0,.55) 55%, var(--bg) 100%);
    }
    /* Band dividers (Grupper/Challenge) are pure photo strips now — no heading of their own.
       Repeating the section's title as a quote on the photo AND again as the real <h2> right
       below it read as two headings for the same section. Instead, the real kicker/title/
       intro (still rendered in the plain section, see its own docblock) sits in this card,
       pulled up over the band's photo by a negative margin so it visually bridges image and
       content — the heading reads as "in" the photo but still belongs to the text below it. */
    /* Glass plate — same frosted-glass card language as the rest of the design (.sl-rail,
       modals, .sl-feature), all on the same ~14-20px rounded-corner scale, rather than the
       angled motorsport-livery cut used nowhere else in this design. The blurred photo still
       shows through near the top, so the card reads as bridging the image rather than just
       sitting on top of it. The background fades from translucent (glass, top) to fully
       opaque --bg (bottom, ~55% down) so it still blends flush into the plain section below —
       backdrop-filter has nothing left to blur through once the gradient turns opaque. Capped
       at 640px, not full .sl-wrap width — a deliberately-sized plate, not a banner. overflow:
       hidden clips the ::before accent bar to the same rounded corners as the card itself. */
    /* Extra breathing room between the title and the intro paragraph — more than
       .sl-section-intro's default .6rem, which reads cramped at this card's larger heading
       size against a photo backdrop. */

    /* Buttons — soft, layered (distinct from /neu's hard edges). */
    .sl-btn {
        display: inline-block; background: var(--accent); color: #fff; text-decoration: none;
        font-weight: 700; font-size: .9rem; letter-spacing: .02em; padding: .85rem 1.6rem;
        border-radius: 999px; border: none; box-shadow: 0 8px 24px rgba(255,59,31,.28);
    }
    .sl-btn-ghost {
        display: inline-block; background: transparent; color: var(--text);
        text-decoration: none; font-weight: 700; font-size: .9rem; padding: .8rem 1.55rem;
        border-radius: 999px; border: 1px solid var(--text-dim);
    }
    .sl-btn-ghost:hover { border-color: var(--text); }
    /* Eine Nummer kleiner — fuer Knoepfe, die in einer Tabellenzeile, neben einem Feld oder
       als zweite Handlung stehen. Angefordert wurde das an acht Stellen im Projekt und
       definiert war es an keiner: in der Bestellliste des Profils stand darum eine Pille in
       voller Groesse in einer Zeile mit .78rem-Text (Befund vom 26.09.2026). Der Schatten
       faellt mit weg; er ist fuer eine Flaeche gedacht, die den Blick holen soll. */
    .sl-btn--sm { padding: .5rem 1.05rem; font-size: .78rem; box-shadow: none; }
    .sl-btn-ghost.sl-btn--sm { padding: .45rem 1rem; }
    /* "Zuruecksetzen" ist kein Knopf, sondern ein Wort. Die zweite Handlung im Fenster darf die
       erste nicht ueberstrahlen: sie stand als Pille mit Rahmen in derselben Reihe wie "In den
       Warenkorb" und las sich wie eine Alternative dazu. Jetzt kleine Schrift, gedeckte Farbe,
       keine Flaeche, kein Rahmen — die Wirkung bleibt (klickbar, Unterstrich beim Ueberfahren),
       und die Reihe wird schmaler. Bewusst KEINE eigene Klasse fuer die Designs: die Abwesenheit
       von Gestaltung ist hier die Gestaltung, und die soll in jeder Haut gelten. */
    .sl-reset {
        display: inline-block; background: none; border: 0; padding: 0; margin: 0;
        font: inherit; font-size: .8rem; line-height: 1.4; color: var(--text-dim);
        cursor: pointer; text-decoration: none;
    }
    .sl-reset:hover, .sl-reset:focus-visible { color: var(--text); text-decoration: underline; }

    /* ============================ FLOATING TOP NAV ============================ */
    /* Right-aligned so it never collides with the left floating panel; transparent over the
       hero, gains a glass background once .sl-scroll has scrolled (JS toggles .is-stuck).
       Mirrors the live layout's full nav (dropdowns for Challenge and Regeln & Info) so no
       menu point is lost; collapses to a burger menu on mobile (nothing lost there either). */
    .sl-topnav {
        position: fixed; top: 0; left: 0; right: 0; height: 64px; z-index: 40;
        display: flex; align-items: center; justify-content: flex-end; gap: 1.4rem;
        padding: 0 2rem; border-bottom: 1px solid transparent;
        transition: background .25s ease, border-color .25s ease;
    }
    .sl-topnav.is-stuck { background: var(--glass); backdrop-filter: blur(14px); border-bottom-color: var(--line); }
    /* Transparent nav sits over the crisp hero photo → light links + a soft top scrim for
       legibility in both themes; once scrolled (.is-stuck) it gets the themed glass bar and
       themed text. */
    .sl-topnav::before {
        content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
        background: linear-gradient(180deg, rgba(0,0,0,.38), rgba(0,0,0,0)); transition: opacity .25s ease;
    }
    .sl-topnav.is-stuck::before { opacity: 0; }
    .sl-topnav a { text-decoration: none; font-size: .85rem; font-weight: 600; color: rgba(255,255,255,.85); }
    .sl-topnav a:hover { color: #fff; }
    .sl-topnav.is-stuck a { color: var(--text-dim); }
    .sl-topnav.is-stuck a:hover { color: var(--text); }
    .sl-topnav .sl-btn { color: #fff; padding: .55rem 1.25rem; box-shadow: none; white-space: nowrap; }
    .sl-theme-toggle {
        display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px;
        border: 0; background: none; color: rgba(255,255,255,.85); cursor: pointer; padding: 0;
    }
    .sl-theme-toggle:hover { color: #fff; }
    .sl-topnav.is-stuck .sl-theme-toggle { color: var(--text-dim); }
    .sl-topnav.is-stuck .sl-theme-toggle:hover { color: var(--text); }
    .sl-theme-toggle svg { width: 18px; height: 18px; display: block; }
    .theme-icon-light { display: none; }
    :root[data-theme="light"] .theme-icon-dark { display: none; }
    :root[data-theme="light"] .theme-icon-light { display: inline-flex; }

    .sl-topnav-links { display: flex; align-items: center; gap: 1.4rem; }
    .sl-nav-top { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; }
    /* Der Pfeil als Zeichen haengt unter der Mitte: ▾ sitzt in seiner Zeile tief. Ohne eigene
       Zeilenhoehe und leicht angehoben steht er auf der Mitte des Wortes daneben (29.09.2026). */
    .sl-nav-caret { font-size: .6rem; opacity: .7; line-height: 1; display: inline-block; transform: translateY(-1px); }

    /* Hover/focus dropdowns — absolutely positioned, so opening one never reflows the bar.
       Selbst ein Flex-Behaelter: als Block stand sein Verweis auf der Textgrundlinie und damit
       ein paar Pixel neben der Mitte der uebrigen Leiste (gemeldet am 29.09.2026). */
    .sl-nav-group { position: relative; display: flex; align-items: center; }
    .sl-nav-drop {
        position: absolute; top: 100%; left: 0; margin-top: .5rem; min-width: 190px;
        background: var(--glass); backdrop-filter: blur(16px); border: 1px solid var(--line);
        border-radius: 12px; padding: .4rem; display: flex; flex-direction: column;
        opacity: 0; visibility: hidden; transform: translateY(6px);
        transition: opacity .15s ease, transform .15s ease, visibility .15s; z-index: 50;
        box-shadow: 0 18px 40px rgba(0,0,0,.5);
    }
    .sl-nav-group:hover .sl-nav-drop, .sl-nav-group:focus-within .sl-nav-drop {
        opacity: 1; visibility: visible; transform: none;
    }
    /* Das Kontomenue (angemeldet) haengt an der Scheibe ganz rechts in der Leiste — mit links:0
       (Grundregel oben) wuchs es ueber den rechten Bildschirmrand hinaus (gemeldet 05.11.2026:
       „das popup für die sprachauswahl im header muss nach links aufgehen"). Es haengt
       stattdessen an seiner rechten Kante und waechst nach links, wie die Sprachwahl der
       Abgemeldeten es in design-serienleiste schon tut. */
    .sl-nav-group:has(> .sl-nav-account) > .sl-nav-drop { left: auto; right: 0; }
    .sl-nav-drop a { padding: .5rem .7rem; border-radius: 8px; white-space: nowrap; color: var(--text-dim); }
    .sl-nav-drop a:hover { background: var(--bg-raised); color: var(--text); }
    .sl-nav-drop a.sl-nav-lang-active { color: var(--accent); font-weight: 700; }
    
    .sl-nav-langs { display: flex; gap: .15rem; padding: .1rem 0; }
    .sl-nav-drop .sl-nav-langs a {
        padding: .35rem .4rem; display: inline-flex; align-items: center; justify-content: center;
    }
    
    .sl-nav-drop .sl-nav-langs a.sl-nav-lang-active {
        background: none;
        
        filter: drop-shadow(0 0 2px var(--accent))
                drop-shadow(0 0 6px var(--accent))
                drop-shadow(0 0 14px color-mix(in srgb, var(--accent) 85%, transparent))
                drop-shadow(0 0 22px color-mix(in srgb, var(--accent) 55%, transparent));
    }
    
    .sl-nav-drop .sl-nav-langs a.sl-nav-lang-active:hover { background: none; }
    
    .sl-nav-group.is-dismissed .sl-nav-drop {
        opacity: 0; visibility: hidden; transform: translateY(6px);
    }
    
    .sl-nav-drop-sep { height: 1px; background: var(--line); margin: .35rem .4rem; }
    
    .sl-nav-drop .sl-nav-logout { padding: .5rem .7rem; border-radius: 8px; text-align: left; width: 100%; }
    .sl-nav-drop .sl-nav-logout:hover { background: var(--bg-raised); color: var(--text); }


    .sl-nav-logout { background: none; border: 0; padding: 0; font: inherit; color: var(--text-dim); cursor: pointer; }
    .sl-nav-logout:hover { color: var(--text); }

    /* Burger — hidden on desktop, shown on mobile via the media query below. */
    .sl-menu-toggle { display: none; }
    /* Die drei Wege am Telefon. Auf dem Schreibtisch gibt es sie nicht — dort stehen
       dieselben Ziele als Woerter in der Leiste. */
    .sl-mobil-wege { display: none; align-items: center; gap: .35rem; }
    /* „:not(.sl-mobil-konto)": die Kontoscheibe daneben traegt ein Foto und darf keine
       Maske bekommen — sonst waere vom Bild nur seine Silhouette in Schriftfarbe uebrig. */
    /* 44 x 44: das kleinste Ziel, das ein Finger sicher trifft (gemessen am 24.09.2026 lagen
       sie bei 40). Das ZEICHEN bleibt 22 px — es waechst die Flaeche darum herum, nicht das
       Symbol. */
    .sl-mobil-wege a:not(.sl-mobil-konto) {
        display: block; width: 44px; height: 44px; flex: none; border-radius: 10px;
        /* Das Zeichen als Maske: die Farbe kommt von der Leiste und wechselt mit ihr,
           wenn sie beim Scrollen hell wird. Ein Bild koennte das nicht. */
        background-color: currentColor;
        -webkit-mask: var(--m-ico) center / 22px 22px no-repeat;
        mask: var(--m-ico) center / 22px 22px no-repeat;
        transition: background-color .15s ease;
    }
    /* Buchen ist die Handlung, die uebrigen beiden sind Auskunft — darum traegt das erste
       Zeichen die Signalfarbe. Sie steht auf dunklem wie auf hellem Grund. */
    .sl-mobil-wege a:first-child { background-color: var(--accent, #da1f25); }
    .sl-mobil-wege a:active { opacity: .6; }
    .sl-mobil-konto { display: grid; place-items: center; width: 44px; height: 44px; flex: none; }
    .sl-burger { display: none; cursor: pointer; font-size: 1.6rem; line-height: 1; color: rgba(255,255,255,.9); }
    .sl-topnav.is-stuck .sl-burger { color: var(--text); }

    /* ============================ EVENT DETAIL MODAL ============================ */
    /* Same glass/rounded language as the side panel. Deliberately NOT scrollable: content is
       laid out compactly (facts grid + day rows + clamped summary) and the modal is capped at
       the viewport with overflow:hidden, so everything is visible at once, never behind a
       scrollbar. */
    .sl-modal-overlay {
        position: fixed; inset: 0; z-index: 60; display: none;
        align-items: center; justify-content: center; padding: 24px;
        background: rgba(4,6,10,.66); backdrop-filter: blur(6px);
    }
    .sl-modal-overlay.is-open { display: flex; }

    
    body.sl-overlay-open #sl-scroll,
    body.sl-overlay-open #sl-scroll *,
    body.sl-overlay-open #sl-scroll *::before,
    body.sl-overlay-open #sl-scroll *::after { animation-play-state: paused; }
    
    .sl-modal {
        /* Die Breite kommt aus dem Platz, den das Fenster hergibt, nicht aus einer festen
           Zahl. Mit 720px brach in Deutsch die Aktionszeile unten um — "In den Warenkorb"
           + "Zurücksetzen" + Summe passen nicht nebeneinander, wo im Dänischen "Læg i kurv"
           + "Nulstil" + "I alt" passen. Das Fenster wuchs damit über die 92vh-Grenze und die
           Formularspalte bekam eine Bildlaufleiste, obwohl der Inhalt fast passte (gemessen
           bei 1366x700: 647px Inhalt gegen 644px Grenze, dänisch 631px). Ab etwa 880px
           Breite bleibt die Zeile einzeilig und die Höhe darunter. Nach oben bei 1080px
           gedeckelt, damit die Textzeilen lesbar bleiben; die volle Breite auf dem Handy
           steht weiter unten in der Mobile-Regel. */
        width: min(1080px, 94vw); max-height: 92vh; overflow: hidden; position: relative;
        background: var(--glass);
        border: 1px solid var(--line); border-radius: 20px;
        box-shadow: 0 40px 100px rgba(0,0,0,.7); display: flex;
        animation: sl-modal-pop .18s ease;
    }
    @keyframes sl-modal-pop { from { opacity: 0; transform: translateY(12px) scale(.98); } to { opacity: 1; transform: none; } }
    .sl-modal-close {
        position: absolute; top: 12px; right: 14px; z-index: 3;
        width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line);
        background: rgba(0,0,0,.4); color: var(--text); font-size: 1.2rem; line-height: 1;
        display: flex; align-items: center; justify-content: center; cursor: pointer;
    }
    .sl-modal-close:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

    .sl-event-detail { display: none; width: 100%; }
    .sl-event-detail.is-active { display: flex; }

    .sl-modal-media {
        flex: 0 0 240px; background-size: cover; background-position: center;
        position: relative; border-right: 1px solid var(--line);
    }
    .sl-modal-media::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,.05), rgba(0,0,0,.6)); }
    .sl-modal-badge {
        position: absolute; bottom: 14px; left: 14px; z-index: 1;
        font-family: var(--font-display); font-size: .72rem; letter-spacing: .07em; text-transform: uppercase;
        background: var(--accent); color: #fff; padding: .3rem .6rem; border-radius: 6px;
    }
    /* min-height:0 + overflow-y:auto: the modal is capped at 92vh (see .sl-modal). On a short
       screen the content column would otherwise crush its flex children (the rider fields
       collapse to 0) to stay within the cap — let it scroll instead so nothing gets squashed. */
    .sl-modal-main { flex: 1; min-width: 0; min-height: 0; overflow-y: auto; padding: 1.9rem; display: flex; flex-direction: column; gap: .7rem; }
    .sl-modal-eyebrow { font-family: var(--font-display); color: var(--gold); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; font-size: .8rem; }
    .sl-modal-title { font-size: clamp(1.6rem, 3vw, 2.15rem); text-transform: uppercase; line-height: 1; }
    .sl-modal-titlebar { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
    /* Cart link as an icon (fixed header + booking modal titlebar). A circular count badge sits
       on the glyph; hidden entirely until the cart holds something (JS toggles [hidden]). */
    .sl-nav-cart {
        position: relative; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
        width: 40px; height: 40px; color: inherit; text-decoration: none;
    }
    .sl-nav-cart:hover { color: var(--accent); }
    .sl-nav-cart[hidden] { display: none; }
    .sl-nav-cart-count {
        position: absolute; top: -2px; right: -2px; min-width: 17px; height: 17px; padding: 0 4px;
        border-radius: 999px; background: var(--accent); color: #fff; box-sizing: border-box;
        font-size: .66rem; font-weight: 700; line-height: 17px; text-align: center;
    }
    /* In the modal titlebar the icon should sit tight against the top-right, not the nav padding. */

    /* "Fly to cart" confirmation: a small accent puck arcs from the add-to-cart button to
       whichever cart icon is visible, then the icon gives a little bump. JS in home-v3. */
    .sl-fly {
        position: fixed; z-index: 200; width: 20px; height: 20px; margin: -10px 0 0 -10px;
        border-radius: 50%; background: var(--accent); pointer-events: none;
        box-shadow: 0 6px 18px rgba(255, 59, 31, .5);
        transition: transform .7s cubic-bezier(.5, -.2, .3, 1), opacity .7s ease;
    }
    .sl-cart-bump { animation: sl-cart-bump .35s ease; }
    @keyframes sl-cart-bump { 0%, 100% { transform: scale(1); } 45% { transform: scale(1.4); } }

    /* Guest checkout nudge — dashed accent card above the details form. */
    .sl-modal-facts { display: flex; flex-wrap: wrap; gap: .35rem 1.1rem; color: var(--text-dim); font-size: .85rem; }
    .sl-modal-facts span { display: inline-flex; align-items: center; gap: .4rem; }
    .sl-modal-facts svg { flex-shrink: 0; opacity: .7; }
    .sl-modal-discount { align-self: flex-start; font-size: .78rem; font-weight: 600; color: var(--gold); border: 1px solid rgba(244,193,80,.4); border-radius: 999px; padding: .25rem .7rem; }
    .sl-modal-days { display: flex; flex-direction: column; gap: .35rem; margin-top: .1rem; }
    /* Die Zeile ueber der Terminliste eines Saisonpasses. Sie trug ihren Stil inline; als
       Klasse laesst sie sich dort ausblenden, wo die Termine schon auf der Seite stehen
       (siehe die Paketseite im Design "serienleiste"). */
    .sl-pass-includes { margin: 0; color: var(--text-dim); font-size: .85rem; }
    .sl-modal-day { display: flex; align-items: center; gap: .6rem; background: rgba(255,255,255,.04); border: 1px solid var(--line); border-radius: 10px; padding: .5rem .75rem; font-size: .85rem; }
    .sl-modal-day b { font-family: var(--font-display); text-transform: uppercase; min-width: 6rem; }
    .sl-modal-day span { color: var(--text-dim); }
    .sl-modal-day em { margin-left: auto; font-style: normal; color: var(--text); font-weight: 600; white-space: nowrap; }
    /* Der Garagen-Waehler klappt unter seinem Haken auf. Eingerueckt wie die Zeile darueber,
       damit sichtbar bleibt, wozu er gehoert. */
    .sl-garage-hint { margin: 0; font-size: .78rem; color: var(--text-dim); }
    /* flex-wrap: wenn die drei Teile nicht nebeneinander passen, rutscht die Summe in die
       naechste Zeile, statt rechts aus dem Fenster zu laufen. Am Handy in Deutsch passiert
       genau das ("In den Warenkorb" + "Zuruecksetzen" + Gesamt) — die Zahl war abgeschnitten,
       also das Wichtigste am ganzen Fenster. Seit "Zuruecksetzen" ein Wort ist statt einer
       Pille, passt der Knopf mit ihm zusammen in die erste Zeile und nur die Summe rutscht
       (gemessen am Handy, 375px: Reihe 93px hoch, Summe vollstaendig). Am Rechner passt alles
       einzeilig. */
    .sl-modal-actions { display: flex; align-items: center; gap: 1rem; margin-top: auto; padding-top: .5rem; flex-wrap: wrap; }
    /* Sold-out card: replaces the day pickers and the price with the waiting list. */
    .waitlist-box { display: flex; flex-direction: column; gap: .45rem; }
    .waitlist-soldout {
        margin: 0; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
        font-size: .82rem; color: #ff3b30;
    }
    .waitlist-intro { margin: 0; font-size: .85rem; line-height: 1.45; color: var(--text-dim); }

    /* Warum ein Hinzufuegen ABGELEHNT wurde (ausverkauft, vor allem). Anders als die
       Bestaetigung darunter ein Kasten und kein Satz: eine Ablehnung muss man lesen, und sie
       bleibt stehen, bis sie beantwortet ist. */
    .sl-modal-error {
        margin: .6rem 0 0; padding: .7rem .9rem; border-radius: 12px; font-size: .85rem; line-height: 1.45;
        border: 1px solid color-mix(in srgb, #ff3b30 45%, transparent);
        background: color-mix(in srgb, #ff3b30 12%, transparent);
        color: var(--text);
    }

    /* Post-add confirmation: spells out the two next steps (add another rider / close) so it's
       obvious the modal stays open on purpose. Hidden until JS reveals it after the first add. */
    /* Die Bestaetigung nach dem Hinzufuegen — eine Zeile, kein Kasten. Sie steht unter dem
       Knopf, den man gerade gedrueckt hat, und nennt den Namen des Fahrers, der gerade in den
       Warenkorb gewandert ist. */
    .sl-modal-done {
        margin: .6rem 1.25rem 0; font-size: .85rem; font-weight: 600;
        color: #2f9e44;
    }

    /* Was noch fehlt, wird umrandet statt beschrieben — der Rahmen sagt WO, ein Satz darueber
       sagte nur, DASS. Die Tagesliste ist eine Reihe von Kaesten ohne gemeinsamen Rahmen und
       bekommt deshalb hier einen; die Felder des Fahrerblocks bringen ihre eigene Regel mit
       (partials/rider-block). Gesetzt vom Skript aus der Antwort des Servers. */
    .sl-modal-days.is-invalid {
        border: 1px solid var(--accent); border-radius: 12px;
        padding: .5rem; margin-left: -.5rem; margin-right: -.5rem;
    }
    /* Der Rahmen allein wird nicht gefunden. Er steht still da, wo er steht — und wenn das
       fehlende Feld gerade unter dem sichtbaren Bereich liegt, sieht ihn niemand. Deshalb
       blaetzt das Feld beim Abschicken dreimal kurz auf (0,45s je Schlag), bevor es beim
       ruhigen roten Rahmen bleibt.

       Animiert wird die FLAECHE (und ein Ring), nicht die Rahmenfarbe: die Rahmen der
       Fahrerblock-Felder kommen aus partials/rider-block mit `!important`, und `!important`
       steht in der Kaskade ueber Animationen — eine animierte Rahmenfarbe bliebe dort
       unsichtbar.

       Wer Bewegung im System abgeschaltet hat, bekommt kein Blinken; der Rahmen bleibt. */
    @keyframes sl-invalid-flash {
        0%, 100% { background-color: color-mix(in srgb, var(--accent) 30%, transparent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 40%, transparent); }
        50% { background-color: transparent; box-shadow: 0 0 0 0 transparent; }
    }
    .sl-modal .is-invalid { animation: sl-invalid-flash .45s ease-in-out 3; }
    @media (prefers-reduced-motion: reduce) {
        .sl-modal .is-invalid { animation: none; }
    }

    /* --- Add-to-cart form: days + transponder rental become "nehm ich" checkboxes, plus the
         required group/race-class selects; a live total updates as boxes are ticked. --- */
    .sl-modal-day, .sl-modal-opt { cursor: pointer; }
    .sl-modal-day input[type="checkbox"], .sl-modal-opt input[type="checkbox"] {
        width: 17px; height: 17px; flex-shrink: 0; margin: 0; cursor: pointer; accent-color: var(--accent);
    }
    .sl-modal-day:has(input:checked), .sl-modal-opt:has(input:checked) { border-color: var(--accent); }
    .sl-modal-opt {
        display: flex; align-items: center; gap: .65rem; font-size: .85rem; color: var(--text-dim);
        background: rgba(255,255,255,.04); border: 1px solid var(--line); border-radius: 10px; padding: .5rem .75rem;
    }
    .sl-modal-opt em { margin-left: auto; font-style: normal; color: var(--text); font-weight: 600; white-space: nowrap; }
    .sl-modal-bike { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
    .sl-modal-bike input {
        width: 100%; padding: .55rem .6rem; border-radius: 10px; border: 1px solid var(--line);
        background: var(--bg-raised); color: var(--text); font: inherit; font-size: .82rem;
    }
    .sl-modal-selects { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
    .sl-modal-selects select {
        width: 100%; padding: .55rem .6rem; border-radius: 10px; border: 1px solid var(--line);
        background: var(--bg-raised); color: var(--text); font: inherit; font-size: .82rem; cursor: pointer;
    }
    /* --- "Für wen?" rider picker — one compact row (label + select), with inline name fields
         that appear only when "+ Neuer Fahrer" is chosen, so the modal stays short by default. --- */
    /* flex-shrink:0 — the modal form is a height-bounded flex column; without this the flex
       algorithm compresses the rider group (min-height 0 via the box's overflow:hidden) right
       back to nothing the moment the name fields expand, so no height/max-height could win. */
    .sl-modal-rider { display: flex; flex-direction: column; gap: .4rem; flex-shrink: 0; }
    .sl-modal-rider > select {
        width: 100%; padding: .55rem .6rem; border-radius: 10px; border: 1px solid var(--line);
        background: var(--bg-raised); color: var(--text); font: inherit; font-size: .82rem; cursor: pointer;
    }
    /* Animated reveal for "+ Neuer Fahrer": the block's height is animated between 0 and its
       measured content height by JS (inline style) so the modal grows smoothly — done in JS
       rather than a pure-CSS max-height/fr trick, both of which resolved unreliably inside this
       fixed glass modal. overflow:hidden clips the fields while collapsed; opacity fades in. */
    .sl-modal-rider-new { height: 0; flex-shrink: 0; overflow: hidden; opacity: 0; transition: height .28s ease, opacity .22s ease; }
    .sl-modal-rider-new.is-open { opacity: 1; }
    .sl-modal-rider-new-inner {
        display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; padding-top: .35rem;
    }
    @media (prefers-reduced-motion: reduce) {
        .sl-modal-rider-new { transition: none; }
    }
    .sl-modal-rider-new input[type="text"],
    .sl-modal-rider-guest input[type="text"] {
        width: 100%; padding: .55rem .6rem; border-radius: 10px; border: 1px solid var(--line);
        background: var(--bg-raised); color: var(--text); font: inherit; font-size: .82rem;
    }
    .sl-modal-rider-remember {
        grid-column: 1 / -1; display: flex; align-items: center; gap: .5rem;
        font-size: .8rem; color: var(--text-dim); cursor: pointer;
    }
    /* Logged-out rider fields: name inputs shown directly (no account to pick from) + a login
       shortcut that swaps this for the saved-rider select once signed in. */
    .sl-modal-rider-guest { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
    .sl-modal-rider-login { align-self: flex-start; font-size: .78rem; color: var(--accent); text-decoration: none; }
    .sl-modal-rider-login:hover { text-decoration: underline; }
    .sl-modal-days.sl-invalid { outline: 1px solid var(--accent); outline-offset: 3px; border-radius: 12px; }
    .sl-modal-total { margin-left: auto; color: var(--text-dim); font-size: .85rem; white-space: nowrap; }
    .sl-modal-total b { color: var(--text); font-size: 1.05rem; }

    /* --- "Event is over" modal — small, centred, same glass language (see live layout's
         past-event modal). Not a .sl-event-detail, so it isn't toggled by the detail loop. --- */
    .sl-modal-past {
        flex-direction: column; width: min(430px, 94vw); padding: 2.4rem 2rem 2rem;
        text-align: center; align-items: center; gap: 1rem;
    }
    .sl-modal-past h2 { font-family: var(--font-display); text-transform: uppercase; font-size: 1.4rem; }
    .sl-modal-past p { color: var(--text-dim); margin: 0; font-size: .95rem; line-height: 1.5; }

    /* ============================ CHECKOUT (cart-v3) ============================ */
    .sl-checkout { padding: 7rem 0 5rem; }
    
    .sl-panel { background: var(--bg-raised); border: 1px solid var(--line); border-radius: 16px; padding: 1.4rem 1.5rem; }
    .sl-panel + .sl-panel { margin-top: 1.1rem; }
    .sl-panel h3 { font-family: var(--font-display); text-transform: uppercase; font-size: 1rem; letter-spacing: .04em; margin: 0 0 1rem; }
    .sl-field { display: block; margin-bottom: .9rem; }
    .sl-field:last-child { margin-bottom: 0; }
    .sl-field > .lbl { display: block; font-size: .8rem; color: var(--text-dim); margin-bottom: .35rem; }
    .sl-input { width: 100%; padding: .7rem .8rem; border-radius: 10px; border: 1px solid var(--line); background: var(--bg); color: var(--text); font: inherit; }
    /* Datumsfelder (Ansage Sven 09.11.2026: „geburtsdatum linksbündig und das feld ist zu breit“): Safari auf dem iPhone
       zeichnet sie selbst — Wert mittig und eine Mindestbreite, die über die Spalte hinausragt. Eigenes Aussehen aus, Wert links,
       keine Mindestbreite; die Mindesthöhe hält das leere Feld so hoch wie die anderen. */
    input.sl-input[type="date"] { -webkit-appearance: none; appearance: none; display: block; min-width: 0; max-width: 100%; text-align: left;
        min-height: calc(1.35em + 1.4rem + 2px); }
    input.sl-input[type="date"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
    .sl-input:focus { outline: none; border-color: var(--accent); }
    .sl-input.is-error { border-color: var(--accent); }
    .sl-input[readonly] { opacity: .7; }
    .sl-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem; }
    .sl-note { font-size: .85rem; color: var(--text-dim); margin: 1rem 0 0; }
    /* Geschäftsbedingungen über dem Kaufknopf. Das Kästchen bleibt oben ausgerichtet, damit
       es bei zweizeiligem Text neben der ersten Zeile steht und nicht in der Mitte schwebt. */
    .sl-flash-ok { background: color-mix(in srgb, #34c759 14%, transparent); border: 1px solid color-mix(in srgb, #34c759 45%, transparent); color: var(--text); border-radius: 10px; padding: .7rem 1rem; font-size: .9rem; margin-bottom: 1rem; }
    .sl-flash-err { background: color-mix(in srgb, var(--accent) 12%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); color: var(--text); border-radius: 10px; padding: .7rem 1rem; font-size: .9rem; margin-bottom: 1rem; }
    /* Die Gründe unter der Sammelmeldung, direkt angeschlossen (10.10.2026). */
    .sl-flash-err-liste { margin: -.7rem 0 1rem; padding: .2rem 1rem .7rem 2.1rem; font-size: .85rem; color: var(--text); background: color-mix(in srgb, var(--accent) 12%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); border-top: 0; border-radius: 0 0 10px 10px; }

    /* Transponder add-ons — compact chips echoing checkout's options (see PublicController). */

    /* Short description teaser + the "read more" trigger for the second (text) popup. */
    .sl-modal-teaser { color: var(--text-dim); font-size: .9rem; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
    .sl-modal-teaser--full { display: block; overflow: visible; }
    .sl-modal-more {
        align-self: flex-start; background: none; border: 0; padding: 0; cursor: pointer;
        color: var(--accent); font: inherit; font-size: .82rem; font-weight: 700;
        display: inline-flex; align-items: center; gap: .3rem;
    }
    .sl-modal-more:hover { text-decoration: underline; }

    /* ===== Second popup: full, structured description text (stacks above the detail modal) ===== */
    .sl-info-overlay {
        position: fixed; inset: 0; z-index: 70; display: none;
        align-items: center; justify-content: center; padding: 24px;
        background: rgba(4,6,10,.72); backdrop-filter: blur(8px);
    }
    .sl-info-overlay.is-open { display: flex; }
    .sl-info {
        width: min(860px, 94vw); max-height: 90vh; overflow: hidden; position: relative;
        background: var(--glass); backdrop-filter: blur(22px);
        border: 1px solid var(--line); border-radius: 20px; box-shadow: 0 40px 100px rgba(0,0,0,.72);
        padding: 2rem 2.2rem; animation: sl-modal-pop .18s ease;
    }
    .sl-info-eyebrow { font-family: var(--font-display); color: var(--gold); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; font-size: .78rem; }
    .sl-info-title { font-family: var(--font-display); font-size: 1.6rem; text-transform: uppercase; margin: .2rem 0 1rem; }
    .sl-event-info { display: none; }
    .sl-event-info.is-active { display: block; }
    /* Two-column flow on wide screens so long text fits vertically without scrolling. */
    .sl-info-prose { column-gap: 2.4rem; }
    @media (min-width: 720px) { .sl-info-prose { column-count: 2; } }
    .sl-info-prose h3 { font-family: var(--font-display); text-transform: uppercase; font-size: .95rem; color: var(--accent); margin: 1rem 0 .3rem; break-after: avoid; }
    .sl-info-prose h3:first-child, .sl-info-prose > *:first-child { margin-top: 0; }
    .sl-info-prose p { color: var(--text-dim); font-size: .9rem; line-height: 1.55; margin: 0 0 .7rem; }
    .sl-info-prose ul { color: var(--text-dim); font-size: .9rem; line-height: 1.5; margin: 0 0 .7rem; padding-left: 1.1rem; }
    .sl-info-prose li { margin: 0 0 .25rem; }
    .sl-info-prose li p { margin: 0; }
    .sl-info-prose a { color: var(--accent); text-decoration: underline; }
    .sl-info-prose h3:empty { display: none; }

    @media (max-width: 640px) {
        /* Mobile: the booking + info modals become full-screen, self-scrolling sheets. A
           floating, height-capped card is unusable on a phone when the content is taller than
           the viewport — the page scroll is locked behind the modal, so anything past the fold
           is unreachable. Full-bleed + its own scroll makes each modal read and behave like its
           own page (the approach chosen over real per-modal routes). */
        .sl-modal-overlay, .sl-info-overlay { padding: 0; }
        .sl-modal:not(.sl-modal-past) {
            flex-direction: column;
            width: 100vw; max-width: 100vw;
            height: 100vh; height: 100dvh; max-height: 100dvh;
            border: none; border-radius: 0;
        }
        /* The active event pane fills the sheet so its .sl-modal-main is the scroll container. */
        .sl-event-detail.is-active { flex: 1; min-height: 0; }
        /* Media + form live inside .sl-event-detail — stack THEM (media as a top banner),
           otherwise the form gets squeezed into a sliver and the day prices clip. */
        .sl-event-detail { flex-direction: column; }
        .sl-modal-media { flex: 0 0 120px; border-right: none; border-bottom: 1px solid var(--line); }
        .sl-modal-main { padding: 1.15rem 1.2rem 1.3rem; gap: .5rem; overscroll-behavior: contain; }
        .sl-modal-title { font-size: 1.5rem; }
        .sl-modal-teaser { -webkit-line-clamp: 2; }
        .sl-modal-day b { min-width: 4.5rem; }
        .sl-modal-day span { display: none; }
        /* Past-event modal stays a small centered card — short message, nothing to scroll. */
        .sl-modal-past { width: 92vw; max-width: 92vw; }

        /* Info modal: full-screen too, with the whole sheet scrolling (not just the prose). */
        .sl-info {
            width: 100vw; max-width: 100vw;
            height: 100vh; height: 100dvh; max-height: 100dvh;
            border: none; border-radius: 0;
            overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
            padding: 1.3rem;
        }
        .sl-info-prose { column-count: 1; max-height: none; overflow: visible; }
    }

    section { padding: 6rem 0; position: relative; }
    .sl-section-kicker {
        font-family: var(--font-display); color: var(--accent); font-weight: 700;
        letter-spacing: .14em; text-transform: uppercase; font-size: .85rem; margin: 0 0 .5rem;
    }
    .sl-section-title { font-size: clamp(1.8rem, 4vw, 2.6rem); }

    /* Parallax divider band — a full-bleed photo strip between sections for extra depth. */
    /* Content list rows (events / speedpakke / merch inside the main column). */
    /* Media tile — image on top, text below. The only shared shape this layout was missing:
       .sl-card is a horizontal row and .sl-gcard is a flat colour-coded panel, neither of which
       carries a photo. Used by the team list and anything else that leads with an image.
       Token-driven like the rest, so it follows whichever skin is active. */
    .sl-tile-media { aspect-ratio: 16 / 9; background: var(--bg); overflow: hidden; }
    .sl-tile-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
    /* Eine Kachel ohne Bild traegt die Wortmarke auf dunklem Grund — nie eine leere graue
       Flaeche, die wie ein nicht geladenes Bild aussieht. Dasselbe Seitenverhaeltnis, damit
       die Reihe nicht verspringt. */
    .sl-tile-media.is-leer { display: flex; align-items: center; justify-content: center; background: #16181c; }



    /* ============================ GROUP DESCRIPTION CARDS (plain, non-parallax section) ============================
       Real, potentially-long content (group/class descriptions) deliberately lives in a normal
       flowing <section> like this one, never inside a .sl-band/.sl-group parallax container —
       those are viewport-height decorative dividers only, sized for a one-line quote, and long
       real content inside them got clipped/hidden as the page scrolled. Plain sections have no
       such ceiling: they grow with their content like #about already does. */
    /* Fades from the group's own colour (same one as its top border) down into the card's
       normal surface — a tinted echo of that border, not a flat block of colour. */
    .sl-gcard {
        position: relative;
        background: linear-gradient(180deg, color-mix(in srgb, var(--gcolor, var(--accent)) 22%, var(--bg-raised)) 0%, var(--bg-raised) 65%);
        border: 1px solid var(--line); border-top: 3px solid var(--gcolor, var(--accent)); border-radius: 14px; padding: 1.3rem 1.4rem;
    }
    /* Raise the hovered/focused/tapped card's own stacking context above its grid siblings —
       its .sl-gcard-hover panel (below) grows outside the card's own box and must paint over
       neighbouring cards, not behind them. */
    .sl-gcard:hover, .sl-gcard:focus-within, .sl-gcard.is-open { z-index: 5; }
    .sl-gcard h3 { font-family: var(--font-display); text-transform: uppercase; font-size: 1.05rem; margin: 0; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
    .sl-gcard p { color: var(--text-dim); font-size: .89rem; line-height: 1.5; margin: .55rem 0 0; }
    /* Encouraging "is this group me?" note, hidden until the card is hovered (mouse),
       focused (keyboard), or tapped (touch — see the script's click-to-toggle .is-open,
       since touch devices don't have a real :hover). Grows OUT of the card via position:
       absolute rather than inline, so the grid around it never reflows and the pointer stays
       over the tile the whole time. Defaults to opening downward; the script flips in
       .opens-up for cards too close to the top of the viewport, since the grid's column count
       (and therefore which cards are in the "top row") changes with viewport width. */
    .sl-gcard-hover {
        position: absolute; left: 0; right: 0; top: calc(100% + 14px); z-index: 6;
        background: linear-gradient(180deg, color-mix(in srgb, var(--gcolor, var(--accent)) 20%, var(--bg-raised)) 0%, var(--bg-raised) 70%);
        border: 1px solid var(--gcolor, var(--accent)); border-radius: 14px;
        padding: 1.1rem 1.25rem; box-shadow: 0 20px 50px rgba(0,0,0,.4);
        opacity: 0; visibility: hidden; pointer-events: none;
        transform: translateY(-6px);
        transition: opacity .18s ease, transform .18s ease, visibility .18s;
    }
    .sl-gcard.opens-up .sl-gcard-hover { top: auto; bottom: calc(100% + 14px); transform: translateY(6px); }
    .sl-gcard:hover .sl-gcard-hover, .sl-gcard:focus-within .sl-gcard-hover, .sl-gcard.is-open .sl-gcard-hover {
        opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
    }
    /* Tail points UP into the card when the panel sits below it (default), filled with the
       TOP-of-gradient tinted colour (not plain --bg-raised) since that's what the panel's own
       background actually resolves to at its top edge, where this tail sits. */
    .sl-gcard-hover::after {
        content: ""; position: absolute; left: 28px; width: 16px; height: 16px;
        background: color-mix(in srgb, var(--gcolor, var(--accent)) 20%, var(--bg-raised));
        transform: rotate(45deg);
        top: -8px; border-left: 1px solid var(--gcolor, var(--accent)); border-top: 1px solid var(--gcolor, var(--accent)); border-radius: 3px 0 0 0;
    }
    /* Flipped for .opens-up: panel sits ABOVE the card, tail points DOWN from the panel's
       bottom edge instead — which is the gradient's resolved --bg-raised end, so the tail
       fill switches to plain --bg-raised (matching, same reasoning as .sl-kids-callout's). */
    .sl-gcard.opens-up .sl-gcard-hover::after {
        background: var(--bg-raised);
        top: auto; bottom: -8px; border-left: none; border-top: none;
        border-right: 1px solid var(--gcolor, var(--accent)); border-bottom: 1px solid var(--gcolor, var(--accent)); border-radius: 0 0 3px 0;
    }
    .sl-gcard-hover p { margin: 0; color: var(--text); font-size: .88rem; line-height: 1.5; }
    /* Styled as a comment ON the group card right below it (always index 0 — the green one,
       see the view's docblock) rather than a standalone box: tinted the same way .sl-gcard
       tints its own border colour into its background, plus a speech-bubble tail (::after)
       pointing down at it, so "our green group" (kids_body) visibly refers to something. */
    /* Photo runs the callout's full height, flush against the left/top/bottom edges (no
       padding, clipped to the card's own rounded corners by the parent's overflow:hidden),
       then fades out via a mask — rather than sitting in its own padded thumbnail slot — so
       it reads as bleeding into the text instead of a separate image beside it. */
    /* Narrow viewports: the same "bleed, then fade into the text" idea, just rotated 90° —
       image runs the full top width and fades DOWN into the text below, since there's no
       room for a wide photo down the left edge without crushing the line length. */
    @media (max-width: 640px) {
        /* Fixed px fade stops here (not %) — the box's height is driven by the text below,
           which varies, so a percentage-based fade would drift with it. A constant ~190px
           photo zone that's fully transparent by 170px stays correct regardless. */
    }

    /* ============================ CHALLENGE CLASS ACCORDION (v3-scoped, own markup/CSS — this
       layout never shares CSS/classnames with the live layout's .accordion-* by design) ============================ */
    .sl-accordion { border: 1px solid var(--line); border-radius: 14px; overflow: hidden; background: var(--bg-raised); margin-top: 1.25rem; }
    .sl-acc-item + .sl-acc-item { border-top: 1px solid var(--line); }
    .sl-acc-toggle { position: absolute; opacity: 0; pointer-events: none; }
    .sl-acc-label { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .85rem 1.1rem; cursor: pointer; font-family: var(--font-display); text-transform: uppercase; font-size: .9rem; }
    .sl-acc-label:hover { background: rgba(255,59,31,.06); }
    .sl-acc-caret { color: var(--text-dim); transition: transform .15s ease; flex-shrink: 0; }
    .sl-acc-toggle:checked ~ .sl-acc-label .sl-acc-caret { transform: rotate(180deg); }
    .sl-acc-toggle:focus-visible ~ .sl-acc-label { outline: 2px solid var(--accent); outline-offset: -2px; }
    .sl-acc-body { max-height: 0; overflow: hidden; transition: max-height .25s ease; }
    .sl-acc-toggle:checked ~ .sl-acc-body { max-height: 30rem; }
    .sl-acc-body-inner { padding: 0 1.1rem 1rem; color: var(--text-dim); font-size: .85rem; line-height: 1.5; }
    .sl-acc-body-inner ul { margin: 0; padding-left: 1.1rem; }
    .sl-acc-body-inner li { margin-bottom: .3rem; }
    .sl-acc-body-inner p { margin: 0 0 .5rem; }
    .sl-acc-body-inner p:last-child { margin-bottom: 0; }

    /* Normalizes raw editable HTML fragments (h3+p+ul, e.g. trophies_block) to the v3 look. */


    /* ============================ RESPONSIVE: rail re-docks to bottom ============================ */
    @media (max-width: 900px) {
        :root { --rail-w: 0px; }
        body { overflow: auto; }
        .sl-scroll { position: static; inset: auto; height: auto; overflow: visible; padding-bottom: calc(var(--unten-streifen) + 3rem); }
        /* Unterer Rand am Telefon (#855): der feste weiße Streifen ist wieder entfernt (Ansage Sven 09.11.2026). Safari auf
           dem iPhone gibt der Seite einen Bereich, der OBERHALB seiner schwebenden Leiste endet — ein Streifen an dessen
           Unterkante stand darum über den Bedienelementen statt dahinter. Geblieben ist nur der Abstand: das Polster der
           Rollfläche hält das Seitenende frei, damit nichts unter der Leiste verschwindet. */
        :root { --unten-streifen: calc(3.75rem + env(safe-area-inset-bottom, 0px)); }
        /* Depth parallax is desktop-only (see the scroll script's matchMedia guard) — plain
           cover image here, no JS-set transform to fight against. */
        .sl-back { position: absolute; top: 0; left: 0; right: 0; height: 100%; transform: none !important; }
        .sl-hero { min-height: 78vh; }
        /* The always-visible floating panel doesn't work as a permanent fixture on mobile —
           a cramped bottom strip with tiny horizontally-scrolling tiles isn't usable. It's
           hidden here entirely; the maximized modal (.sl-rail.is-modal-open, styled above —
           NOT mobile-specific, works at every viewport) is the only way it's ever shown. */
        /* Safety net: the desktop hero-scroll-reveal script is already gated to desktop only,
           but .sl-rail.is-visible (2 classes) is MORE specific than the plain .sl-rail rule
           above, so it would otherwise win the cascade and force the panel visible here too
           (e.g. a stray leftover class from resizing down from desktop without a reload). This
           explicitly wins back over it on mobile — only .is-modal-open may ever show the rail
           here. */
        .sl-rail.is-visible:not(.is-modal-open) { opacity: 0; visibility: hidden; pointer-events: none; }
        .sl-rail-item { flex-shrink: initial; width: auto; }
        .sl-wrap { padding: 0 1.25rem; }
        section { padding: 3.5rem 0; }
        .sl-topnav { padding: 0 .75rem; justify-content: flex-end; gap: .5rem; }
        .sl-burger { display: inline-flex; order: 4; }
        /* Die drei Zeichen stehen VOR dem Burger und nicht darin. */
        .sl-mobil-wege { display: flex; order: 3; }
        /* Der Stand ist am Telefon zugeklappt: er ist der laengste Kasten der Seite und
           stand vor den Terminen, nach denen hier gesucht wird. Das Ergebnis-Zeichen im
           Kopf holt ihn. Ohne Javascript bleibt er sichtbar — dann ist „zu" ein Zustand,
           aus dem niemand herauskaeme. */
        html.js .sr-stand-block { display: none; }
        html.js body.zeigt-stand .sr-stand-block:not([hidden]) { display: block; }
        /* Und das Zeichen zeigt, dass es gerade an ist. */
        body.zeigt-stand .sl-mobil-wege a[data-sr-stand] { background-color: var(--accent, #da1f25); }
        /* Der breite Knopf faellt weg: das erste der drei Zeichen fuehrt an dieselbe
           Stelle, und die Leiste hat am Telefon keinen Platz fuer beides. */
        .sl-topnav > .sl-btn-book { display: none; }
        /* Links collapse into a full-width panel toggled by the burger checkbox. */
        .sl-topnav-links {
            position: fixed; top: 64px; left: 0; right: 0; display: none;
            flex-direction: column; align-items: stretch; gap: .1rem;
            background: var(--bg-raised); backdrop-filter: blur(12px);
            border-bottom: 1px solid var(--line); padding: 1rem; max-height: 80vh; overflow-y: auto;
        }
        .sl-menu-toggle:checked ~ .sl-topnav-links,
        .sl-menu-toggle:checked ~ .sl-topnav-glas .sl-topnav-links { display: flex; }
        .sl-topnav-links > a, .sl-nav-top { padding: .7rem .4rem; }
        /* Inside the solid mobile panel the links are on a themed surface, not over a photo. */
        .sl-topnav-links a, .sl-topnav-links .sl-nav-top { color: var(--text); }
        /* Dropdowns expand inline inside the mobile panel instead of hovering. */
        /* align-items: stretch (23.10.2026): die Gruppe erbte von der Leiste „center“ — als Spalte stand „Info & Regeln“
           darum mittig, seine Unterpunkte eingerückt daneben, und „Mein Profil“, Fahnen und „Abmelden“ ebenfalls mittig. */
        .sl-nav-group { display: flex; flex-direction: column; align-items: stretch; }
        .sl-nav-drop {
            position: static; opacity: 1; visibility: visible; transform: none;
            background: none; border: none; box-shadow: none; padding: 0 0 .4rem .9rem; margin: 0;
            backdrop-filter: none;
        }
        /* Das Kontomenü hat am Telefon keinen sichtbaren Kopf (der Kreis steht in der Leiste) — seine Punkte sind darum
           Hauptpunkte und stehen bündig mit den anderen. */
        .sl-nav-group:has(> .sl-nav-account) > .sl-nav-drop { padding-left: 0; }
        .sl-topnav .sl-nav-group:has(> .sl-nav-account) > .sl-nav-drop > a,
        .sl-topnav .sl-nav-group:has(> .sl-nav-account) > .sl-nav-drop .sl-nav-logout { padding-left: .4rem; padding-right: .4rem; }
        /* Abgemeldet: die Fahne der aktuellen Sprache stand als eigener Punkt über der Fahnenreihe, in der sie ohnehin
           markiert ist — zweimal dieselbe Fahne. Die Reihe genügt. */
        .sl-nav-sprache > .sl-nav-top { display: none; }
        .sl-nav-sprache > .sl-nav-drop { padding-left: 0; }
        .sl-nav-caret { display: none; }
    }

    /* Die schmalsten Telefone (360 px: Galaxy S26, Z Flip). Logo, Warenkorb, vier
       Scheiben und Burger brauchen dort mit den ueblichen Abstaenden 358 px, da sind aber
       nur 336 — die Leiste ist rechtsbuendig, also schob sie das Logo 14 px links aus
       dem Bild (das „Z" fehlte; gemessen 02.10.2026, auf jeder Seite). Die Abstaende
       schrumpfen, nicht die Scheiben: die bleiben 44 px, das kleinste sichere Ziel. */
    @media (max-width: 380px) {
        .sl-topnav { gap: .25rem; }
        .sl-mobil-wege { gap: 0; }
    }

    @media (prefers-reduced-motion: reduce) {
        .sl-scroll { scroll-behavior: auto; }
        .sl-back { transform: none !important; }
        .sl-rail-item:hover { transform: none; }
    }
