diff --git a/app/components/banner-slider.php b/app/components/banner-slider.php index ad1963a..3fb5bb7 100644 --- a/app/components/banner-slider.php +++ b/app/components/banner-slider.php @@ -9,7 +9,8 @@ declare(strict_types=1); * "tag" (Badge-Text, Default "Anzeige"), "background" (Bild), "cta.internal" * (interner Link ohne target=_blank/rel=sponsored, für eigene Seiten/Anker), * "cta_secondary" (zweiter Button als Outline), "logo_light" (helle Logo-Platte - * für dunkle Firmenlogos). + * für dunkle Firmenlogos), "accent" (CSS-Farbe; überschreibt das Vereins-Rot + * der Buttons für diese Slide, z. B. Sponsor-CI). * Auto-Rotation + Fortschritts-Indikatoren übernimmt assets/js/banner.js * (pausiert bei Hover/Fokus, respektiert prefers-reduced-motion). * Ohne JS: nur der erste Banner ist sichtbar (Graceful Degradation). @@ -35,9 +36,32 @@ $total = count($banners);
= e($banner['title']) ?>
diff --git a/data/banners.json b/data/banners.json index 4f588de..15bf82c 100644 --- a/data/banners.json +++ b/data/banners.json @@ -18,6 +18,7 @@ "text": "Beratung, Software & Implementierung aus einer Hand. Wir entwickeln Intranets, Kundenportale, Apps und Individualsoftware – inklusive Einführung, sodass sie im Alltag tatsächlich ankommt.", "logo": "img/banners/breadcrumb-solutions.svg", "logo_light": true, + "accent": "#6cbbbc", "background": "img/banners/breadcrumb-hero-1600.jpg", "cta": { "label": "Lösungen entdecken", "url": "https://www.breadcrumb-solutions.de/bc/de/loesungen/" }, "cta_secondary": { "label": "Über uns", "url": "https://www.breadcrumb-solutions.de/bc/de/unternehmen/ueber-uns/" } diff --git a/public/assets/css/components.css b/public/assets/css/components.css index e824009..b51278c 100644 --- a/public/assets/css/components.css +++ b/public/assets/css/components.css @@ -907,6 +907,32 @@ box-shadow: var(--shadow-card); } +/* Crossfade-Übergang (nur mit JS): Slides im selben Grid-Feld stapeln, sodass + die Höhe konstant bleibt (kein Sprung) und ein- wie ausgehende Folie sauber + überblenden. Die ausgehende driftet leicht nach unten, die eingehende steigt + auf. Ohne JS greift weiter .ad-banner__slide[hidden] (nur erste Folie). + Reduced-Motion: globaler Kill-Switch in reset.css macht den Wechsel instant. */ +.ad-banner.is-enhanced .ad-banner__track { + display: grid; +} + +.ad-banner.is-enhanced .ad-banner__slide { + grid-area: 1 / 1; + opacity: 0; + transform: translateY(8px); + pointer-events: none; + transition: opacity 0.55s ease, transform 0.55s ease, visibility 0s linear 0.55s; + visibility: hidden; +} + +.ad-banner.is-enhanced .ad-banner__slide.is-active { + opacity: 1; + transform: none; + pointer-events: auto; + visibility: visible; + transition: opacity 0.55s ease, transform 0.55s ease, visibility 0s; +} + /* Optionaler Hintergrund pro Banner (data: "background"). Dunkler Verlauf über dem Bild hält Text & CTA links lesbar. */ .ad-banner__slide--bg { @@ -918,6 +944,30 @@ border-color: transparent; } +/* Pro-Slide-Akzentfarbe (data: "accent") — z. B. Sponsor-CI statt Vereins-Rot. + --banner-accent kommt als Inline-Variable von der Komponente. */ +.ad-banner__slide--accent { + --clr-accent: var(--banner-accent); + --clr-accent-dark: color-mix(in srgb, var(--banner-accent) 82%, #000); +} + +/* Solider Button: dunkler, aus der Akzentfarbe abgeleiteter Text — helle + Akzentfarben (z. B. Teal) hätten mit Weiß zu wenig Kontrast (WCAG 1.4.3). */ +.ad-banner__slide--accent .ad-banner__cta.btn:not(.btn--outline) { + color: color-mix(in srgb, var(--banner-accent) 22%, #000); +} + +.ad-banner__slide--accent .ad-banner__cta.btn--outline { + color: var(--banner-accent); + border-color: var(--banner-accent); +} + +.ad-banner__slide--accent .ad-banner__cta.btn--outline:hover { + background: color-mix(in srgb, var(--banner-accent) 16%, transparent); + border-color: var(--banner-accent); + color: var(--banner-accent); +} + .ad-banner__slide--bg .ad-banner__text { color: var(--clr-text); } @@ -2343,7 +2393,7 @@ /* === membership (Mitglied werden) === */ .membership-signup__inner { - max-width: 820px; + max-width: 720px; margin-inline: auto; } @@ -2359,43 +2409,78 @@ color: var(--clr-text-muted); } -/* Beitragstabelle und Formular mittig, schlanke Spaltenbreite für Lesbarkeit */ -.membership-signup .fee-table { - max-width: 560px; - margin-inline: auto; +/* Eine einzige Karte: Beitragsinfo + Formular zusammen, durch Hairline getrennt. */ +.membership-card { + padding: clamp(1.5rem, 1rem + 2.5vw, 2.5rem); + background: var(--clr-glass-bg); + border: 1px solid var(--clr-glass-border); + border-radius: var(--radius-card); } -.membership-signup .form { - margin-inline: auto; +/* Verschachtelte Bausteine verlieren ihre eigene Karten-Optik (eine Karte, ein Rahmen). */ +.membership-card .fee-table, +.membership-card .form { + max-width: none; + margin: 0; + padding: 0; + background: none; + border: 0; + border-radius: 0; } -.membership-signup .fee-table + .form { - margin-top: 2rem; +.membership-card .fee-table { + padding-bottom: 1.75rem; + margin-bottom: 1.75rem; + border-bottom: 1px solid var(--clr-glass-border); } +/* Turnen-Hinweise: ruhige Liste, Icon links, dezente Hairline als Trenner. */ .membership-notes { - display: grid; - gap: 1.5rem; margin: 0 0 2.5rem; padding: 0; list-style: none; } -@media (min-width: 768px) { - .membership-notes { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } +.membership-notes__item { + display: flex; + gap: 1rem; + padding: 1.25rem 0; + border-bottom: 1px solid var(--clr-glass-border); +} + +.membership-notes__item:first-child { + padding-top: 0; +} + +.membership-notes__item:last-child { + padding-bottom: 0; + border-bottom: 0; +} + +.membership-notes__icon { + flex: none; + margin-top: 0.15rem; + font-size: 1.5rem; + line-height: 1; + color: var(--clr-accent); } .membership-notes__title { font-size: var(--fs-650); line-height: var(--lh-heading); - margin-bottom: 0.4rem; - padding-top: 0.75rem; - border-top: 2px solid var(--clr-accent); + margin-bottom: 0.25rem; } +.membership-notes__body p { + color: var(--clr-text-muted); +} + +/* Download-Block: alles sauber mittig, Texte in lesbarer Breite. */ .membership-download { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.75rem; text-align: center; } @@ -2411,7 +2496,8 @@ .membership-download__hint, .membership-download__contact { - margin-top: 0.75rem; + margin: 0; + max-width: 48ch; font-size: var(--fs-400); color: var(--clr-text-muted); } diff --git a/public/assets/js/banner.js b/public/assets/js/banner.js index 6581133..7b1f9dd 100644 --- a/public/assets/js/banner.js +++ b/public/assets/js/banner.js @@ -42,7 +42,8 @@ function activate(i) { index = (i % slides.length + slides.length) % slides.length; slides.forEach(function (slide, n) { - slide.hidden = n !== index; + // Sichtbarkeit per Klasse → CSS blendet über (siehe .is-enhanced). + slide.classList.toggle('is-active', n === index); }); dots.forEach(function (dot, n) { var on = n === index; @@ -110,6 +111,13 @@ }); } + // Crossfade aktivieren: Slides stapeln (CSS) und Sichtbarkeit per Klasse + // steuern. Vorher gesetzte hidden-Attribute (No-JS-Fallback) entfernen. + root.classList.add('is-enhanced'); + slides.forEach(function (slide) { + slide.hidden = false; + }); + activate(0); syncPaused(); })();