Design rework
parent
9066763ec6
commit
8b906202b7
35
README.md
35
README.md
|
|
@ -1,4 +1,35 @@
|
|||
# PM_Project
|
||||
# PM_Project – vollständige TriHub-Ernährungsseite
|
||||
|
||||
Project for ProjectManagement in IB.4
|
||||
`ernaehrungsberatung.html` im Browser öffnen. Kein Build und keine Installation nötig.
|
||||
|
||||
Die vollständige Seite aus TriHub-Design-Original ist integriert: Header, Desktop-/Mobilnavigation,
|
||||
Hero, Zielgruppenleiste, eigener Vorteilsbereich, drei Pakete, Coaching-Rabatte,
|
||||
zentrierter Detaildialog, vier Ablaufschritte und Footer.
|
||||
|
||||
Animationen: Scroll-Einblendungen mit 720 ms und maximal 240 ms Staffelung, Bild-/Karten-Hover,
|
||||
sanfte Ankerlinks und Dialog-/Backdrop-Einblendung. `prefers-reduced-motion` wird berücksichtigt.
|
||||
Inhalte bleiben ohne JavaScript sichtbar; Menü und Dialog benötigen JavaScript.
|
||||
|
||||
## Dateien und Zuständigkeiten
|
||||
- ernaehrungsberatung.html: vollständige Seitenstruktur und Inhalte.
|
||||
- css/assets.css: Original-CSS der Vorlage mit lokalen Schriftpfaden.
|
||||
- css/base.css: Grundlagen, Header, Buttons, Footer.
|
||||
- css/sections/hero.css: Hero, Zielgruppenleiste, Vorteile, gemeinsame Sektionsüberschriften.
|
||||
- css/sections/angebote.css: Angebote, Rabattbanner und Detaildialog.
|
||||
- css/sections/ablauf.css: Programmablauf.
|
||||
- css/responsive.css (neu): responsive Anpassungen und Dialoganimationen; zuletzt eingebunden.
|
||||
- js/angebote.js: Paketdetails und Rabattauswahl.
|
||||
- js/main.js: Mobilnavigation und Scrollanimationen.
|
||||
- assets/fonts/ (neu): 16 lokale Originalschriftdateien für Sora und DM Sans.
|
||||
- assets/images/: Bilder in den vorhandenen Unterordnern angebote/, hero/ und icons/.
|
||||
|
||||
Bestehende Git- und IDE-Dateien wurden nicht geändert. Es wurde kein Commit oder Push ausgeführt.
|
||||
Keine zusätzlichen index.html-/projekt.html-Kopien: Der Einstieg bleibt ernaehrungsberatung.html.
|
||||
|
||||
## Abgleich
|
||||
HTML-Inhalte und Reihenfolge entsprechen der vollständigen Vorlage. CSS-Regeln wurden auf die
|
||||
Projektdateien verteilt, JavaScript wurde in Navigation/Animationen und Angebotsdialog aufgeteilt.
|
||||
Geprüft: vollständige HTML-Struktur und Texte gegen die Vorlage, lokale Dateiverweise, JavaScript-Syntax, responsive CSS sowie DOM-Interaktionen für alle Pakete, Rabatte, Menü und 22 Animationselemente einschließlich reduzierter Bewegung.
|
||||
Eine visuelle Browserprüfung ist nicht Bestandteil dieser Prüfung.
|
||||
|
||||
Angebote bleiben Konzeptvorschläge ohne Buchung, Datenübermittlung oder erfundene Preise.
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
9478
css/assets.css
9478
css/assets.css
File diff suppressed because one or more lines are too long
232
css/base.css
232
css/base.css
|
|
@ -1,95 +1,179 @@
|
|||
/* =========================================================
|
||||
base.css – gemeinsame Basis für alle Features
|
||||
Änderungen hier nur über eigenen Branch (betrifft alle!)
|
||||
========================================================= */
|
||||
|
||||
/* ---------- Design-Tokens laut tri-hub Design-DNA ---------- */
|
||||
/* Gemeinsame Basis, Header, Buttons und Footer aus TriHub Design Original. */
|
||||
/* 1. Grundlagen und Typografie */
|
||||
:root {
|
||||
/* Hintergrund: tiefes Dunkelblau / Schwarz */
|
||||
--th-bg: #0d0d1a;
|
||||
--th-bg-elevated: #1a1a2e;
|
||||
|
||||
/* Akzent: Teal / Emerald Green – CTAs, Icons, Highlights */
|
||||
--th-accent: #10b981;
|
||||
|
||||
/* Text: Weiß / Hellgrau */
|
||||
--th-text: #ffffff;
|
||||
--th-text-soft: #f8fafc;
|
||||
--th-text-muted: #94a3b8;
|
||||
|
||||
/* Typografie: Serif Display + Sans-Serif Body */
|
||||
--th-font-display: "Playfair Display", Georgia, serif;
|
||||
--th-font-body: "Inter", system-ui, sans-serif;
|
||||
|
||||
/* Lesbarkeit Zielgruppe 50+ (Definition of Done) */
|
||||
--th-font-size-body: 1.125rem; /* 18px */
|
||||
--th-line-height: 1.65;
|
||||
|
||||
/* Abstände / Radien für alle Sektionen */
|
||||
--th-section-space: 5rem;
|
||||
--th-radius: 1.4rem;
|
||||
--page: var(--background);
|
||||
--text: #fff;
|
||||
--muted: rgb(255 255 255 / 70%);
|
||||
--quiet: rgb(255 255 255 / 56%);
|
||||
--line: rgb(255 255 255 / 10%);
|
||||
--panel: linear-gradient(#ffffff14, #ffffff08);
|
||||
--ease: cubic-bezier(.22, 1, .36, 1);
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
/* ---------- Grundlayout ---------- */
|
||||
* { box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; scroll-padding-top: 120px; }
|
||||
body {
|
||||
background: var(--th-bg);
|
||||
color: var(--th-text-soft);
|
||||
font-family: var(--th-font-body);
|
||||
font-size: var(--th-font-size-body);
|
||||
line-height: var(--th-line-height);
|
||||
margin: 0;
|
||||
background: var(--background);
|
||||
color: var(--text);
|
||||
font-family: var(--font-sans), sans-serif;
|
||||
font-size: 1.0625rem;
|
||||
line-height: 1.7;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
main { overflow: clip; }
|
||||
h1, h2, h3, p, figure { margin: 0; }
|
||||
h1, h2, h3 {
|
||||
font-family: var(--th-font-display);
|
||||
color: var(--th-text);
|
||||
letter-spacing: -0.01em;
|
||||
font-family: var(--font-display), sans-serif;
|
||||
font-weight: 700;
|
||||
letter-spacing: -.04em;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
main > section {
|
||||
padding-block: var(--th-section-space);
|
||||
h1, h2 { line-height: 1.12; }
|
||||
h3 { line-height: 1.35; }
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button, select { font: inherit; }
|
||||
button { cursor: pointer; border: 0; }
|
||||
button, a, select { -webkit-tap-highlight-color: transparent; }
|
||||
a, button, select { touch-action: manipulation; }
|
||||
:where(button, a, select):focus-visible {
|
||||
outline: 2px solid var(--accent-strong);
|
||||
outline-offset: 5px;
|
||||
}
|
||||
img { display: block; max-width: 100%; object-fit: cover; }
|
||||
button:disabled { cursor: default; }
|
||||
[hidden] { display: none !important; }
|
||||
.shell { width: min(1280px, calc(100% - 128px)); margin-inline: auto; }
|
||||
|
||||
/* Anker nicht unter dem Header verstecken */
|
||||
section[id] {
|
||||
scroll-margin-top: 5rem;
|
||||
}
|
||||
|
||||
/* ---------- Header ---------- */
|
||||
/* 2. Kopfbereich – Website-Logo ganz links, wie auf der Referenzseite */
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 40;
|
||||
background: rgb(13 13 26 / 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid rgb(255 255 255 / 0.08);
|
||||
z-index: 20;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: linear-gradient(
|
||||
color-mix(in oklab, var(--background) 95%, transparent),
|
||||
color-mix(in oklab, var(--background) 80%, transparent)
|
||||
);
|
||||
backdrop-filter: blur(18px);
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
.site-header .container {
|
||||
.header-inner {
|
||||
width: calc(100% - 64px);
|
||||
min-height: 98px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-block: 1rem;
|
||||
gap: 24px;
|
||||
padding-block: 16px;
|
||||
}
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.brand-mark {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 74px;
|
||||
height: 66px;
|
||||
padding: 8px 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgb(255 255 255 / 12%);
|
||||
border-radius: 1.1rem;
|
||||
background: #fff;
|
||||
box-shadow: 0 14px 34px rgb(0 0 0 / 22%);
|
||||
}
|
||||
.brand-logo img { width: 48px; height: 48px; object-fit: contain; }
|
||||
.brand-copy { display: grid; gap: 3px; }
|
||||
.brand-name {
|
||||
color: var(--quiet);
|
||||
font-size: .75rem;
|
||||
letter-spacing: .28em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.brand-sub { color: var(--muted); font-size: .875rem; line-height: 1.5; }
|
||||
.header-inner nav { display: flex; align-items: center; gap: 5px; }
|
||||
.header-inner nav a {
|
||||
padding: 9px 14px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
color: var(--muted);
|
||||
font-size: .875rem;
|
||||
white-space: nowrap;
|
||||
transition: color .2s, background .2s, border-color .2s;
|
||||
}
|
||||
.header-inner nav a:hover,
|
||||
.header-inner nav a[aria-current] {
|
||||
border-color: var(--line);
|
||||
background: rgb(255 255 255 / 5%);
|
||||
color: #fff;
|
||||
}
|
||||
.menu-toggle { display: none; }
|
||||
.skip {
|
||||
position: fixed;
|
||||
left: 16px;
|
||||
top: -100px;
|
||||
z-index: 100;
|
||||
padding: 12px 20px;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: var(--ink-strong);
|
||||
}
|
||||
.skip:focus { top: 12px; }
|
||||
|
||||
.site-logo {
|
||||
font-family: var(--th-font-display);
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--th-text);
|
||||
/* 3. Buttons – weiße Primär-CTAs, zurückhaltende Konturen */
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 50px;
|
||||
padding: 14px 24px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: var(--ink-strong);
|
||||
font-size: .9375rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.45;
|
||||
text-align: center;
|
||||
transition: background .25s, border-color .25s, transform .25s var(--ease);
|
||||
}
|
||||
.button:hover { background: #e9edf0; transform: translateY(-2px); }
|
||||
.button.small { min-height: 42px; padding: 10px 20px; font-size: .875rem; }
|
||||
.button.outline, .header-cta {
|
||||
border-color: rgb(255 255 255 / 16%);
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
.button.outline:hover, .header-cta:hover {
|
||||
border-color: rgb(255 255 255 / 28%);
|
||||
background: rgb(255 255 255 / 7%);
|
||||
}
|
||||
.text-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 44px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid rgb(255 255 255 / 28%);
|
||||
background: transparent;
|
||||
color: rgb(255 255 255 / 86%);
|
||||
font-size: .9375rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
transition: color .2s, border-color .2s;
|
||||
}
|
||||
.text-link:hover { color: #fff; border-color: #fff; }
|
||||
|
||||
/* ---------- Barrierefreiheit ---------- */
|
||||
a:focus-visible,
|
||||
button:focus-visible {
|
||||
outline: 3px solid var(--th-accent);
|
||||
outline-offset: 4px;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html { scroll-behavior: auto; }
|
||||
*, *::before, *::after {
|
||||
transition-duration: 0.01ms !important;
|
||||
animation-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
/* Footer */
|
||||
footer { border-top: 1px solid var(--line); background: var(--sidebar); }
|
||||
.footer-main { display: flex; align-items: center; gap: 24px; padding-block: 32px; }
|
||||
.footer-main p { color: var(--muted); font-size: .9375rem; }
|
||||
.footer-main > a:last-child { margin-left: auto; color: var(--muted); font-size: .875rem; }
|
||||
.footer-main > a:last-child:hover { color: #fff; }
|
||||
.footer-note { display: flex; justify-content: space-between; gap: 24px; padding-block: 20px; border-top: 1px solid var(--line); color: var(--quiet); font-size: .75rem; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,142 +1,8 @@
|
|||
/* =========================================================
|
||||
US01-03: Ablauf sehen
|
||||
Branch: feature_US01-03
|
||||
Nur Selektoren unter #ablauf verwenden.
|
||||
Farben/Schriften über var(--th-...) aus base.css.
|
||||
Vorlage: Prototyp (Programmablauf)
|
||||
========================================================= */
|
||||
|
||||
#ablauf {
|
||||
--abl-mint: #56d9b1;
|
||||
--abl-line: rgb(255 255 255 / 0.11);
|
||||
}
|
||||
|
||||
/* ---------- Überschrift ---------- */
|
||||
#ablauf .ablauf-heading {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 3.5rem;
|
||||
margin-bottom: 2.75rem;
|
||||
}
|
||||
|
||||
#ablauf .ablauf-eyebrow {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--abl-mint);
|
||||
}
|
||||
|
||||
#ablauf h2 {
|
||||
margin: 0.9rem 0 0;
|
||||
font-size: clamp(2.2rem, 3.4vw, 2.8rem);
|
||||
font-weight: 400;
|
||||
line-height: 1.12;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
#ablauf .ablauf-heading > p {
|
||||
max-width: 24rem;
|
||||
margin: 0;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Schritte ---------- */
|
||||
#ablauf .steps {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 2rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#ablauf .step-number {
|
||||
display: block;
|
||||
margin-bottom: 1.4rem;
|
||||
padding: 0.5rem 0 1.1rem;
|
||||
border-bottom: 1px solid var(--abl-line);
|
||||
font-family: var(--th-font-display);
|
||||
font-size: 2rem;
|
||||
line-height: 1;
|
||||
color: var(--abl-mint);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* grüner Fortschrittsstrich unter der Nummer zeigt die Reihenfolge */
|
||||
#ablauf .step-number::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -1px;
|
||||
width: 2.5rem;
|
||||
height: 2px;
|
||||
background: var(--th-accent);
|
||||
}
|
||||
|
||||
#ablauf .step h3 {
|
||||
margin: 0 0 0.75rem;
|
||||
font-family: var(--th-font-body);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
#ablauf .step p {
|
||||
margin: 0;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Abschluss ---------- */
|
||||
#ablauf .process-end {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1.5rem;
|
||||
margin-top: 2.75rem;
|
||||
padding-top: 1.9rem;
|
||||
border-top: 1px solid var(--abl-line);
|
||||
}
|
||||
|
||||
#ablauf .process-end p {
|
||||
margin: 0;
|
||||
font-family: var(--th-font-display);
|
||||
font-size: 1.45rem;
|
||||
font-style: italic;
|
||||
color: #d3d7e1;
|
||||
}
|
||||
|
||||
#ablauf .process-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
min-height: 2.75rem;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
color: var(--th-text-soft);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#ablauf .process-link:hover {
|
||||
color: var(--abl-mint);
|
||||
}
|
||||
|
||||
/* ---------- Tablet: 2 × 2 ---------- */
|
||||
@media (max-width: 1100px) {
|
||||
#ablauf .ablauf-heading { gap: 2rem; }
|
||||
#ablauf .steps { grid-template-columns: repeat(2, 1fr); gap: 2rem 1.75rem; }
|
||||
}
|
||||
|
||||
/* ---------- Mobil: untereinander ---------- */
|
||||
@media (max-width: 760px) {
|
||||
#ablauf .ablauf-heading { display: block; margin-bottom: 2rem; }
|
||||
#ablauf .ablauf-heading > p { max-width: none; margin-top: 1.25rem; }
|
||||
#ablauf .process-end { display: block; }
|
||||
#ablauf .process-link { margin-top: 1rem; }
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
#ablauf .steps { grid-template-columns: 1fr; gap: 1.75rem; }
|
||||
}
|
||||
/* 7. Ablauf und Fußbereich */
|
||||
.steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 30px; margin: 0; padding: 0; list-style: none; }
|
||||
.step-number { display: block; margin-bottom: 24px; padding: 8px 0 22px; border-bottom: 1px solid var(--line); color: rgb(255 255 255 / 45%); font-family: var(--font-display); font-size: 2rem; font-weight: 500; letter-spacing: -.04em; }
|
||||
.steps h3 { margin-bottom: 14px; font-size: 1.0625rem; }
|
||||
.steps p { color: var(--muted); font-size: 1rem; }
|
||||
.process-end { display: flex; align-items: center; justify-content: space-between; gap: 24px; margin-top: 48px; padding-top: 30px; border-top: 1px solid var(--line); }
|
||||
.process-end p { color: rgb(255 255 255 / 82%); font-size: 1.25rem; }
|
||||
.process-end .text-link { flex-shrink: 0; }
|
||||
|
|
|
|||
|
|
@ -1,381 +1,90 @@
|
|||
/* =========================================================
|
||||
US01-02: Angebote und Pakete (+ Verweis auf Coaching-Rabatte)
|
||||
Branch: feature_US01-02
|
||||
Nur Selektoren unter #angebote verwenden.
|
||||
Farben/Schriften über var(--th-...) aus base.css.
|
||||
Vorlage: Prototyp (Angebotsbereich + Detaildialog)
|
||||
========================================================= */
|
||||
|
||||
#angebote {
|
||||
--ang-mint: #56d9b1;
|
||||
--ang-line: rgb(255 255 255 / 0.11);
|
||||
background: linear-gradient(135deg, #161625, #11111e);
|
||||
border-block: 1px solid var(--ang-line);
|
||||
}
|
||||
|
||||
/* ---------- Überschrift ---------- */
|
||||
#angebote .angebote-heading {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#angebote .angebote-eyebrow {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ang-mint);
|
||||
}
|
||||
|
||||
#angebote h2 {
|
||||
margin: 0.9rem 0 0;
|
||||
font-size: clamp(2.2rem, 3.4vw, 2.8rem);
|
||||
font-weight: 400;
|
||||
line-height: 1.12;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
#angebote .angebote-heading > p {
|
||||
max-width: 24rem;
|
||||
margin: 0;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
#angebote .concept-note {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin: 0 0 2rem;
|
||||
font-size: 1rem;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Paketkarten ---------- */
|
||||
#angebote .package-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr)); /* minmax(0,…) verhindert Überlaufen */
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
#angebote .package {
|
||||
/* 6. Angebote – Bildkarten statt Vergleichstabelle */
|
||||
.offers-section { border-block: 1px solid var(--line); background: var(--surface-elevated); }
|
||||
.offers-section .section-heading { margin-bottom: 28px; }
|
||||
.concept-note { display: flex; gap: 8px; margin-bottom: 30px; color: var(--quiet); font-size: .8125rem; }
|
||||
.package-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
|
||||
.package {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--ang-line);
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(140deg, #202032, #181827);
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
#angebote .package:hover,
|
||||
#angebote .package.featured {
|
||||
border-color: rgb(16 185 129 / 0.45);
|
||||
}
|
||||
|
||||
#angebote .package-image {
|
||||
position: relative;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 2rem;
|
||||
background: linear-gradient(#ffffff0f, #ffffff05), linear-gradient(#08151ee6, #091822fa);
|
||||
box-shadow: 0 18px 48px rgb(0 0 0 / 16%);
|
||||
transition: border-color .3s, transform .3s var(--ease), box-shadow .3s;
|
||||
}
|
||||
|
||||
#angebote .package-image img {
|
||||
width: 100%;
|
||||
aspect-ratio: 1.65;
|
||||
object-fit: cover;
|
||||
transition: transform 0.4s;
|
||||
}
|
||||
|
||||
#angebote .package:hover img {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
#angebote .package-badge {
|
||||
.package:hover { border-color: rgb(255 255 255 / 22%); transform: translateY(-4px); box-shadow: 0 24px 52px rgb(0 0 0 / 22%); }
|
||||
.package.featured { border-color: color-mix(in srgb, var(--accent-muted) 35%, transparent); }
|
||||
.package-image { position: relative; overflow: hidden; border-radius: 1.35rem; }
|
||||
.package-image img { width: 100%; aspect-ratio: 1.65; transition: transform .65s var(--ease); }
|
||||
.package:hover .package-image img { transform: scale(1.025); }
|
||||
.package-badge {
|
||||
position: absolute;
|
||||
left: 0.75rem;
|
||||
bottom: 0.75rem;
|
||||
padding: 0.45rem 0.75rem;
|
||||
border-radius: 5px;
|
||||
background: var(--th-accent);
|
||||
color: #06261a;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 750;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#angebote .package-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 1.5rem 0.9rem 0.9rem;
|
||||
}
|
||||
|
||||
#angebote .package-label {
|
||||
margin: 0;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ang-mint);
|
||||
}
|
||||
|
||||
#angebote .package-body h3 {
|
||||
margin: 0.8rem 0 1rem;
|
||||
font-size: 1.9rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
#angebote .package-text {
|
||||
margin: 0;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
#angebote .package-body ul {
|
||||
flex: 1;
|
||||
margin: 1.25rem 0 0;
|
||||
padding: 1.25rem 0 1.5rem;
|
||||
list-style: none;
|
||||
border-top: 1px solid var(--ang-line);
|
||||
}
|
||||
|
||||
#angebote .package-body li {
|
||||
position: relative;
|
||||
padding: 0.3rem 0 0.3rem 1.5rem;
|
||||
}
|
||||
|
||||
#angebote .package-body li::before {
|
||||
content: "✓";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--ang-mint);
|
||||
}
|
||||
|
||||
/* ---------- Buttons ---------- */
|
||||
#angebote .package-button,
|
||||
#angebote .dialog-done {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
min-height: 3.25rem;
|
||||
padding: 0.9rem 1rem;
|
||||
border: 1px solid rgb(255 255 255 / 0.15);
|
||||
border-radius: 7px;
|
||||
background: transparent;
|
||||
color: var(--th-text-soft);
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 650;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
#angebote .package-button:hover {
|
||||
border-color: var(--th-accent);
|
||||
background: rgb(16 185 129 / 0.08);
|
||||
}
|
||||
|
||||
#angebote .package-button.is-primary,
|
||||
#angebote .dialog-done {
|
||||
border-color: transparent;
|
||||
background: var(--th-accent);
|
||||
color: #071b16;
|
||||
}
|
||||
|
||||
#angebote .package-button.is-primary:hover,
|
||||
#angebote .dialog-done:hover {
|
||||
background: #37c99b;
|
||||
}
|
||||
|
||||
/* ---------- Coaching-Rabatt ---------- */
|
||||
#angebote .coaching-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
margin-top: 1.75rem;
|
||||
padding: 1.6rem 1.9rem;
|
||||
border: 1px solid rgb(16 185 129 / 0.19);
|
||||
border-radius: 12px;
|
||||
background: rgb(16 185 129 / 0.04);
|
||||
}
|
||||
|
||||
#angebote .bonus-symbol {
|
||||
padding-right: 1.5rem;
|
||||
border-right: 1px solid rgb(16 185 129 / 0.25);
|
||||
font-family: var(--th-font-display);
|
||||
font-size: 2.2rem;
|
||||
color: var(--ang-mint);
|
||||
}
|
||||
|
||||
#angebote .coaching-banner h3 {
|
||||
margin: 0 0 0.3rem;
|
||||
font-family: var(--th-font-body);
|
||||
font-size: 1.2rem;
|
||||
bottom: 12px;
|
||||
left: 12px;
|
||||
max-width: calc(100% - 24px);
|
||||
padding: 6px 12px;
|
||||
border: 1px solid color-mix(in srgb, var(--accent-muted) 32%, transparent);
|
||||
border-radius: 999px;
|
||||
background: rgb(7 27 34 / 90%);
|
||||
color: color-mix(in srgb, var(--accent-strong) 74%, white);
|
||||
font-size: .6875rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: .13em;
|
||||
}
|
||||
.package-body { display: flex; flex: 1; flex-direction: column; padding: 24px 8px 8px; }
|
||||
.package-body h3 { margin-block: 14px 20px; font-size: clamp(1.5rem, 2.05vw, 1.875rem); line-height: 1.3; }
|
||||
.package-body > p:not(.eyebrow) { color: var(--muted); font-size: 1rem; line-height: 1.8; }
|
||||
.package-body ul { flex: 1; margin-top: 24px; padding: 20px 0 24px; border-top: 1px solid var(--line); list-style: none; font-size: .9375rem; }
|
||||
.package-body li { position: relative; padding: 6px 0 6px 23px; color: rgb(255 255 255 / 82%); }
|
||||
.package-body li::before { content: '✓'; position: absolute; left: 0; color: var(--quiet); }
|
||||
.package .button { width: 100%; font-size: .9375rem; }
|
||||
.coaching-banner { display: flex; align-items: center; gap: 24px; margin-top: 30px; padding: 28px 30px; border: 1px solid var(--line); border-radius: 1.5rem; background: var(--panel); }
|
||||
.bonus-symbol { display: grid; flex-shrink: 0; place-items: center; width: 52px; height: 52px; border: 1px solid var(--line); border-radius: 1rem; background: rgb(255 255 255 / 3%); color: rgb(255 255 255 / 80%); font-size: 1.5rem; }
|
||||
.coaching-banner h3 { margin-bottom: 6px; font-size: 1.0625rem; }
|
||||
.coaching-banner p { color: var(--muted); font-size: .9375rem; }
|
||||
.coaching-banner .text-link { margin-left: auto; flex-shrink: 0; font-size: .875rem; }
|
||||
|
||||
#angebote .coaching-banner p {
|
||||
margin: 0;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
#angebote .bonus-button {
|
||||
margin-left: auto;
|
||||
min-height: 2.75rem;
|
||||
border: 0;
|
||||
background: none;
|
||||
color: var(--ang-mint);
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ---------- Dialog ---------- */
|
||||
#angebote dialog {
|
||||
margin: auto; /* Kunden-CSS setzt margin:0 → Dialog wieder zentrieren */
|
||||
width: min(680px, calc(100% - 2rem));
|
||||
/* 8. Produktdetails – weiterhin zentriert und innerhalb des Fensters scrollbar */
|
||||
dialog {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
width: min(720px, calc(100% - 32px));
|
||||
max-height: 90dvh;
|
||||
padding: 0;
|
||||
border: 1px solid rgb(255 255 255 / 0.15);
|
||||
border-radius: 20px;
|
||||
background: #171726;
|
||||
color: var(--th-text-soft);
|
||||
box-shadow: 0 30px 100px rgb(0 0 0 / 0.55);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
border: 1px solid rgb(255 255 255 / 16%);
|
||||
border-radius: 1.75rem;
|
||||
background: linear-gradient(#ffffff07, #ffffff00), var(--surface-elevated);
|
||||
color: var(--text);
|
||||
box-shadow: 0 30px 100px rgb(0 0 0 / 55%);
|
||||
scrollbar-color: #46545c transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
dialog::backdrop { background: rgb(2 8 12 / 78%); backdrop-filter: blur(7px); }
|
||||
.dialog-inner { position: relative; padding: 42px; }
|
||||
.close-dialog { position: absolute; top: 14px; right: 14px; width: 42px; height: 42px; border: 1px solid var(--line); border-radius: 50%; background: rgb(255 255 255 / 4%); color: var(--muted); font-size: 1.75rem; line-height: 1; }
|
||||
.close-dialog:hover { background: rgb(255 255 255 / 10%); color: #fff; }
|
||||
.dialog-inner > .eyebrow { padding-right: 24px; }
|
||||
.dialog-inner h2 { margin: 16px 18px 22px 0; font-size: 2rem; line-height: 1.2; }
|
||||
.dialog-inner > p:not(.eyebrow) { color: var(--muted); font-size: 1rem; }
|
||||
.dialog-inner h3 { margin: 28px 0 14px; font-size: 1.125rem; }
|
||||
#dialog-features { padding-left: 20px; color: rgb(255 255 255 / 82%); font-size: 1rem; }
|
||||
#dialog-features li { padding-block: 5px; }
|
||||
#dialog-features li::marker { color: var(--quiet); }
|
||||
.detail-note, .discount-help { color: var(--quiet); font-size: .8125rem; line-height: 1.7; }
|
||||
.detail-note { margin-top: 12px; }
|
||||
.discount-box { margin-block: 28px; padding: 24px; border: 1px solid var(--line); border-radius: 1.25rem; background: var(--panel); }
|
||||
.discount-box h3 { margin: 10px 0 22px; }
|
||||
.discount-box label { display: block; margin-bottom: 10px; color: rgb(255 255 255 / 82%); font-size: .9375rem; }
|
||||
.discount-box select { width: 100%; min-height: 50px; padding: 12px; border: 1px solid rgb(255 255 255 / 20%); border-radius: .75rem; background: var(--background); color: #fff; font-size: .9375rem; }
|
||||
#discount-result { padding-block: 20px; color: rgb(255 255 255 / 88%); font-size: 1.0625rem; }
|
||||
#discount-result strong { color: color-mix(in srgb, var(--accent-strong) 70%, white); font-size: 1.5rem; font-weight: 600; }
|
||||
.discount-box a { display: inline-block; margin-top: 16px; color: rgb(255 255 255 / 84%); font-size: .875rem; text-decoration: underline; text-underline-offset: 4px; }
|
||||
.discount-box a:hover { color: #fff; }
|
||||
.dialog-done { width: 100%; }
|
||||
body:has(dialog[open]) { overflow: hidden; }
|
||||
|
||||
#angebote dialog::backdrop {
|
||||
background: rgb(5 5 11 / 0.8);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
#angebote .dialog-inner {
|
||||
position: relative;
|
||||
padding: 2.5rem;
|
||||
}
|
||||
|
||||
#angebote .close-dialog {
|
||||
position: absolute;
|
||||
top: 0.75rem;
|
||||
right: 1rem;
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--th-text-muted);
|
||||
font-size: 1.9rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#angebote .dialog-inner h2 {
|
||||
margin: 0.8rem 2.2rem 1.1rem 0;
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
#angebote #dialog-description {
|
||||
margin: 0;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
#angebote .dialog-inner h3 {
|
||||
margin: 1.6rem 0 0.75rem;
|
||||
font-family: var(--th-font-body);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#angebote #dialog-features {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
#angebote #dialog-features li {
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
#angebote .dialog-hint {
|
||||
margin: 0.75rem 0 0;
|
||||
font-size: 1rem;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
#angebote .discount-box {
|
||||
margin: 1.6rem 0;
|
||||
padding: 1.4rem;
|
||||
border: 1px solid rgb(16 185 129 / 0.27);
|
||||
border-radius: 12px;
|
||||
background: rgb(16 185 129 / 0.035);
|
||||
}
|
||||
|
||||
#angebote .discount-box h3 {
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
#angebote .discount-box label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#angebote .discount-box select {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid rgb(255 255 255 / 0.25);
|
||||
border-radius: 7px;
|
||||
background: #11111f;
|
||||
color: var(--th-text-soft);
|
||||
font-size: 1.0625rem;
|
||||
}
|
||||
|
||||
#angebote #discount-result {
|
||||
margin: 0;
|
||||
padding: 1rem 0 0;
|
||||
color: var(--ang-mint);
|
||||
}
|
||||
|
||||
#angebote #discount-result strong {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
#angebote .discount-box a {
|
||||
display: inline-block;
|
||||
margin-top: 0.9rem;
|
||||
color: var(--ang-mint);
|
||||
}
|
||||
|
||||
#angebote select:focus-visible {
|
||||
outline: 3px solid var(--th-accent);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
/* ---------- Tablet ---------- */
|
||||
@media (max-width: 1100px) {
|
||||
#angebote .angebote-heading { gap: 2rem; }
|
||||
#angebote .package-body h3 { font-size: 1.7rem; }
|
||||
#angebote .coaching-banner { flex-wrap: wrap; }
|
||||
#angebote .bonus-button { margin-left: 0; }
|
||||
}
|
||||
|
||||
/* ---------- schmale Tablets: 2 Karten nebeneinander ---------- */
|
||||
@media (max-width: 1000px) {
|
||||
#angebote .package-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
/* ---------- Mobil ---------- */
|
||||
@media (max-width: 760px) {
|
||||
#angebote .angebote-heading { display: block; }
|
||||
#angebote .angebote-heading > p { max-width: none; margin-top: 1.25rem; }
|
||||
#angebote .package-grid { grid-template-columns: 1fr; }
|
||||
#angebote .package-image img { aspect-ratio: 1.8; }
|
||||
#angebote .coaching-banner { padding: 1.4rem; gap: 1rem; }
|
||||
#angebote .coaching-banner > div:nth-child(2) { flex: 1; min-width: 12rem; }
|
||||
#angebote .bonus-symbol { display: none; }
|
||||
#angebote .dialog-inner { padding: 2rem 1.4rem; }
|
||||
#angebote .dialog-inner h2 { font-size: 1.9rem; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#angebote .package img { transition: none; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,264 +1,107 @@
|
|||
/* =========================================================
|
||||
US01-01: Angebot und Zielgruppe sofort sehen (Hero)
|
||||
Branch: feature_US01-01
|
||||
Nur Selektoren unter #hero verwenden.
|
||||
Farben/Schriften über var(--th-...) aus base.css.
|
||||
Vorlage: Prototyp (Hero-Bereich)
|
||||
========================================================= */
|
||||
|
||||
#hero {
|
||||
--hero-mint: #56d9b1; /* helle Akzentvariante aus dem Prototyp */
|
||||
--hero-line: rgb(255 255 255 / 0.11);
|
||||
padding-block: clamp(1.5rem, 4svh, 3.5rem); /* überschreibt Sektionsabstand aus base.css */
|
||||
min-height: calc(100svh - 4.5rem); /* ohne Scrollen sichtbar (minus Header) */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#hero .hero-grid {
|
||||
/* 4. Hero – Sans Serif, Original-Hintergrund und gerahmtes Foto */
|
||||
.hero {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
display: grid;
|
||||
grid-template-columns: 1.08fr 1fr;
|
||||
gap: 4rem;
|
||||
gap: 56px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding-block: 64px 72px;
|
||||
}
|
||||
|
||||
/* ---------- Text ---------- */
|
||||
#hero h1 {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
.hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
inset: 0 calc((100vw - 100%) / -2);
|
||||
pointer-events: none;
|
||||
background: linear-gradient(rgb(4 14 20 / 40%), rgb(4 14 20 / 82%)),
|
||||
url('../../assets/images/hero/trihub-ribbon.webp') center / cover;
|
||||
opacity: .2;
|
||||
}
|
||||
|
||||
#hero .hero-kicker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-family: var(--th-font-body);
|
||||
font-size: 1rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--hero-mint);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
#hero .hero-line {
|
||||
flex: 0 0 1.5rem;
|
||||
height: 1px;
|
||||
background: var(--th-accent);
|
||||
}
|
||||
|
||||
#hero .hero-headline {
|
||||
display: block;
|
||||
margin-top: 1.5rem;
|
||||
font-family: var(--th-font-display);
|
||||
font-size: clamp(2.6rem, 4.8vw, 4.5rem);
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.03em;
|
||||
color: var(--th-text);
|
||||
}
|
||||
|
||||
#hero .hero-headline em {
|
||||
color: var(--hero-mint);
|
||||
}
|
||||
|
||||
#hero .hero-intro {
|
||||
margin-top: 1.5rem;
|
||||
max-width: 32rem;
|
||||
font-size: 1.1875rem;
|
||||
line-height: 1.75;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Aktionen ---------- */
|
||||
#hero .hero-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 1.75rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#hero .hero-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
min-height: 3.25rem; /* große Klickfläche */
|
||||
padding: 0.9rem 1.6rem;
|
||||
border-radius: 7px;
|
||||
background: var(--th-accent);
|
||||
color: #071b16;
|
||||
font-size: 1.125rem;
|
||||
font-weight: 650;
|
||||
transition: background 0.2s, transform 0.2s;
|
||||
}
|
||||
|
||||
#hero .hero-button:hover {
|
||||
background: #37c99b;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
#hero .hero-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
min-height: 2.75rem;
|
||||
font-size: 1.125rem;
|
||||
.eyebrow {
|
||||
color: var(--quiet);
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
color: var(--th-text-soft);
|
||||
letter-spacing: .22em;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
#hero .hero-link:hover {
|
||||
color: var(--hero-mint);
|
||||
.hero-copy > .eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 999px;
|
||||
background: rgb(255 255 255 / 4%);
|
||||
color: var(--muted);
|
||||
font-size: .6875rem;
|
||||
letter-spacing: .16em;
|
||||
}
|
||||
|
||||
/* ---------- Bild ---------- */
|
||||
#hero .hero-visual {
|
||||
.tiny-line { width: 16px; height: 1px; flex-shrink: 0; background: var(--accent-warm); }
|
||||
h1 {
|
||||
margin-block: 28px;
|
||||
font-size: clamp(2.75rem, 4.65vw, 4.5rem);
|
||||
font-weight: 600;
|
||||
letter-spacing: -.05em;
|
||||
line-height: 1.06;
|
||||
}
|
||||
h1 em { color: inherit; font: inherit; }
|
||||
.hero-intro { max-width: 510px; color: rgb(255 255 255 / 74%); font-size: 1.125rem; line-height: 1.8; }
|
||||
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 24px; margin-top: 32px; }
|
||||
.hero-note { margin-top: 26px; color: var(--quiet); font-size: .875rem; }
|
||||
.check { margin-right: 7px; color: rgb(255 255 255 / 72%); }
|
||||
.hero-visual {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
height: clamp(320px, 52svh, 540px);
|
||||
border-radius: 15px;
|
||||
height: 570px;
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--th-bg-elevated);
|
||||
border: 1px solid rgb(255 255 255 / 12%);
|
||||
border-radius: 2rem;
|
||||
background: var(--panel);
|
||||
box-shadow: 0 24px 60px rgb(0 0 0 / 22%);
|
||||
}
|
||||
|
||||
#hero .hero-visual img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
#hero .hero-visual::after { /* Verlauf für lesbare Bildunterschrift */
|
||||
content: "";
|
||||
.hero-visual > img { width: 100%; height: 100%; border-radius: 1.4rem; object-position: center; }
|
||||
.hero-visual figcaption {
|
||||
position: absolute;
|
||||
inset: 35% 0 0;
|
||||
background: linear-gradient(transparent, rgb(5 15 18 / 0.94));
|
||||
right: 28px;
|
||||
bottom: 28px;
|
||||
left: 28px;
|
||||
padding: 22px 24px;
|
||||
border: 1px solid rgb(255 255 255 / 14%);
|
||||
border-radius: 1.4rem;
|
||||
background: rgb(3 13 18 / 84%);
|
||||
backdrop-filter: blur(14px);
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
#hero figcaption {
|
||||
.hero-visual figcaption span { color: var(--quiet); font-size: .75rem; letter-spacing: .19em; }
|
||||
.hero-visual figcaption p { margin-top: 10px; font-size: 1.25rem; font-weight: 500; line-height: 1.5; }
|
||||
.image-tag {
|
||||
position: absolute;
|
||||
left: 2rem;
|
||||
bottom: 2rem;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#hero .hero-caption-label {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: #b5efda;
|
||||
}
|
||||
|
||||
#hero .hero-caption-text {
|
||||
display: block;
|
||||
margin-top: 0.6rem;
|
||||
font-family: var(--th-font-display);
|
||||
font-size: 1.75rem;
|
||||
line-height: 1.3;
|
||||
color: var(--th-text);
|
||||
}
|
||||
|
||||
#hero .hero-tag {
|
||||
position: absolute;
|
||||
top: 1.25rem;
|
||||
right: 1.25rem;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid rgb(255 255 255 / 0.19);
|
||||
border-radius: 8px;
|
||||
background: rgb(13 13 26 / 0.8);
|
||||
top: 28px;
|
||||
right: 28px;
|
||||
padding: 10px 16px;
|
||||
border: 1px solid rgb(255 255 255 / 18%);
|
||||
border-radius: 1rem;
|
||||
background: rgb(3 13 18 / 78%);
|
||||
backdrop-filter: blur(12px);
|
||||
font-size: 0.7rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
font-size: .6875rem;
|
||||
letter-spacing: .13em;
|
||||
text-align: center;
|
||||
color: var(--th-text-soft);
|
||||
}
|
||||
.image-tag b { display: block; margin-top: 2px; color: #fff; font-family: var(--font-display); font-size: 1.8rem; font-weight: 600; letter-spacing: -.04em; line-height: 1.2; }
|
||||
.values-strip { border-block: 1px solid var(--line); background: rgb(255 255 255 / 2%); }
|
||||
.values-strip .shell { display: flex; justify-content: center; align-items: center; gap: 60px; padding-block: 22px; color: var(--muted); font-size: .875rem; }
|
||||
.values-strip i { color: rgb(255 255 255 / 24%); font-size: .75rem; font-style: normal; }
|
||||
|
||||
#hero .hero-tag b {
|
||||
display: block;
|
||||
margin-top: 0.25rem;
|
||||
font-family: var(--th-font-display);
|
||||
font-size: 2rem;
|
||||
line-height: 1.1;
|
||||
letter-spacing: 0;
|
||||
color: var(--hero-mint);
|
||||
}
|
||||
/* 5. Vorteile und wiederkehrende Sektionsüberschriften */
|
||||
.section { padding-block: 96px; }
|
||||
.section-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 56px; margin-bottom: 44px; }
|
||||
.section-heading h2 { margin-top: 16px; font-size: clamp(2rem, 3.1vw, 3rem); }
|
||||
.section-heading > p { max-width: 350px; color: var(--muted); font-size: 1rem; line-height: 1.85; }
|
||||
.benefit-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px; }
|
||||
.benefit-grid article { padding-top: 28px; border-top: 1px solid var(--line); }
|
||||
.benefit-icon { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; margin-bottom: 22px; border: 1px solid var(--line); border-radius: .875rem; background: rgb(255 255 255 / 4%); color: rgb(255 255 255 / 74%); font-size: 1.5rem; }
|
||||
.benefit-grid h3 { margin-bottom: 14px; font-size: 1.25rem; }
|
||||
.benefit-grid p { max-width: 365px; color: var(--muted); font-size: 1rem; }
|
||||
|
||||
/* ---------- 3 Vorteile unter dem Hero ---------- */
|
||||
#hero .hero-benefits {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
margin: 2.5rem 0 0;
|
||||
padding: 1.5rem 0 0;
|
||||
list-style: none;
|
||||
border-top: 1px solid var(--hero-line);
|
||||
}
|
||||
|
||||
#hero .hero-benefits li {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
#hero .hero-benefit-icon {
|
||||
flex: 0 0 2.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 2.5rem;
|
||||
border-radius: 10px;
|
||||
background: rgb(16 185 129 / 0.1);
|
||||
color: var(--hero-mint);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
#hero .hero-benefits h2 {
|
||||
margin: 0;
|
||||
font-family: var(--th-font-body);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.35;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--th-text);
|
||||
}
|
||||
|
||||
#hero .hero-benefits p {
|
||||
margin: 0.3rem 0 0;
|
||||
font-size: 1rem;
|
||||
line-height: 1.55;
|
||||
color: var(--th-text-muted);
|
||||
}
|
||||
|
||||
/* ---------- Tablet ---------- */
|
||||
@media (max-width: 1100px) {
|
||||
#hero .hero-grid { gap: 2rem; }
|
||||
#hero .hero-benefits { gap: 1.25rem; }
|
||||
}
|
||||
|
||||
/* ---------- Mobil: Text zuerst, Bild darunter ---------- */
|
||||
@media (max-width: 760px) {
|
||||
#hero {
|
||||
min-height: 0;
|
||||
padding-block: 2rem 3rem;
|
||||
}
|
||||
|
||||
#hero .hero-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
#hero .hero-kicker { font-size: 0.875rem; }
|
||||
#hero .hero-headline { margin-top: 1rem; font-size: clamp(2.3rem, 10vw, 3.2rem); }
|
||||
#hero .hero-intro { margin-top: 1rem; font-size: 1.125rem; }
|
||||
#hero .hero-actions { margin-top: 1.5rem; gap: 1.25rem; }
|
||||
#hero .hero-visual { height: 340px; }
|
||||
#hero figcaption { left: 1.25rem; bottom: 1.25rem; }
|
||||
#hero .hero-caption-text { font-size: 1.4rem; }
|
||||
#hero .hero-benefits { grid-template-columns: 1fr; gap: 1.25rem; margin-top: 2rem; }
|
||||
}
|
||||
|
||||
@media (max-width: 390px) {
|
||||
#hero .hero-button { width: 100%; justify-content: space-between; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,270 +1,389 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ernährungsberatung für Triathleten 50+ | tri-hub</title>
|
||||
<meta name="description" content="Ernährungsberatung für Triathletinnen und Triathleten ab 50.">
|
||||
|
||||
<!-- Kunden-CSS (Tailwind-Build von tri-hub.de) – NICHT verändern -->
|
||||
<link rel="stylesheet" href="css/assets.css">
|
||||
|
||||
<!-- Schriften laut Design-DNA: Playfair Display (Überschriften) + Inter (Text) -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:wght@600;700&display=swap">
|
||||
|
||||
<!-- Projektweite Basis (Design-Tokens, Lesbarkeit) -->
|
||||
<link rel="stylesheet" href="css/base.css">
|
||||
|
||||
<!-- Ein Stylesheet pro User Story – jede Datei gehört genau einem Feature-Branch -->
|
||||
<link rel="stylesheet" href="css/sections/hero.css"> <!-- US01-01 -->
|
||||
<link rel="stylesheet" href="css/sections/angebote.css"> <!-- US01-02 -->
|
||||
<link rel="stylesheet" href="css/sections/ablauf.css"> <!-- US01-03 -->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Ernährungsberatung ab 50 | TriHub</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Ernährung, die zu deinem Triathlon und deinem Leben passt. Entdecke drei Konzepte für persönliche Ernährungsberatung bei TriHub."
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/jpeg"
|
||||
href="assets/images/icons/trihub-logo.jpg"
|
||||
/>
|
||||
<link rel="stylesheet" href="css/assets.css" />
|
||||
<link rel="stylesheet" href="css/base.css" />
|
||||
<link rel="stylesheet" href="css/sections/hero.css" />
|
||||
<link rel="stylesheet" href="css/sections/angebote.css" />
|
||||
<link rel="stylesheet" href="css/sections/ablauf.css" />
|
||||
<link rel="stylesheet" href="css/responsive.css" />
|
||||
<script src="js/angebote.js" defer></script>
|
||||
<script src="js/main.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip" href="#inhalt">Zum Inhalt</a>
|
||||
<header class="site-header">
|
||||
<div class="container">
|
||||
<a href="/" class="site-logo">tri-hub</a>
|
||||
<!-- US01-05 Navigation: späterer Sprint -->
|
||||
<div class="shell header-inner">
|
||||
<a
|
||||
class="brand brand-logo"
|
||||
href="https://tri-hub.de/"
|
||||
aria-label="TriHub Startseite"
|
||||
><span class="brand-mark"
|
||||
><img
|
||||
src="assets/images/icons/trihub-logo.jpg"
|
||||
width="1024"
|
||||
height="1024"
|
||||
alt="Trihub – fit und vital ab 50!" /></span
|
||||
><span class="brand-copy"
|
||||
><span class="brand-name">Tri-hub</span
|
||||
><span class="brand-sub"
|
||||
>Ernährungsberatung für Triathlon ab 50</span
|
||||
></span
|
||||
></a
|
||||
>
|
||||
<nav aria-label="Hauptnavigation">
|
||||
<a href="https://tri-hub.de/coaching-1zu1">Coaching 1zu1</a
|
||||
><a href="#inhalt" aria-current="page">Ernährungsberatung</a
|
||||
><a href="#ablauf">So läuft’s ab</a>
|
||||
</nav>
|
||||
<a class="button small header-cta" href="#angebote"
|
||||
>Angebote entdecken</a
|
||||
>
|
||||
<button
|
||||
class="menu-toggle"
|
||||
aria-expanded="false"
|
||||
aria-controls="mobile-nav"
|
||||
aria-label="Menü öffnen"
|
||||
>
|
||||
☰
|
||||
</button>
|
||||
</div>
|
||||
<nav id="mobile-nav" aria-label="Mobile Navigation" hidden>
|
||||
<a href="#angebote">Angebote entdecken</a
|
||||
><a href="#vorteile">Deine Vorteile</a
|
||||
><a href="#ablauf">So läuft’s ab</a
|
||||
><a href="https://tri-hub.de/coaching-1zu1">Coaching 1zu1</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- ========== US01-01: Angebot und Zielgruppe (Hero) ==========
|
||||
Branch: feature/US01-01-hero · Styles: css/sections/hero.css
|
||||
Nur innerhalb dieser <section> arbeiten. -->
|
||||
<section id="hero" aria-labelledby="hero-title">
|
||||
<div class="container">
|
||||
<div class="hero-grid">
|
||||
|
||||
<main id="inhalt">
|
||||
<section class="hero shell" aria-labelledby="hero-title">
|
||||
<div class="hero-copy">
|
||||
<div class="eyebrow">
|
||||
<span class="tiny-line"></span> ERNÄHRUNGSBERATUNG FÜR TRIATHLON AB
|
||||
50
|
||||
</div>
|
||||
<h1 id="hero-title">
|
||||
<span class="hero-kicker"><span class="hero-line" aria-hidden="true"></span>Ernährungsberatung für Triathlon ab 50</span>
|
||||
<span class="hero-headline">Gut versorgt.<br>Für alles, was<br><em>noch vor dir liegt.</em></span>
|
||||
Gut versorgt.<br />Für alles, was<br /><em>noch vor dir liegt.</em>
|
||||
</h1>
|
||||
|
||||
<p class="hero-intro">
|
||||
Dein nächstes Ziel beginnt auch auf dem Teller. Finde eine Ernährung,
|
||||
die zu deinem Training, deinem Körper und deinem Leben passt.
|
||||
Dein nächstes Ziel beginnt auch auf dem Teller. Finde eine
|
||||
Ernährung, die zu deinem Training, deinem Körper und deinem Leben
|
||||
passt.
|
||||
</p>
|
||||
|
||||
<div class="hero-actions">
|
||||
<a class="hero-button" href="#angebote">Mehr erfahren <span aria-hidden="true">↓</span></a>
|
||||
<a class="hero-link" href="#ablauf">So funktioniert’s <span aria-hidden="true">→</span></a>
|
||||
<a class="button" href="#angebote">Deine Begleitung finden</a
|
||||
><a class="text-link" href="#ablauf">So funktioniert’s</a>
|
||||
</div>
|
||||
<div class="hero-note">
|
||||
<span class="check" aria-hidden="true">✓</span> Persönlich.
|
||||
Alltagstauglich. Auf Augenhöhe.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<figure class="hero-visual">
|
||||
<img src="assets/images/hero/hero.webp" width="1200" height="800"
|
||||
<img
|
||||
src="assets/images/hero/hero.webp"
|
||||
width="1200"
|
||||
height="800"
|
||||
alt="Zwei sportlich aktive Menschen ab 50 besprechen einen Plan neben einem Fahrrad am See"
|
||||
fetchpriority="high">
|
||||
fetchpriority="high"
|
||||
/>
|
||||
<figcaption>
|
||||
<span class="hero-caption-label">Dein Tempo. Deine Ziele.</span>
|
||||
<span class="hero-caption-text">Mehr Freude am Sport.<br>Mehr Energie fürs Leben.</span>
|
||||
<span>DEIN TEMPO. DEINE ZIELE.</span>
|
||||
<p>Mehr Freude am Sport.<br />Mehr Energie fürs Leben.</p>
|
||||
</figcaption>
|
||||
<div class="hero-tag" aria-hidden="true">Triathlon <b>50+</b></div>
|
||||
<div class="image-tag">TRIATHLON <b>50+</b></div>
|
||||
</figure>
|
||||
|
||||
</section>
|
||||
<div class="values-strip">
|
||||
<div class="shell">
|
||||
<span>Für deinen Einstieg</span><i aria-hidden="true">✦</i
|
||||
><span>Für deinen Wiedereinstieg</span><i aria-hidden="true">✦</i
|
||||
><span>Für dein nächstes Ziel</span>
|
||||
</div>
|
||||
|
||||
<!-- 3 Vorteile mit Überschrift (Checkliste US01-01) -->
|
||||
<ul class="hero-benefits" aria-label="Deine Vorteile auf einen Blick">
|
||||
<li>
|
||||
<span class="hero-benefit-icon" aria-hidden="true">↗</span>
|
||||
</div>
|
||||
<section id="vorteile" class="shell section benefits">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>Energie gezielt einplanen</h2>
|
||||
<p>Mahlzeiten passend zu Ruhetagen, harten Einheiten und langen Ausfahrten.</p>
|
||||
<p class="eyebrow">WAS DU DAVON HAST</p>
|
||||
<h2>Dein Training verdient<br />die passende Ernährung.</h2>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span class="hero-benefit-icon" aria-hidden="true">↻</span>
|
||||
<div>
|
||||
<h2>Regeneration mitdenken</h2>
|
||||
<p>Ernährung, die deinen Körper nach dem Training gezielt unterstützt.</p>
|
||||
<p>
|
||||
Du bringst die Motivation mit. Gemeinsam schaffen wir Orientierung
|
||||
für das Essen und Trinken rund um deinen Sport.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span class="hero-benefit-icon" aria-hidden="true">✓</span>
|
||||
<div>
|
||||
<h2>Im Alltag dranbleiben</h2>
|
||||
<p>Routinen, die zu Arbeit, Familie und deinen Vorlieben passen.</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="benefit-grid">
|
||||
<article>
|
||||
<span class="benefit-icon" aria-hidden="true">↗</span>
|
||||
<h3>Energie gezielt einplanen</h3>
|
||||
<p>
|
||||
Verstehe, wie du deine Mahlzeiten auf ruhige Tage, intensive
|
||||
Einheiten und lange Ausfahrten abstimmst.
|
||||
</p>
|
||||
</article>
|
||||
<article>
|
||||
<span class="benefit-icon" aria-hidden="true">↻</span>
|
||||
<h3>Regeneration mitdenken</h3>
|
||||
<p>
|
||||
Gib Erholung einen festen Platz – mit einer Ernährung, die deinen
|
||||
Körper nach dem Training unterstützt.
|
||||
</p>
|
||||
</article>
|
||||
<article>
|
||||
<span class="benefit-icon" aria-hidden="true">✓</span>
|
||||
<h3>Im Alltag dranbleiben</h3>
|
||||
<p>
|
||||
Entwickle Routinen, die zu Arbeit, Familie und deinen Vorlieben
|
||||
passen. Ohne komplizierte Regeln.
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
<!-- ========== /US01-01 ========== -->
|
||||
|
||||
|
||||
<!-- ========== US01-02: Angebote und Pakete ==========
|
||||
Branch: feature_US01-02 · Styles: css/sections/angebote.css · Script: js/angebote.js
|
||||
Nur innerhalb dieser <section> arbeiten. -->
|
||||
<section id="angebote" aria-labelledby="angebote-title">
|
||||
<div class="container">
|
||||
|
||||
<div class="angebote-heading">
|
||||
<section id="angebote" class="offers-section">
|
||||
<div class="shell section">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<p class="angebote-eyebrow">Deine Ernährung. Deine Begleitung.</p>
|
||||
<h2 id="angebote-title">So viel Unterstützung,<br>wie du brauchst.</h2>
|
||||
<p class="eyebrow">DEINE ERNÄHRUNG. DEINE BEGLEITUNG.</p>
|
||||
<h2>So viel Unterstützung,<br />wie du brauchst.</h2>
|
||||
</div>
|
||||
<p>Ein klarer Einstieg oder eine enge Begleitung: Wähle den Rahmen, der sich für dich richtig anfühlt.</p>
|
||||
<p>
|
||||
Ein klarer Einstieg oder eine enge Begleitung: Wähle den Rahmen,
|
||||
der sich für dich richtig anfühlt.
|
||||
</p>
|
||||
</div>
|
||||
<div class="concept-note">
|
||||
<span aria-hidden="true">ⓘ</span> Angebotskonzept · Leistungen zur
|
||||
Abstimmung. Preise und Laufzeiten sind noch offen.
|
||||
</div>
|
||||
|
||||
<p class="concept-note"><span aria-hidden="true">ⓘ</span> Angebotskonzept · Leistungen zur Abstimmung. Preise und Laufzeiten sind noch offen.</p>
|
||||
|
||||
<div class="package-grid">
|
||||
<article class="package">
|
||||
<div class="package-image">
|
||||
<img src="assets/images/angebote/starter.webp" width="700" height="420" alt="Gemeinsame Planung am See für den sportlichen Einstieg" loading="lazy">
|
||||
<img
|
||||
src="assets/images/angebote/starter.webp"
|
||||
width="700"
|
||||
height="420"
|
||||
alt="Gemeinsame Planung am See für den sportlichen Einstieg"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="package-body">
|
||||
<p class="package-label">Starter</p>
|
||||
<h3>Dein erster<br>guter Schritt.</h3>
|
||||
<p class="package-text">Für Einsteiger und Wiedereinsteiger, die ihre Ernährung verstehen und gezielt verändern möchten.</p>
|
||||
<p class="eyebrow">STARTER</p>
|
||||
<h3>Dein erster<br />guter Schritt.</h3>
|
||||
<p>
|
||||
Für Einsteiger und Wiedereinsteiger, die ihre Ernährung
|
||||
verstehen und gezielt verändern möchten.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Persönliche Bestandsaufnahme</li>
|
||||
<li>Analyse deiner Essgewohnheiten</li>
|
||||
<li>Konkrete Empfehlungen für den Alltag</li>
|
||||
</ul>
|
||||
<button type="button" class="package-button" data-package="starter">Starter entdecken <span aria-hidden="true">↗</span></button>
|
||||
<button
|
||||
class="button outline package-open"
|
||||
data-package="starter"
|
||||
>
|
||||
Starter entdecken
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="package featured">
|
||||
<div class="package-image">
|
||||
<img src="assets/images/angebote/standard.webp" width="700" height="420" alt="Sportler und Coach besprechen gemeinsam einen Plan am Fahrrad" loading="lazy">
|
||||
<span class="package-badge">Mit individuellem Plan</span>
|
||||
<img
|
||||
src="assets/images/angebote/standard.webp"
|
||||
width="700"
|
||||
height="420"
|
||||
alt="Sportler und Coach besprechen gemeinsam einen Plan am Fahrrad"
|
||||
loading="lazy"
|
||||
/><span class="package-badge">MIT INDIVIDUELLEM PLAN</span>
|
||||
</div>
|
||||
<div class="package-body">
|
||||
<p class="package-label">Standard</p>
|
||||
<h3>Aus guten Vorsätzen<br>wird dein Plan.</h3>
|
||||
<p class="package-text">Für alle, die Ernährung und Training aufeinander abstimmen und neue Routinen festigen möchten.</p>
|
||||
<p class="eyebrow">STANDARD</p>
|
||||
<h3>Aus guten Vorsätzen<br />wird dein Plan.</h3>
|
||||
<p>
|
||||
Für alle, die Ernährung und Training aufeinander abstimmen und
|
||||
neue Routinen festigen möchten.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Alles aus Starter</li>
|
||||
<li>Individueller Ernährungsrahmen</li>
|
||||
<li>Feedback und gemeinsame Anpassung</li>
|
||||
</ul>
|
||||
<button type="button" class="package-button is-primary" data-package="standard">Standard entdecken <span aria-hidden="true">↗</span></button>
|
||||
<button class="button package-open" data-package="standard">
|
||||
Standard entdecken
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="package">
|
||||
<div class="package-image">
|
||||
<img src="assets/images/angebote/premium.webp" width="700" height="420" alt="Persönliches Coachinggespräch auf einer Bank neben einem Triathlonrad" loading="lazy">
|
||||
<img
|
||||
src="assets/images/angebote/premium.webp"
|
||||
width="700"
|
||||
height="420"
|
||||
alt="Persönliches Coachinggespräch auf einer Bank neben einem Triathlonrad"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="package-body">
|
||||
<p class="package-label">Premium</p>
|
||||
<h3>Dein Ziel.<br>Ganz persönlich.</h3>
|
||||
<p class="package-text">Für ambitionierte Ziele und alle, die sich eine besonders enge, individuelle Begleitung wünschen.</p>
|
||||
<p class="eyebrow">PREMIUM</p>
|
||||
<h3>Dein Ziel.<br />Ganz persönlich.</h3>
|
||||
<p>
|
||||
Für ambitionierte Ziele und alle, die sich eine besonders
|
||||
enge, individuelle Begleitung wünschen.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Alles aus Standard</li>
|
||||
<li>Verpflegungsstrategie für Wettkämpfe</li>
|
||||
<li>Engmaschige Begleitung und Anpassung</li>
|
||||
</ul>
|
||||
<button type="button" class="package-button" data-package="premium">Premium entdecken <span aria-hidden="true">↗</span></button>
|
||||
<button
|
||||
class="button outline package-open"
|
||||
data-package="premium"
|
||||
>
|
||||
Premium entdecken
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<!-- Verweis auf Rabatte aus dem Coaching 1zu1 -->
|
||||
<div class="coaching-banner">
|
||||
<div class="bonus-symbol" aria-hidden="true">%</div>
|
||||
<div>
|
||||
<h3>Schon im Coaching 1zu1? Dein Vorteil kommt mit.</h3>
|
||||
<p>Mit deinem Coaching-Paket sparst du bei der Ernährungsberatung: Starter 3 %, Standard 5 %, Premium 10 %.</p>
|
||||
<p>
|
||||
Spare mit deinem bestehenden Coaching-Paket bei der
|
||||
Ernährungsberatung.
|
||||
</p>
|
||||
</div>
|
||||
<button type="button" class="bonus-button" data-package="bonus">Rabatte ansehen <span aria-hidden="true">↗</span></button>
|
||||
<button id="bonus-open" class="text-link">Rabatte ansehen</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Detaildialog (öffnet nur per Klick, kein Pop-up beim Laden) -->
|
||||
</section>
|
||||
<section id="ablauf" class="shell section process">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<p class="eyebrow">SO LÄUFT’S AB</p>
|
||||
<h2>Vom ersten Gespräch<br />zu deiner eigenen Routine.</h2>
|
||||
</div>
|
||||
<p>
|
||||
Du musst nicht schon alles wissen. Wir beginnen bei dir und gehen
|
||||
Schritt für Schritt weiter.
|
||||
</p>
|
||||
</div>
|
||||
<ol class="steps">
|
||||
<li>
|
||||
<span class="step-number">01</span>
|
||||
<h3>Dich kennenlernen</h3>
|
||||
<p>
|
||||
Wir besprechen deine Ziele, deinen Alltag und deine sportliche
|
||||
Ausgangslage.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="step-number">02</span>
|
||||
<h3>Gewohnheiten verstehen</h3>
|
||||
<p>
|
||||
Ein Ernährungsprotokoll macht sichtbar, was bereits passt und wo
|
||||
du ansetzen kannst.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="step-number">03</span>
|
||||
<h3>Deinen Weg planen</h3>
|
||||
<p>
|
||||
Du erhältst konkrete Empfehlungen – je nach Paket ergänzt um einen
|
||||
individuellen Ernährungsrahmen.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="step-number">04</span>
|
||||
<h3>Umsetzen & anpassen</h3>
|
||||
<p>
|
||||
Du erprobst die Empfehlungen. In Standard und Premium begleiten
|
||||
Feedback und Anpassungen deinen Weg.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="process-end">
|
||||
<p>Der beste Plan ist der, der in dein Leben passt.</p>
|
||||
<a class="text-link" href="#angebote">Dein Angebot entdecken</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
<div class="shell footer-main">
|
||||
<a
|
||||
class="brand brand-logo"
|
||||
href="https://tri-hub.de/"
|
||||
aria-label="TriHub Startseite"
|
||||
><span class="brand-mark"
|
||||
><img
|
||||
src="assets/images/icons/trihub-logo.jpg"
|
||||
width="1024"
|
||||
height="1024"
|
||||
alt="Trihub – fit und vital ab 50!" /></span
|
||||
></a>
|
||||
<p>Dein sportliches Zuhause ab 50.</p>
|
||||
<a href="https://tri-hub.de/">Zur TriHub-Website</a>
|
||||
</div>
|
||||
<div class="shell footer-note">
|
||||
<span>Projektprototyp · Keine Buchung oder Datenübermittlung</span
|
||||
><span
|
||||
>Ernährungsangebote sind Konzeptvorschläge, keine veröffentlichten
|
||||
TriHub-Tarife.</span
|
||||
>
|
||||
</div>
|
||||
</footer>
|
||||
<dialog id="package-dialog" aria-labelledby="dialog-title">
|
||||
<div class="dialog-inner">
|
||||
<button type="button" class="close-dialog" aria-label="Details schließen">×</button>
|
||||
<p id="dialog-eyebrow" class="angebote-eyebrow"></p>
|
||||
<button class="close-dialog" aria-label="Details schließen">×</button>
|
||||
<p id="dialog-eyebrow" class="eyebrow"></p>
|
||||
<h2 id="dialog-title"></h2>
|
||||
<p id="dialog-description"></p>
|
||||
|
||||
<div id="detail-section">
|
||||
<section id="detail-section">
|
||||
<h3>Deine Begleitung im Überblick</h3>
|
||||
<ul id="dialog-features"></ul>
|
||||
<p class="dialog-hint">Konzeptvorschlag: Leistungsumfang, Kontaktfrequenz, Laufzeit und Preis werden noch abgestimmt.</p>
|
||||
</div>
|
||||
|
||||
<div class="discount-box">
|
||||
<p class="angebote-eyebrow">Dein Coaching-Vorteil</p>
|
||||
<p class="detail-note">
|
||||
Konzeptvorschlag: Leistungsumfang, Kontaktfrequenz, Laufzeit und
|
||||
Preis werden noch abgestimmt.
|
||||
</p>
|
||||
</section>
|
||||
<section class="discount-box">
|
||||
<p class="eyebrow">DEIN COACHING-VORTEIL</p>
|
||||
<h3>Du bist schon im Coaching 1zu1?</h3>
|
||||
<label for="coaching-select">Dein bestehendes Coaching-Paket</label>
|
||||
<select id="coaching-select">
|
||||
<label for="coaching-select">Dein bestehendes Coaching-Paket</label
|
||||
><select id="coaching-select">
|
||||
<option value="0">Noch kein Coaching 1zu1</option>
|
||||
<option value="3">Starter-Coaching</option>
|
||||
<option value="5">Standard-Coaching</option>
|
||||
<option value="10">Premium-Coaching (24 oder 52 Wochen)</option>
|
||||
</select>
|
||||
<p id="discount-result" aria-live="polite"></p>
|
||||
<p class="dialog-hint">Der Rabatt richtet sich nach deinem bestehenden Coaching 1zu1, unabhängig vom gewählten Ernährungsangebot.</p>
|
||||
<a href="https://tri-hub.de/coaching-1zu1" target="_blank" rel="noopener">Coaching 1zu1 bei TriHub ansehen ↗</a>
|
||||
</div>
|
||||
|
||||
<button type="button" class="dialog-done">Zurück zu den Angeboten</button>
|
||||
<div id="discount-result" aria-live="polite"></div>
|
||||
<p class="discount-help">
|
||||
Der Rabatt richtet sich nach deinem bestehenden Coaching 1zu1,
|
||||
unabhängig vom gewählten Ernährungsangebot. Er gilt während der
|
||||
Coaching-Laufzeit auf den aktuellen Verkaufspreis der
|
||||
Ernährungsberatung.
|
||||
</p>
|
||||
<a
|
||||
href="https://tri-hub.de/coaching-1zu1"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>Coaching 1zu1 bei TriHub ansehen</a
|
||||
>
|
||||
</section>
|
||||
<button class="button dialog-done">Zurück zu den Angeboten</button>
|
||||
</div>
|
||||
</dialog>
|
||||
</section>
|
||||
<!-- ========== /US01-02 ========== -->
|
||||
|
||||
|
||||
<!-- ========== US01-03: Ablauf sehen ==========
|
||||
Branch: feature_US01-03 · Styles: css/sections/ablauf.css
|
||||
Nur innerhalb dieser <section> arbeiten. -->
|
||||
<section id="ablauf" aria-labelledby="ablauf-title">
|
||||
<div class="container">
|
||||
|
||||
<div class="ablauf-heading">
|
||||
<div>
|
||||
<p class="ablauf-eyebrow">So läuft’s ab</p>
|
||||
<h2 id="ablauf-title">Vom ersten Gespräch<br>zu deiner eigenen Routine.</h2>
|
||||
</div>
|
||||
<p>Du musst nicht schon alles wissen. Wir beginnen bei dir und gehen Schritt für Schritt weiter.</p>
|
||||
</div>
|
||||
|
||||
<ol class="steps">
|
||||
<li class="step">
|
||||
<span class="step-number" aria-hidden="true">01</span>
|
||||
<h3><span class="sr-only">Schritt 1: </span>Dich kennenlernen</h3>
|
||||
<p>Wir besprechen deine Ziele, deinen Alltag und deine sportliche Ausgangslage.</p>
|
||||
</li>
|
||||
<li class="step">
|
||||
<span class="step-number" aria-hidden="true">02</span>
|
||||
<h3><span class="sr-only">Schritt 2: </span>Gewohnheiten verstehen</h3>
|
||||
<p>Ein Ernährungsprotokoll macht sichtbar, was bereits passt und wo du ansetzen kannst.</p>
|
||||
</li>
|
||||
<li class="step">
|
||||
<span class="step-number" aria-hidden="true">03</span>
|
||||
<h3><span class="sr-only">Schritt 3: </span>Deinen Weg planen</h3>
|
||||
<p>Du erhältst konkrete Empfehlungen – je nach Paket ergänzt um einen individuellen Ernährungsrahmen.</p>
|
||||
</li>
|
||||
<li class="step">
|
||||
<span class="step-number" aria-hidden="true">04</span>
|
||||
<h3><span class="sr-only">Schritt 4: </span>Umsetzen & anpassen</h3>
|
||||
<p>Du erprobst die Empfehlungen. In Standard und Premium begleiten Feedback und Anpassungen deinen Weg.</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="process-end">
|
||||
<p>Der beste Plan ist der, der in dein Leben passt.</p>
|
||||
<a class="process-link" href="#angebote">Dein Angebot entdecken <span aria-hidden="true">↑</span></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
<!-- ========== /US01-03 ========== -->
|
||||
|
||||
</main>
|
||||
|
||||
<script src="js/main.js" defer></script>
|
||||
<script src="js/angebote.js" defer></script> <!-- US01-02 -->
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
160
js/angebote.js
160
js/angebote.js
|
|
@ -1,105 +1,115 @@
|
|||
// US01-02: Paketdetails und Coaching-Rabatt im Dialog (Vorlage: Prototyp)
|
||||
'use strict';
|
||||
|
||||
// Vollständige Paketdetails und Rabattdialog aus TriHub Design Original.
|
||||
(() => {
|
||||
const section = document.querySelector('#angebote');
|
||||
if (!section) return;
|
||||
|
||||
"use strict";
|
||||
const packages = {
|
||||
starter: {
|
||||
name: 'Starter',
|
||||
title: 'Dein erster guter Schritt.',
|
||||
description: 'Du möchtest wissen, wo du stehst und was du konkret verändern kannst? Starter schafft eine persönliche Grundlage für deinen Einstieg.',
|
||||
name: "Starter",
|
||||
title: "Dein erster guter Schritt.",
|
||||
description:
|
||||
"Du möchtest wissen, wo du stehst und was du konkret verändern kannst? Starter schafft eine persönliche Grundlage für deinen Einstieg.",
|
||||
features: [
|
||||
'Gemeinsames Erstgespräch zu Zielen, Training, Alltag und Vorlieben.',
|
||||
'Auswertung eines Ernährungsprotokolls mit Blick auf deine bisherigen Gewohnheiten.',
|
||||
'Persönliche Handlungsempfehlungen für Essen und Trinken im Alltag und rund um dein Training.',
|
||||
'Abschlussgespräch zur Einordnung deiner nächsten Schritte.'
|
||||
]
|
||||
"Gemeinsames Erstgespräch zu Zielen, Training, Alltag und Vorlieben.",
|
||||
"Auswertung eines Ernährungsprotokolls mit Blick auf deine bisherigen Gewohnheiten.",
|
||||
"Persönliche Handlungsempfehlungen für Essen und Trinken im Alltag und rund um dein Training.",
|
||||
"Abschlussgespräch zur Einordnung deiner nächsten Schritte.",
|
||||
],
|
||||
},
|
||||
standard: {
|
||||
name: 'Standard',
|
||||
title: 'Aus guten Vorsätzen wird dein Plan.',
|
||||
description: 'Du möchtest aus einzelnen Empfehlungen eine verlässliche Routine machen? Standard verbindet die Bestandsaufnahme mit einem individuellen Plan und persönlichem Feedback.',
|
||||
name: "Standard",
|
||||
title: "Aus guten Vorsätzen wird dein Plan.",
|
||||
description:
|
||||
"Du möchtest aus einzelnen Empfehlungen eine verlässliche Routine machen? Standard verbindet die Bestandsaufnahme mit einem individuellen Plan und persönlichem Feedback.",
|
||||
features: [
|
||||
'Alle vorgeschlagenen Leistungen aus Starter.',
|
||||
'Ein individueller Ernährungsrahmen für Trainings- und Ruhetage.',
|
||||
'Praktische Mahlzeitenideen, abgestimmt auf deine Vorlieben und deinen Alltag.',
|
||||
'Feedbackgespräche, um Erfahrungen zu besprechen und den Plan gemeinsam anzupassen.'
|
||||
]
|
||||
"Alle vorgeschlagenen Leistungen aus Starter.",
|
||||
"Ein individueller Ernährungsrahmen für Trainings- und Ruhetage.",
|
||||
"Praktische Mahlzeitenideen, abgestimmt auf deine Vorlieben und deinen Alltag.",
|
||||
"Feedbackgespräche, um Erfahrungen zu besprechen und den Plan gemeinsam anzupassen.",
|
||||
],
|
||||
},
|
||||
premium: {
|
||||
name: 'Premium',
|
||||
title: 'Dein Ziel. Ganz persönlich.',
|
||||
description: 'Du möchtest deine Ernährung gezielt auf sportliche Herausforderungen abstimmen? Premium sieht eine besonders enge Begleitung bis in die Wettkampfvorbereitung vor.',
|
||||
name: "Premium",
|
||||
title: "Dein Ziel. Ganz persönlich.",
|
||||
description:
|
||||
"Du möchtest deine Ernährung gezielt auf sportliche Herausforderungen abstimmen? Premium sieht eine besonders enge Begleitung bis in die Wettkampfvorbereitung vor.",
|
||||
features: [
|
||||
'Alle vorgeschlagenen Leistungen aus Standard.',
|
||||
'Eine individuelle Strategie für Essen und Trinken vor, während und nach Wettkämpfen.',
|
||||
'Erprobung der Verpflegung im Training und Anpassung an deine Erfahrungen.',
|
||||
'Engmaschiger persönlicher Austausch und laufende Anpassungen an deine Trainingsphasen.'
|
||||
]
|
||||
}
|
||||
"Alle vorgeschlagenen Leistungen aus Standard.",
|
||||
"Eine individuelle Strategie für Essen und Trinken vor, während und nach Wettkämpfen.",
|
||||
"Erprobung der Verpflegung im Training und Anpassung an deine Erfahrungen.",
|
||||
"Engmaschiger persönlicher Austausch und laufende Anpassungen an deine Trainingsphasen.",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const dialog = section.querySelector('#package-dialog');
|
||||
const select = section.querySelector('#coaching-select');
|
||||
const result = section.querySelector('#discount-result');
|
||||
let trigger = null;
|
||||
|
||||
const dialog = document.querySelector("#package-dialog");
|
||||
const select = document.querySelector("#coaching-select");
|
||||
let trigger;
|
||||
function updateDiscount() {
|
||||
const rate = Number(select.value);
|
||||
const result = document.querySelector("#discount-result");
|
||||
result.replaceChildren();
|
||||
if (rate) {
|
||||
const strong = document.createElement('strong');
|
||||
strong.textContent = `${rate} % Rabatt`;
|
||||
result.append(strong, document.createTextNode(' auf deine Ernährungsberatung.'));
|
||||
} else {
|
||||
result.textContent = 'Mit Coaching 1zu1: Starter 3 %, Standard 5 %, Premium 10 % Rabatt.';
|
||||
const strong = document.createElement("strong");
|
||||
strong.textContent = rate + " % Rabatt";
|
||||
result.append(
|
||||
strong,
|
||||
document.createTextNode(" auf deine Ernährungsberatung."),
|
||||
);
|
||||
} else
|
||||
result.textContent =
|
||||
"Mit Coaching 1zu1: Starter 3 %, Standard 5 %, Premium 10 % Rabatt.";
|
||||
}
|
||||
}
|
||||
|
||||
function openDetails(key, button) {
|
||||
trigger = button;
|
||||
const data = packages[key];
|
||||
|
||||
section.querySelector('#dialog-eyebrow').textContent =
|
||||
data ? `Ernährungsberatung · ${data.name}` : 'Coaching 1zu1 · Bonusregelung';
|
||||
section.querySelector('#dialog-title').textContent =
|
||||
data ? data.title : 'Dein Coaching zahlt sich aus.';
|
||||
section.querySelector('#dialog-description').textContent = data
|
||||
document.querySelector("#dialog-eyebrow").textContent = data
|
||||
? "ERNÄHRUNGSBERATUNG · " + data.name.toUpperCase()
|
||||
: "COACHING 1ZU1 · BONUSREGELUNG";
|
||||
document.querySelector("#dialog-title").textContent = data
|
||||
? data.title
|
||||
: "Dein Coaching zahlt sich aus.";
|
||||
document.querySelector("#dialog-description").textContent = data
|
||||
? data.description
|
||||
: 'Dein bestehendes Coaching-Paket bringt dir einen Preisvorteil bei der Ernährungsberatung. Wähle es aus und sieh deinen Rabatt.';
|
||||
|
||||
section.querySelector('#detail-section').hidden = !data;
|
||||
const list = section.querySelector('#dialog-features');
|
||||
: "Dein bestehendes Coaching-Paket bringt dir einen Preisvorteil bei der Ernährungsberatung. Wähle es aus und entdecke deinen Rabatt.";
|
||||
document.querySelector("#detail-section").hidden = !data;
|
||||
const list = document.querySelector("#dialog-features");
|
||||
list.replaceChildren();
|
||||
if (data) {
|
||||
if (data)
|
||||
data.features.forEach((text) => {
|
||||
const li = document.createElement('li');
|
||||
const li = document.createElement("li");
|
||||
li.textContent = text;
|
||||
list.append(li);
|
||||
});
|
||||
}
|
||||
|
||||
updateDiscount();
|
||||
dialog.showModal();
|
||||
}
|
||||
|
||||
section.querySelectorAll('[data-package]').forEach((button) => {
|
||||
button.addEventListener('click', () => openDetails(button.dataset.package, button));
|
||||
document
|
||||
.querySelectorAll(".package-open")
|
||||
.forEach((button) =>
|
||||
button.addEventListener("click", () =>
|
||||
openDetails(button.dataset.package, button),
|
||||
),
|
||||
);
|
||||
document
|
||||
.querySelector("#bonus-open")
|
||||
.addEventListener("click", (event) =>
|
||||
openDetails(null, event.currentTarget),
|
||||
);
|
||||
select.addEventListener("change", updateDiscount);
|
||||
document
|
||||
.querySelectorAll(".close-dialog,.dialog-done")
|
||||
.forEach((button) =>
|
||||
button.addEventListener("click", () => dialog.close()),
|
||||
);
|
||||
dialog.addEventListener("click", (event) => {
|
||||
if (event.target === dialog) {
|
||||
const r = dialog.getBoundingClientRect();
|
||||
if (
|
||||
event.clientX < r.left ||
|
||||
event.clientX > r.right ||
|
||||
event.clientY < r.top ||
|
||||
event.clientY > r.bottom
|
||||
)
|
||||
dialog.close();
|
||||
}
|
||||
});
|
||||
|
||||
select.addEventListener('change', updateDiscount);
|
||||
|
||||
section.querySelectorAll('.close-dialog, .dialog-done').forEach((button) => {
|
||||
button.addEventListener('click', () => dialog.close());
|
||||
});
|
||||
|
||||
// Klick auf den abgedunkelten Hintergrund schließt den Dialog
|
||||
dialog.addEventListener('click', (event) => {
|
||||
if (event.target === dialog) dialog.close();
|
||||
});
|
||||
|
||||
// Fokus zurück auf den auslösenden Button (Barrierefreiheit)
|
||||
dialog.addEventListener('close', () => trigger?.focus());
|
||||
dialog.addEventListener("close", () => trigger?.focus());
|
||||
})();
|
||||
|
|
|
|||
90
js/main.js
90
js/main.js
|
|
@ -1,3 +1,87 @@
|
|||
// Einstiegspunkt für Skripte.
|
||||
// Feature-Code in eigene Dateien auslagern (z. B. js/scroll.js für US01-01)
|
||||
// und hier bzw. in index.html einbinden.
|
||||
// Mobile Navigation und alle Scrollanimationen aus TriHub Design Original.
|
||||
"use strict";
|
||||
(() => {
|
||||
const menu = document.querySelector(".menu-toggle"),
|
||||
nav = document.querySelector("#mobile-nav");
|
||||
menu.addEventListener("click", () => {
|
||||
const open = menu.getAttribute("aria-expanded") !== "true";
|
||||
menu.setAttribute("aria-expanded", String(open));
|
||||
menu.setAttribute("aria-label", open ? "Menü schließen" : "Menü öffnen");
|
||||
nav.hidden = !open;
|
||||
});
|
||||
nav.querySelectorAll("a").forEach((a) =>
|
||||
a.addEventListener("click", () => {
|
||||
nav.hidden = true;
|
||||
menu.setAttribute("aria-expanded", "false");
|
||||
menu.setAttribute("aria-label", "Menü öffnen");
|
||||
}),
|
||||
);
|
||||
|
||||
// Progressive enhancement: content stays visible without JS or animation support.
|
||||
(() => {
|
||||
const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
|
||||
if (!("IntersectionObserver" in window) || !Element.prototype.animate)
|
||||
return;
|
||||
const running = new Map();
|
||||
const played = new WeakSet();
|
||||
const delays = new WeakMap();
|
||||
const targets = [
|
||||
...document.querySelectorAll(
|
||||
".hero-copy > *, .hero-visual, .section-heading, .benefit-grid > article, " +
|
||||
".concept-note, .package-grid > article, .coaching-banner, .steps > li, .process-end",
|
||||
),
|
||||
];
|
||||
document
|
||||
.querySelectorAll(".hero-copy, .benefit-grid, .package-grid, .steps")
|
||||
.forEach((group) => {
|
||||
[...group.children].forEach((child, index) =>
|
||||
delays.set(child, Math.min(index * 80, 240)),
|
||||
);
|
||||
});
|
||||
function reveal(element) {
|
||||
if (played.has(element)) return;
|
||||
played.add(element);
|
||||
if (reducedMotion.matches) return;
|
||||
const animation = element.animate(
|
||||
[
|
||||
{ opacity: 0, transform: "translateY(24px)" },
|
||||
{ opacity: 1, transform: "translateY(0)" },
|
||||
],
|
||||
{
|
||||
duration: 720,
|
||||
delay: delays.get(element) || 0,
|
||||
easing: "cubic-bezier(.22, 1, .36, 1)",
|
||||
fill: "backwards",
|
||||
},
|
||||
);
|
||||
running.set(element, animation);
|
||||
const cleanup = () => {
|
||||
if (running.get(element) === animation) running.delete(element);
|
||||
};
|
||||
animation.onfinish = cleanup;
|
||||
animation.oncancel = cleanup;
|
||||
}
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry.isIntersecting) return;
|
||||
observer.unobserve(entry.target);
|
||||
// A direct anchor jump must not animate already-scrolled-past content.
|
||||
if (entry.boundingClientRect.bottom > 0) reveal(entry.target);
|
||||
});
|
||||
},
|
||||
{ threshold: 0, rootMargin: "0px 0px -24px 0px" },
|
||||
);
|
||||
targets.forEach((element) => observer.observe(element));
|
||||
// Keyboard users never wait for a focused control to become visible.
|
||||
document.addEventListener("focusin", (event) => {
|
||||
running.forEach((animation, element) => {
|
||||
if (element.contains(event.target)) animation.cancel();
|
||||
});
|
||||
});
|
||||
reducedMotion.addEventListener("change", () => {
|
||||
if (reducedMotion.matches)
|
||||
running.forEach((animation) => animation.cancel());
|
||||
});
|
||||
})();
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in New Issue