integration/ernaehrung-review #2

Merged
3024588 merged 23 commits from integration/ernaehrung-review into main 2026-09-29 10:40:47 +02:00
19 changed files with 1958 additions and 14 deletions

BIN
.DS_Store vendored 100644

Binary file not shown.

197
css/berater.css 100644
View File

@ -0,0 +1,197 @@
/* Ahmad: Styles bleiben in .berater-section; Karten passen auch auf Mobilgeraete. */
/* ==========================================================
Globale Design-Variablen - Angepasst an die Design-DNA von Tri-hub
========================================================== */
.berater-section {
/* Farben und variabel-namen wurden standarttisiert siehe Kommentare */
--background: ##0714198a; /* früher "--bg-dark-1" */
--background-rgb: 7 20 25; /* gleiche Basisfarbe wie --background,
aber ohne fixes Alpha – für Gradient-Stops
wird benutzt um Bildern einen gradient zu verpassen */
--background-panel: #152027; /* früher "--bg-dark-2" */
--accent: #4597A3; /* früher "accent-teal" */
--text-primary: #ffffff; /* früher "text-white" */
--text-muted: #94A3B8;
--font-display: 'Inter', system-ui, sans-serif;
--font-body: 'Inter', system-ui, sans-serif;
}
.berater-section {
margin: 0;
/* Padding vereinheitlicht, um dem Pakete-Bereich zu entsprechen */
padding: 5rem 1.5rem;
font-family: var(--font-body);
background-color: var(--background);
color: var(--text-white);
display: flex;
flex-direction: column;
align-items: center;
/* Gesamten Inhalt vertikal zentrieren */
}
/* =========================================
Styling für Header (Titel und Untertitel) passend zu den Paketen
========================================= */
.berater-section .section-header {
text-align: center;
max-width: 42rem;
margin: 0 auto 3rem;
}
.berater-section .section-title {
font-family: var(--font-display);
font-weight: 700;
font-size: clamp(1.8rem, 3vw, 2.4rem);
color: var(--text-white);
margin: 0 0 0.75rem;
}
.berater-section .section-subtitle {
color: var(--text-muted);
line-height: 1.6;
margin: 0;
}
/* =========================================
Styling für den Container und die Berater-Karten
========================================= */
.berater-section .berater-container {
display: flex;
gap: 30px;
width: 100%;
max-width: 1000px;
flex-wrap: wrap;
justify-content: center;
}
.berater-section .berater-card {
background-color: var(--background-panel);
/* Leichte Umrandung hinzugefügt, ähnlich wie bei den Pakete-Karten */
border: 1px solid rgba(248, 250, 252, 0.08);
/* Border-Radius angepasst, passend zu den Paketen */
border-radius: 14px;
padding: 24px;
width: min(380px, 100%);
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.berater-section .berater-image-wrapper {
background-color: var(--background);
border-radius: 10px;
padding: 10px;
margin-bottom: 24px;
}
.berater-section .berater-image-wrapper img {
width: 100%;
height: 350px;
object-fit: cover;
border-radius: 8px;
display: block;
}
.berater-section .berater-name {
margin: 0 0 8px 0;
font-family: var(--font-display);
font-size: 1.4rem;
/* Schriftgröße des Namens harmonisiert */
font-weight: 600;
color: var(--text-white);
}
.berater-section .berater-rolle {
margin: 0 0 24px 0;
font-family: var(--font-body);
font-size: 14px;
color: var(--accent);
text-transform: uppercase;
letter-spacing: 1.5px;
font-weight: 600;
}
.berater-section .berater-bio-box {
/* Hintergrund entfernt, um sich nahtlos in die Karte einzufügen */
background-color: transparent;
border-radius: 16px;
/* Überschüssiges Padding entfernt */
padding: 0;
flex-grow: 1;
}
.berater-section .bio-title {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
}
.berater-section .bio-text {
margin: 0;
font-size: 15px;
line-height: 1.6;
color: var(--text-muted);
}
/* =========================================
Styling für dynamische Listen (z. B. Zertifikate)
========================================= */
.berater-section .berater-liste {
margin: 8px 0 0 0;
padding-left: 1.4rem;
color: var(--text-muted);
font-size: 14px;
line-height: 1.6;
list-style: none;
/* Standard-Listenpunkte entfernt für benutzerdefiniertes Styling */
}
.berater-section .berater-liste li {
position: relative;
margin-bottom: 0.7rem;
color: var(--text-primary);
}
/* Grünes quadratisches Aufzählungszeichen hinzugefügt, exakt wie im Pakete-Bereich */
.berater-section .berater-liste li::before {
content: "";
position: absolute;
left: -1.4rem;
top: 0.4em;
width: 8px;
height: 8px;
border-radius: 2px;
background: var(--accent);
}
/* =========================================
Styling für dynamische Links (Buttons)
========================================= */
.berater-section .berater-links {
margin-top: 20px;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.berater-section .berater-link-btn {
display: inline-block;
font-family: var(--font-body);
font-weight: 600;
font-size: 0.95rem;
color: var(--background);
background: var(--accent);
border: none;
border-radius: 8px;
padding: 0.85rem 1rem;
cursor: pointer;
text-decoration: none;
transition: filter 0.15s ease;
}
.berater-section .berater-link-btn:hover,
.berater-section .berater-link-btn:focus-visible {
filter: brightness(1.1);
}

419
css/beratung.css 100644
View File

@ -0,0 +1,419 @@
/* Dennis: Seitenweite Regeln sind auf den Beratungsbereich begrenzt. */
.beratung-bereich {
/* Farben – Tokens von tri-hub.de (Hex-Fallback + oklch) */
--background: #0714198a;
--background-rgb: 7 20 25; /* gleiche Basisfarbe wie --background,
aber ohne fixes Alpha – für Gradient-Stops
wird benutzt um Bildern einen gradient zu verpassen */
--background-panel: #152027; /* früher "surface" */
--text-primary: #ffffff; /* früher "foreground" */
--text-muted: #9ba7aa; /* früher "muted-fg" */
--accent: #4597A3; /* früher "primary" */
--border: rgba(234, 8, 8, 0.1);
/* Typografie */
--font-display: "Sora", sans-serif;
--font-body: "DM Sans", Arial, Helvetica, sans-serif;
/* Layout */
--container: 1120px;
--radius: 1.1rem;
}
/* ---------- Basic ---------- */
.beratung-bereich,
.beratung-bereich *,
.beratung-bereich::before,
.beratung-bereich *::before,
.beratung-bereich::after,
.beratung-bereich *::after {
box-sizing: border-box;
}
.beratung-bereich {
scroll-behavior: smooth;
}
.beratung-bereich {
margin: 0;
background-color: var(--background);
color: var(--foreground);
font-family: var(--font-body);
line-height: 1.625;
-webkit-font-smoothing: antialiased;
position: relative;
isolation: isolate;
}
/* Licht*/
.beratung-bereich::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
background:
radial-gradient(900px 520px at 78% -10%, rgba(0, 179, 194, 0.13), transparent 65%),
radial-gradient(700px 480px at -10% 30%, rgba(35, 137, 148, 0.1), transparent 60%),
radial-gradient(600px 420px at 90% 95%, rgba(247, 194, 48, 0.05), transparent 60%);
pointer-events: none;
}
.beratung-bereich h1,
.beratung-bereich h2,
.beratung-bereich h3 {
margin-top: 0;
font-family: var(--font-display);
color: var(--foreground);
line-height: 1.2;
letter-spacing: -0.01em;
}
.beratung-bereich p {
margin: 0 0 1em;
}
.beratung-bereich .container {
width: min(100% - 48px, var(--container));
margin-inline: auto;
}
/* ---------- Typo-Helfer ---------- */
.beratung-bereich .kicker {
display: inline-flex;
align-items: center;
gap: 10px;
font-size: 0.78rem;
font-weight: 600;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 18px;
}
.beratung-bereich .kicker::before {
content: "";
width: 28px;
height: 2px;
border-radius: 2px;
background: var(--accent);
}
.beratung-bereich .lead {
font-size: 1.15rem;
color: var(--text-muted);
max-width: 660px;
}
.beratung-bereich .muted {
color: var(--text-muted);
}
/* ---------- Button ---------- */
.beratung-bereich .btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.8rem 1.5rem;
border-radius: 999px;
font-family: var(--font-body);
font-weight: 600;
font-size: 0.95rem;
line-height: 1.2;
text-decoration: none;
border: 1px solid transparent;
cursor: pointer;
transition: transform 0.18s ease, box-shadow 0.18s ease,
background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.beratung-bereich .btn-accent {
background: var(--accent);
color: #03242b;
}
.beratung-bereich .btn-accent:hover {
transform: translateY(-1px);
box-shadow: 0 10px 28px rgba(0, 179, 194, 0.28);
}
/* ---------- Sektionen ---------- */
.beratung-bereich .section {
padding: 96px 0;
}
.beratung-bereich .section-head {
max-width: 720px;
margin-bottom: 56px;
}
.beratung-bereich .section-head h2 {
font-size: clamp(1.9rem, 4vw, 2.7rem);
margin-bottom: 18px;
}
/* ---------- Boxen & Grid ---------- */
.beratung-bereich .grid-2 {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24px;
}
.beratung-bereich .box {
/* Lange Woerter duerfen die Karten auf kleinen Displays nicht verbreitern. */
min-width: 0;
overflow-wrap: anywhere;
hyphens: auto;
background-color: var(--background-panel);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 32px;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
/* ---------- Checklisten ---------- */
.beratung-bereich .check-list {
list-style: none;
padding: 0;
margin: 20px 0 0;
display: grid;
gap: 12px;
}
.beratung-bereich .check-list li {
position: relative;
padding-left: 34px;
color: var(--foreground);
}
.beratung-bereich .check-list li::before {
content: "✓";
position: absolute;
left: 0;
top: 0;
color: var(--accent);
font-weight: bold;
font-size: 1.1rem;
}
/* ---------- Ablauf-Schritte ---------- */
.beratung-bereich .beratung-ablauf {
list-style: none;
counter-reset: schritt;
padding: 0;
margin: 24px 0 0;
display: grid;
gap: 20px;
}
.beratung-bereich .beratung-ablauf li {
counter-increment: schritt;
position: relative;
padding-left: 60px;
}
.beratung-bereich .beratung-ablauf li::before {
content: counter(schritt, decimal-leading-zero);
position: absolute;
left: 0;
top: 2px;
display: grid;
place-items: center;
width: 44px;
height: 44px;
border-radius: 50%;
font-family: var(--font-display);
font-size: 0.9rem;
font-weight: 600;
color: var(--accent);
background: rgba(0, 179, 194, 0.1);
border: 1px solid rgba(0, 179, 194, 0.3);
}
.beratung-bereich .beratung-ablauf strong {
display: block;
font-family: var(--font-display);
font-size: 1.02rem;
color: var(--foreground);
margin-bottom: 4px;
}
.beratung-bereich .beratung-ablauf p {
margin: 0;
color: var(--text-muted);
font-size: 0.95rem;
}
/* ---------- CTA-Band ---------- */
.beratung-bereich .cta-band {
margin-top: 96px;
padding: 64px 40px;
text-align: center;
border: 1px solid var(--border);
border-radius: calc(var(--radius) + 8px);
background: linear-gradient(135deg, #071216, #0a1b1f 46%, #050e16);
}
.beratung-bereich .cta-band h2 {
font-size: clamp(1.8rem, 4vw, 2.5rem);
margin-bottom: 16px;
}
.beratung-bereich .cta-band p {
color: var(--text-muted);
max-width: 560px;
margin-inline: auto;
}
/* ---------- Footer ---------- */
.beratung-bereich .logo {
font-family: var(--font-display);
font-weight: 700;
font-size: 1.35rem;
letter-spacing: -0.02em;
color: var(--foreground);
text-decoration: none;
white-space: nowrap;
}
.beratung-bereich .logo span {
color: var(--accent);
}
.beratung-bereich .site-footer {
margin-top: 96px;
padding: 64px 0 40px;
border-top: 1px solid var(--border);
background: rgba(255, 255, 255, 0.015);
}
.beratung-bereich .footer-grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 48px;
}
.beratung-bereich .footer-brand p {
color: var(--text-muted);
font-size: 0.95rem;
max-width: 340px;
margin-top: 14px;
}
.beratung-bereich .footer-col h3 {
font-size: 0.85rem;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 16px;
}
.beratung-bereich .footer-col ul {
list-style: none;
margin: 0;
padding: 0;
}
.beratung-bereich .footer-col a {
display: block;
padding: 5px 0;
color: var(--text-muted);
text-decoration: none;
font-size: 0.92rem;
transition: color 0.15s ease;
}
.beratung-bereich .footer-col a:hover {
color: var(--foreground);
}
.beratung-bereich .footer-legal {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 12px;
margin-top: 48px;
padding-top: 24px;
border-top: 1px solid var(--border);
color: var(--text-muted);
font-size: 0.85rem;
}
.beratung-bereich .footer-legal a {
color: inherit;
text-decoration: none;
}
.beratung-bereich .footer-legal a:hover {
color: var(--foreground);
}
/* ---------- Scroll-Reveal ---------- */
.beratung-bereich .reveal {
opacity: 0;
transform: translateY(18px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.beratung-bereich .reveal.visible {
opacity: 1;
transform: none;
}
/* ---------- Responsiv ---------- */
@media (max-width: 980px) {
.beratung-bereich .footer-grid {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 760px) {
.beratung-bereich .grid-2 {
grid-template-columns: minmax(0, 1fr);
}
.beratung-bereich .section {
padding: 72px 0;
}
.beratung-bereich .footer-grid {
grid-template-columns: 1fr;
gap: 32px;
}
.beratung-bereich .cta-band {
padding: 48px 24px;
}
}
/* ---------- Reduzierte Bewegung ---------- */
@media (prefers-reduced-motion: reduce) {
.beratung-bereich {
scroll-behavior: auto;
}
.beratung-bereich .reveal {
opacity: 1;
transform: none;
transition: none;
}
.beratung-bereich,
.beratung-bereich * {
transition-duration: 0.01ms !important;
}
}

200
css/leistungen.css 100644
View File

@ -0,0 +1,200 @@
/* Vincent: Gemeinsame Klassennamen und Variablen sind auf .pakete begrenzt. */
/* ==========================================================
tri-hub.de – Farben angeglichen an Produktübersicht (Shahnam)
Hintergrund: #071419 / #1b2830
Akzent: #4597A3 (gedämpftes Cyan-Teal)
Primärtext: #ffffff / #b7bec2 / #7e858a
Typografie: Sora (Display) + Inter (Body)
Werte per Pixel-Sampling aus dem Screenshot der Produktübersicht ermittelt.
========================================================== */
.pakete {
/* Werte per Pixel-Sampling aus dem Referenz-Screenshot (Produktübersicht) übernommen */
--background: #0714198a; /* früher "bg-dark */
--background-rgb: 7 20 25; /* gleiche Basisfarbe wie --background,
aber ohne fixes Alpha – für Gradient-Stops
wird benutzt um Bildern einen gradient zu verpassen */
--background-panel: #152027; /* früher "primary */
--accent: #4597A3;
--accent-soft: rgba(69, 151, 163, 0.14);
--text-primary: #ffffff;
--text-muted: #7e858a;
--font-display: "Sora", "Inter", system-ui, sans-serif;
--font-body: "Inter", system-ui, sans-serif;
}
.pakete,
.pakete * {
box-sizing: border-box;
}
.pakete {
margin: 0;
background: var(--background);
color: var(--text-primary);
font-family: var(--font-body);
}
/* ---------- Leistungsübersicht ---------- */
.pakete {
padding: 5rem 1.5rem;
max-width: 1120px;
margin: 0 auto;
}
.pakete .pakete__intro {
text-align: center;
max-width: 42rem;
margin: 0 auto 3rem;
}
.pakete .pakete__titel {
font-family: var(--font-display);
font-weight: 700;
font-size: clamp(1.8rem, 3vw, 2.4rem);
color: var(--text-primary);
margin: 0 0 0.75rem;
}
.pakete .pakete__text {
color: var(--text-muted);
line-height: 1.6;
margin: 0;
}
/* Kästchen nebeneinander, jede Karte für sich */
.pakete .pakete__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
align-items: stretch;
}
.pakete .paket-karte {
display: flex;
flex-direction: column;
background: var(--background-panel);
border: 1px solid rgba(248, 250, 252, 0.08);
border-radius: 14px;
padding: 2rem 1.75rem;
position: relative;
}
.pakete .paket-karte--empfohlen {
border-color: var(--accent);
box-shadow: 0 0 0 1px var(--accent-soft);
}
.pakete .paket-karte--ausgewaehlt {
border-color: var(--accent);
box-shadow: 0 0 0 2px var(--accent);
}
.pakete .paket-karte__badge {
display: inline-block;
background: var(--accent-soft);
color: var(--accent);
border: 1px solid var(--accent);
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 0.35rem 0.9rem;
border-radius: 999px;
margin: 0 0 1rem;
}
.pakete .paket-karte__name {
font-family: var(--font-display);
font-weight: 600;
font-size: 1.4rem;
color: var(--text-primary);
margin: 0 0 0.5rem;
}
.pakete .paket-karte__preis {
margin: 0 0 0.75rem;
display: flex;
align-items: baseline;
gap: 0.35rem;
}
.pakete .paket-karte__betrag {
font-family: var(--font-display);
font-size: 2rem;
font-weight: 700;
color: var(--text-primary);
}
.pakete .paket-karte__zeitraum {
color: var(--text-muted);
font-size: 0.9rem;
}
.pakete .paket-karte__beschreibung {
color: var(--text-muted);
line-height: 1.55;
margin: 0 0 1.5rem;
min-height: 3.3em;
}
.pakete .paket-karte__leistungen {
list-style: none;
margin: 0 0 2rem;
padding: 0;
flex-grow: 1;
}
.pakete .paket-karte__leistungen li {
position: relative;
padding-left: 1.4rem;
margin-bottom: 0.7rem;
line-height: 1.4;
color: var(--text-primary);
}
.pakete .paket-karte__leistungen li::before {
content: "";
position: absolute;
left: 0;
top: 0.5em;
width: 8px;
height: 8px;
border-radius: 2px;
background: var(--accent);
}
.pakete .paket-karte__cta {
font-family: var(--font-body);
font-weight: 600;
font-size: 0.95rem;
color: var(--text-primary);
background: var(--accent);
border: none;
border-radius: 8px;
padding: 0.85rem 1rem;
cursor: pointer;
transition: filter 0.15s ease;
}
.pakete .paket-karte__cta:hover,
.pakete .paket-karte__cta:focus-visible {
filter: brightness(1.1);
}
.pakete .paket-karte__cta:focus-visible {
outline: 2px solid var(--text-primary);
outline-offset: 2px;
}
@media (max-width: 860px) {
.pakete .pakete__grid {
grid-template-columns: 1fr;
}
.pakete .paket-karte--empfohlen {
order: -1;
}
}

View File

@ -0,0 +1,412 @@
/* Shahnam: Styles und Variablen bleiben innerhalb der Produktuebersicht. */
.produktuebersicht {
color-scheme: dark;
--background: #0714198a;
--background-rgb: 7 20 25; /* gleiche Basisfarbe wie --background,
aber ohne fixes Alpha – für Gradient-Stops
wird benutzt um Bildern einen gradient zu verpassen */
/* es fehlt eine andere backgroundfarbe für das Panel */
--accent: #4597A3;
--text-primary: #ffffff; /*früher "text"*/
--text-muted: #b7bec2; /*früher "muted"*/
--border: rgb(255 255 255 / 16%);
font-family: system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
color: var(--text-primary);
background: var(--background);
}
.produktuebersicht,
.produktuebersicht *,
.produktuebersicht::before,
.produktuebersicht *::before,
.produktuebersicht::after,
.produktuebersicht *::after {
box-sizing: border-box;
}
.produktuebersicht {
display: flex;
flex-direction: column;
min-height: 100vh;
min-height: 100svh;
margin: 0;
line-height: 1.6;
}
.produktuebersicht p,
.produktuebersicht h1 {
margin: 0;
}
.produktuebersicht .container {
width: min(1680px, calc(100% - clamp(40px, 10vw, 192px)));
margin-inline: auto;
}
.produktuebersicht .site-header {
border-top: 3px solid var(--accent);
}
.produktuebersicht .brand {
display: flex;
align-items: center;
gap: 20px;
min-height: 96px;
padding-block: 8px;
}
.produktuebersicht .brand__logo {
display: grid;
place-items: center;
flex-shrink: 0;
width: 90px;
height: 80px;
border-radius: 22px;
background: #fff;
}
.produktuebersicht .brand__logo img {
display: block;
width: 60px;
height: 60px;
object-fit: contain;
}
.produktuebersicht .brand__text {
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.produktuebersicht .brand__name {
color: #8a9093;
font-size: 14px;
font-weight: 650;
line-height: 1.4;
letter-spacing: 0.25em;
}
.produktuebersicht .brand__label {
color: var(--text-muted);
font-size: 17px;
font-weight: 600;
line-height: 1.4;
}
.produktuebersicht .produktuebersicht__main {
display: flex;
flex: 1;
}
.produktuebersicht .hero {
position: relative;
isolation: isolate;
display: flex;
flex: 1;
min-width: 0;
border-block: 1px solid var(--border);
}
.produktuebersicht .hero__image,
.produktuebersicht .hero::after {
position: absolute;
z-index: -1;
inset: 0;
width: 100%;
height: 100%;
}
.produktuebersicht .hero__image {
object-fit: cover;
object-position: center 42%;
}
.produktuebersicht .hero::after {
/*background: var(--background);
/* ich bekomme das nicht richtig hin muss Shahmad machen */
background:
linear-gradient(0deg, rgb(var(--background-rgb) / 96%), transparent 42%),
linear-gradient(90deg, rgb(var(--background-rgb) / 94%) 0%, rgb(var(--background-rgb) / 79%) 35%, rgb(var(--background-rgb) / 38%) 72%, rgb(var(--background-rgb) / 25%) 100%);
content: "";
}
.produktuebersicht .hero__inner {
display: flex;
flex-direction: column;
padding-block: clamp(32px, 5vh, 64px) 28px;
}
.produktuebersicht .hero__content {
width: min(100%, 1000px);
margin-block: auto;
padding-block: 24px 64px;
}
.produktuebersicht .hero__eyebrow {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 26px;
color: #4597A3;
font-size: 11px;
font-weight: 650;
letter-spacing: 0.16em;
text-transform: uppercase;
}
.produktuebersicht .hero__eyebrow::before {
width: 28px;
height: 1px;
flex-shrink: 0;
background: currentColor;
content: "";
}
.produktuebersicht h1 {
max-width: 100%;
font-size: clamp(42px, 4.9vw, 88px);
font-weight: 550;
line-height: 1.1;
letter-spacing: -0.055em;
text-wrap: balance;
overflow-wrap: break-word;
}
.produktuebersicht h1 span {
display: block;
margin-top: 8px;
color: var(--accent);
}
.produktuebersicht .hero__description {
max-width: 65ch;
margin-top: 30px;
color: #d1d7df;
font-size: clamp(16px, 1.15vw, 19px);
line-height: 1.85;
}
.produktuebersicht .hero__details {
display: grid;
grid-template-columns: minmax(0, 1fr) 250px;
align-items: center;
gap: 48px;
padding-top: 28px;
border-top: 1px solid var(--border);
}
.produktuebersicht .benefits {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 24px;
margin: 0;
padding: 0;
list-style: none;
}
.produktuebersicht .benefits li {
display: flex;
align-items: baseline;
gap: 14px;
}
.produktuebersicht .benefits__number {
color: var(--accent);
font-size: 11px;
font-variant-numeric: tabular-nums;
}
.produktuebersicht .benefits p {
font-size: 14px;
font-weight: 500;
}
.produktuebersicht .benefits p span {
display: block;
margin-top: 4px;
color: var(--text-muted);
font-size: 12px;
font-weight: 400;
}
.produktuebersicht .hero__caption {
padding-left: 24px;
border-left: 1px solid var(--border);
}
.produktuebersicht .hero__caption-label {
color: var(--text-muted);
font-size: 10px;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.produktuebersicht .hero__slogan {
margin-top: 8px;
font-size: 22px;
font-weight: 450;
line-height: 1.4;
letter-spacing: -0.025em;
}
.produktuebersicht .site-footer__inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
min-height: 88px;
padding-block: 24px;
font-size: 12px;
}
.produktuebersicht .site-footer__inner p > span {
margin-left: 12px;
color: var(--text-muted);
}
.produktuebersicht .site-footer__note {
display: flex;
align-items: center;
gap: 9px;
color: var(--text-muted);
}
.produktuebersicht .site-footer__note > span {
width: 5px;
height: 5px;
flex-shrink: 0;
border-radius: 50%;
background: var(--accent);
}
@media (max-width: 1100px) {
.produktuebersicht .hero__image {
object-position: 80% center;
}
.produktuebersicht .hero::after {
background:
linear-gradient(0deg, rgb(var(--background-rgb) / 96%), transparent 42%),
linear-gradient(90deg, rgb(var(--background-rgb) / 92%), rgb(var(--background-rgb) / 70%) 65%, rgb(var(--background-rgb) / 48%));
}
.produktuebersicht .hero__content {
max-width: 85%;
}
.produktuebersicht .hero__details {
grid-template-columns: minmax(0, 1fr) 200px;
gap: 28px;
}
.produktuebersicht .benefits li {
flex-direction: column;
gap: 8px;
}
}
@media (max-width: 700px) {
.produktuebersicht .brand {
min-height: 78px;
gap: 12px;
}
.produktuebersicht .brand__logo {
width: 66px;
height: 62px;
border-radius: 17px;
}
.produktuebersicht .brand__logo img {
width: 46px;
height: 46px;
}
.produktuebersicht .brand__name {
font-size: 12px;
}
.produktuebersicht .brand__label {
font-size: 13px;
}
.produktuebersicht .hero__image {
object-position: 85% center;
}
.produktuebersicht .hero::after {
background: linear-gradient(90deg, rgb(var(--background-rgb) / 87%), rgb(var(--background-rgb) / 65%)),
linear-gradient(0deg, var(--background), transparent 55%);
}
.produktuebersicht .hero__content {
max-width: 100%;
padding-block: 12px 40px;
}
.produktuebersicht .hero__eyebrow {
gap: 8px;
font-size: 10px;
letter-spacing: 0.11em;
}
.produktuebersicht .hero__eyebrow::before {
width: 20px;
}
.produktuebersicht .hero__description {
margin-top: 24px;
}
.produktuebersicht .hero__details {
grid-template-columns: 1fr;
gap: 28px;
padding-top: 24px;
}
.produktuebersicht .benefits {
gap: 16px;
}
.produktuebersicht .benefits p {
font-size: 12px;
}
.produktuebersicht .hero__caption {
padding-left: 16px;
border-left-color: var(--accent);
}
.produktuebersicht .hero__slogan {
font-size: 20px;
}
.produktuebersicht .site-footer__inner {
align-items: flex-start;
flex-direction: column;
gap: 14px;
}
.produktuebersicht .site-footer__inner p > span {
margin-left: 0;
}
.produktuebersicht .site-footer__inner > p:first-child span {
display: block;
margin-top: 4px;
}
}
@media (max-width: 360px) {
.produktuebersicht .benefits {
grid-template-columns: 1fr;
}
.produktuebersicht .benefits li {
flex-direction: row;
gap: 14px;
}
}

10
css/site.css 100644
View File

@ -0,0 +1,10 @@
:root {
color-scheme: dark;
font-family: system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
color: #f8fafc;
background: #0714198a;
}
body {
margin: 0;
}

View File

@ -0,0 +1,105 @@
# Ernährungsseite – Integrationsänderungen
## Dateien und Zuständigkeiten
Die Bereiche stehen gemeinsam in [index.html](../index.html), in dieser Reihenfolge: Produktübersicht → Pakete → Berater → Beratungsinformationen mit Footer.
| Bereich | CSS | JavaScript | Daten |
| --- | --- | --- | --- |
| Shahnam: Produktübersicht | [produktuebersicht.css](../css/produktuebersicht.css) | – | Direkt im HTML |
| Vincent: Pakete | [leistungen.css](../css/leistungen.css) | [leistungen.js](../js/leistungen.js) | [pakete.json](../json/pakete.json) |
| Ahmad: Berater | [berater.css](../css/berater.css) | [berater.js](../js/berater.js) | [berater.json](../json/berater.json) |
| Dennis: Beratung und Footer | [beratung.css](../css/beratung.css) | [beratung.js](../js/beratung.js) | Direkt im HTML |
[site.css](../css/site.css) enthält nur die gemeinsame Seitengrundlage: Hintergrund, Textfarbe, Standardschrift und den entfernten Außenabstand des `body`.
### Umbenannte und verschobene Dateien
Die alten Pfade beziehen sich auf den jeweiligen Quellbranch.
| Bereich | Vorher | Jetzt |
| --- | --- | --- |
| Shahnam | `css/style.css` | `css/produktuebersicht.css` |
| Vincent | `css/style.css` | `css/leistungen.css` |
| Vincent | `js/script.js` | `js/leistungen.js` |
| Ahmad | `css/style.css` | `css/berater.css` |
| Dennis | `style.css` | `css/beratung.css` |
| Dennis | `script.js` | `js/beratung.js` |
| Beraterbilder | `img/relindis_agethen.png` | `images/relindis_agethen.png` |
| Beraterbilder | `img/relindis_agethen_1.jpg` | `images/relindis_agethen_1.jpg` |
Die Bildpfade in `json/berater.json` wurden entsprechend angepasst.
## Gemeinsames HTML und CSS
**HTML:** Die unterschiedlichen `index.html`-Versionen wurden zu einem Dokument mit einem `head`, einem `body` und einem übergeordneten `main` zusammengesetzt. Alle benötigten CSS- und JS-Dateien sind dort eingebunden; die Skripte laden mit `defer`. Die Schriftarten werden einmal im gemeinsamen Head angefordert.
**CSS:** Regeln für `body`, Überschriften, `.container` und Farbvariablen waren ursprünglich teilweise seitenweit gültig. Sie sind jetzt auf die jeweiligen Bereiche begrenzt:
| Bereich | Äußerer Selektor |
| --- | --- |
| Produktübersicht | `.produktuebersicht` |
| Pakete | `.pakete` |
| Berater | `.berater-section` |
| Beratung einschließlich Footer | `.beratung-bereich` |
Beispiel: `.produktuebersicht .container` gilt nur im Produktbereich, `.beratung-bereich .container` nur im Beratungsbereich. Gleichnamige Klassen und Variablen können dadurch in beiden Bereichen bestehen bleiben.
**Beim Ergänzen von Styles:** Den jeweiligen äußeren Selektor beibehalten. Neue globale Regeln wie `h2 { ... }`, `.container { ... }` oder Variablen in `:root` können wieder andere Bereiche beeinflussen. Ein anderer CSS-Dateiname allein verhindert das nicht.
## Änderungen je Bereich
### Shahnam – Produktübersicht
- Der gesamte Bereich liegt jetzt innerhalb von `.produktuebersicht`; die Styles und Variablen wurden entsprechend begrenzt.
- Das bisherige innere `main` wurde zu `div.produktuebersicht__main`, damit es nur einen übergeordneten `main` gibt. Der innere `.hero` ist ebenfalls ein `div`.
### Vincent – Pakete
| Stelle | Änderung | Grund |
| --- | --- | --- |
| Datenabruf in `js/leistungen.js` | `data/pakete.json` → `json/pakete.json` | Der bisherige Pfad passte nicht zum vorhandenen Ordner. |
| Initialisierung | Prüfung auf `#leistungen`; Elementsuche innerhalb dieses Bereichs | Das Skript greift nur auf seinen eigenen Bereich zu. |
| Datenabruf | HTTP-Statusprüfung und `try/catch` mit sichtbarer Fehlermeldung | Ein Ladefehler soll nicht als leerer Paketbereich enden. |
| Paketbuttons | Klickfunktion wieder angeschlossen | Die Auswahl aus der ersten Umsetzung fehlte nach der Umstellung auf JSON. |
| Auswahlstatus | Genau eine markierte Karte und `aria-pressed` für die Buttons | Auswahl sichtbar und für Hilfstechnologien erkennbar halten. |
Nach einer Auswahl wird auf `document` das Event `paket:ausgewaehlt` ausgelöst. `event.detail.paket` enthält den `dataPaket`-Wert aus der JSON-Datei. Eine spätere Buchungsfunktion kann daran anschließen; der Button führt aktuell keine Buchung aus.
### Ahmad – Berater
- Kartenbreite von `380px` auf `min(380px, 100%)` angepasst; der Kartencontainer erhält `width: 100%` bei weiterhin maximal `1000px`. So passen die Karten auf schmale Displays.
- CSS auf `.berater-section` begrenzt. Die HTML-Sektion erhielt `id="berater"` und eine zugängliche Bereichsbezeichnung.
- `json/berater.json`: die beiden Bildpfade auf `images/` umgestellt.
### Dennis – Beratung und Footer
- CSS auf `.beratung-bereich` begrenzt. Die vorhandenen allgemeinen Klassennamen bleiben innerhalb dieses Containers nutzbar.
- Der dekorative Hintergrund ist jetzt innerhalb des Bereichs absolut positioniert und durch `isolation: isolate` begrenzt. Er liegt nicht mehr fest hinter der gesamten Seite.
- Scroll-Reveal sucht in `js/beratung.js` nach `.beratung-bereich .reveal` statt seitenweit nach `.reveal`.
- Grid-Spalten verwenden `minmax(0, 1fr)`. Die Karten erhalten `min-width: 0`, `overflow-wrap: anywhere` und `hyphens: auto`. Das behebt den beim 320-Pixel-Test festgestellten horizontalen Überlauf durch lange Wörter.
## Lokal starten und prüfen
`index.html` über einen lokalen HTTP-Server öffnen, zum Beispiel VS Code Live Server. Beim direkten Öffnen als `file://` können die JSON-Abfragen scheitern.
Die vollständige Integrationsprüfung erfolgte automatisiert in Chrome, ergänzt durch die Ansicht von Screenshots:
- Breiten: **320, 390, 768, 1366 und 1920 px**; nach den Korrekturen kein horizontaler Überlauf.
- **3 Pakete und 2 Beraterkarten**, funktionierende Bilder und eindeutige IDs.
- Paketwechsel: genau eine Auswahl und korrektes `paket:ausgewaehlt`-Event.
- Sichtbare Fehlermeldungen bei fehlender Paket- beziehungsweise Berater-JSON.
- Sichtbare Beratungsinhalte bei aktivierter Einstellung für reduzierte Bewegung.
- Keine unbehandelten JavaScript-Fehler oder fehlgeschlagenen lokalen Ressourcen im normalen Testlauf.
Die Browserprüfung fand vor dem Verschieben der Bilder statt; danach wurden die Bildpfade und Dateiinhalte geprüft. Andere Browser und echte Mobilgeräte wurden nicht getestet.
## Offene Punkte für das Team
| Bereich | Noch zu prüfen |
| --- | --- |
| Produktübersicht | Platzhalter durch endgültige Texte ersetzen. |
| Pakete | Bezeichnung `STANDART`, Preise und Paketangaben prüfen; Buchungsfunktion noch offen. |
| Berater | Zwei gleich benannte Profile mit gleichen Informationen und unterschiedlichen Bildern sind aus dem Quellstand übernommen. Prüfen, ob das so vorgesehen ist. |
| Kontakt und externe Links | Ziele und Angaben fachlich prüfen. |
| Gesamtgestaltung | Unterschiede bei Farben, Abständen und Schriftgrößen gemeinsam bewerten. |

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -4,26 +4,247 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ernährungsberater</title>
<title>Ernährungsberatung für Triathleten | tri-hub</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&amp;family=Inter:wght@400;500;600;700&amp;family=Sora:wght@400;600;700&amp;display=swap"
rel="stylesheet">
<link rel="stylesheet" href="css/site.css">
<link rel="stylesheet" href="css/produktuebersicht.css">
<link rel="stylesheet" href="css/leistungen.css">
<link rel="stylesheet" href="css/berater.css">
<link rel="stylesheet" href="css/beratung.css">
<script src="js/leistungen.js" defer></script>
<script src="js/berater.js" defer></script>
<script src="js/beratung.js" defer></script>
</head>
<body>
<!-- Leistungsübersicht Vincent-->
<section>
<main id="main-content">
<!-- Shahnam: Produktübersicht -->
<section class="produktuebersicht" id="produktuebersicht" aria-labelledby="hero-title">
<header class="site-header">
<div class="container brand">
<div class="brand__logo">
<img src="images/trihub-logo.jpg" alt="Trihub – fit und vital ab 50!" width="1024" height="1024">
</div>
<div class="brand__text">
<span class="brand__name">TRI-HUB</span>
<span class="brand__label">Triathlon als sportliches Zuhause ab 50</span>
</div>
</div>
</header>
<div class="produktuebersicht__main">
<div class="hero">
<img class="hero__image" src="images/hero-triathlon.webp"
alt="Gruppe beim Radfahren und Laufen in einer Berglandschaft im Abendlicht" width="1920"
height="1080" fetchpriority="high">
<div class="container hero__inner">
<div class="hero__content">
<p class="hero__eyebrow">Der Text wärmt sich noch auf</p>
<h1 id="hero-title">
Überschrift. Weitere Zeile.
<span>Akzentzeile.</span>
</h1>
<p class="hero__description">
Hier folgt eine kurze Beschreibung der Ernährungsberatung.
Dieser Platz ist für den finalen Text vorgesehen und wird ergänzt,
sobald die Inhalte vorliegen.
</p>
</div>
<div class="hero__details">
<ul class="benefits" aria-label="Platzhalter für die Vorteile der Beratung">
<li>
<span class="benefits__number" aria-hidden="true">01</span>
<p>Erster Vorteil <span>Text folgt</span></p>
</li>
<li>
<span class="benefits__number" aria-hidden="true">02</span>
<p>Zweiter Vorteil <span>Text folgt</span></p>
</li>
<li>
<span class="benefits__number" aria-hidden="true">03</span>
<p>Dritter Vorteil <span>Text folgt</span></p>
</li>
</ul>
<div class="hero__caption">
<p class="hero__caption-label">Bildunterschrift folgt</p>
<p class="hero__slogan">Slogan folgt. Weitere Zeile.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Vorläufig ausgeblendet, bis die endgültigen Texte vorliegen.
<footer>
<div class="container site-footer__inner">
<p>Abschlusstext folgt. <span>Ergänzender Text folgt.</span></p>
<p class="site-footer__note"><span aria-hidden="true"></span>Kurzhinweis folgt.</p>
</div>
</footer>
-->
</section>
<!-- Vincent: Leistungsübersicht -->
<section id="leistungen" class="pakete">
<div class="pakete__intro">
<h2 class="pakete__titel"></h2>
<p class="pakete__text"></p>
</div>
<div class="pakete__grid"></div>
</section>
<!-- Ahmad: Berater und Qualifikationen -->
<section class="berater-section" id="berater" aria-label="Berater und Qualifikationen">
<div class="section-header">
<h2 class="section-title"></h2>
<p class="section-subtitle"></p>
</div>
<!-- Container wird durch berater.js befüllt -->
<div class="berater-container" id="berater-container"></div>
</section>
<!-- Dennis: Beratungsablauf und Footer -->
<div class="beratung-bereich">
<section id="beratung" class="section">
<div class="container">
<div class="section-head reveal">
<span class="kicker">Info über die Beratung</span>
<h2>Gut zu wissen, bevor du startest</h2>
<p class="lead">Transparenz von Anfang an: So arbeitet die Beratung, für wen sie sich eignet und
was dich erwartet.</p>
</div>
<div class="grid-2">
<div class="box reveal">
<h2>Was dich bei der Beratung erwartet</h2>
<p>Gemeinsam schauen wir uns deine individuellen Ziele, Gewohnheiten und Bedürfnisse an und
entwickeln daraus passende Strategien für deinen Alltag.</p>
<ul class="check-list">
<li>Individuelle Ernährungsberatung</li>
<li>Erstellung von Ernährungsplänen</li>
<li>Unterstützung bei Gewichtsmanagement</li>
<li>Beratung bei speziellen Ernährungsbedürfnissen</li>
<li>Analyse deiner aktuellen Ernährungsgewohnheiten</li>
<li>Praktische Tipps für die Umsetzung im Alltag</li>
</ul>
</div>
<div class="box reveal">
<h2>So läuft die Beratung ab</h2>
<ol class="beratung-ablauf">
<li>
<strong>Erstgespräch</strong>
<p>Wir besprechen deine Ziele, Wünsche und bisherigen Erfahrungen.</p>
</li>
<li>
<strong>Analyse</strong>
<p>Deine aktuelle Ernährung und deine individuellen Bedürfnisse werden betrachtet.
</p>
</li>
<li>
<strong>Planung</strong>
<p>Gemeinsam entwickeln wir konkrete und realistische Maßnahmen.</p>
</li>
<li>
<strong>Begleitung</strong>
<p>Bei Bedarf wird der Fortschritt regelmäßig überprüft und der Plan angepasst.</p>
</li>
</ol>
</div>
<div class="box reveal">
<h2>Für wen ist die Beratung geeignet?</h2>
<ul class="check-list">
<li>Menschen, die ihre Ernährung verbessern möchten</li>
<li>Sportler mit individuellen Ernährungszielen</li>
<li>Menschen mit speziellen Ernährungsbedürfnissen</li>
<li>Personen, die Unterstützung beim Gewichtsmanagement suchen</li>
</ul>
</div>
<div class="box reveal">
<h2>Weitere Informationen</h2>
<p class="muted">
Platzhalter für zukünftige Erweiterungen, beispielsweise Informationen zu Preisen,
Terminen, Kontaktmöglichkeiten oder zusätzlichen Beratungsangeboten.
</p>
</div>
</div>
</div>
<div class="container" id="kontakt">
<div class="cta-band reveal">
<h2>Bereit für deinen nächsten Schritt?</h2>
<p>Vereinbare ein unverbindliches Kennenlerngespräch – wir schauen gemeinsam, ob die Beratung zu
dir
passt.</p>
<a class="btn btn-primary"
href="mailto:info@trihub.de?subject=Ernaehrungsberatung%20-%20Kennenlerngespraech">Jetzt
unverbindlich anfragen</a>
</div>
</div>
</section>
<!-- Berater & Qualifikationen Ahmad -->
<section>
<footer class="site-footer">
<div class="container">
<div class="footer-grid">
<div class="footer-brand">
<a class="logo" href="https://tri-hub.de/">tri<span>-hub</span></a>
<p>Triathlon ab 50 – Coaching, Wissen und Begleitung für Best Ager. Hier: der neue Bereich
Ernährungsberatung.</p>
</div>
</section>
<!-- Info über Beratung Dennis-->
<section>
<div class="footer-col">
<h3>Dieser Bereich</h3>
<ul>
<li><a href="#beratung">Ablauf der Beratung</a></li>
<li><a href="#kontakt">Kontakt</a></li>
</ul>
</div>
</section>
<!-- Produktsübersicht Shahnam -->
<section>
<div class="footer-col">
<h3>Tri-hub</h3>
<ul>
<li><a href="https://tri-hub.de/">Start</a></li>
<li><a href="https://tri-hub.de/coaching-1zu1">1:1 Coaching</a></li>
<li><a href="https://tri-hub.de/camps-schwarzwald">Camps Schwarzwald</a></li>
<li><a href="https://tri-hub.de/webinare-workshops">Webinare &amp; Workshops</a></li>
<li><a href="https://tri-hub.de/wissen">Wissen</a></li>
<li><a href="https://tri-hub.de/kontakt">Kontakt</a></li>
</ul>
</div>
</div>
</section>
<div class="footer-legal">
<span>© 2026 Tri-hub GmbH</span>
<span>
<a href="https://tri-hub.de/impressum">Impressum</a> ·
<a href="https://tri-hub.de/datenschutz">Datenschutz</a> ·
<a href="https://tri-hub.de/agb">AGB</a>
</span>
</div>
</div>
</footer>
</div>
</main>
</body>
</html>

103
js/berater.js 100644
View File

@ -0,0 +1,103 @@
document.addEventListener('DOMContentLoaded', async () => {
// Container für die Berater-Karten auswählen
const container = document.getElementById('berater-container');
// Titel- und Untertitel-Elemente aus dem HTML abrufen
const titleEl = document.querySelector('.section-title');
const subtitleEl = document.querySelector('.section-subtitle');
let daten;
try {
// Daten aus der JSON-Datei asynchron laden
const response = await fetch('json/berater.json');
if (!response.ok) throw new Error(`HTTP Fehler: ${response.status}`);
daten = await response.json();
} catch (error) {
console.error('Fehler beim Laden der JSON-Datei:', error);
// Fehlermeldung auf der Webseite anzeigen, falls das Laden fehlschlägt
if (container) {
container.innerHTML = '<p style="color: #94A3B8;">Daten konnten nicht geladen werden.</p>';
}
return;
}
// 1. Titel und Einleitungstext (Intro) aus der JSON-Datei einfügen
if (titleEl && daten.intro) {
titleEl.textContent = daten.intro.titel;
}
if (subtitleEl && daten.intro) {
subtitleEl.textContent = daten.intro.text;
}
// 2. Berater-Karten verarbeiten und erstellen
// Wir iterieren über das Array "berater" innerhalb der JSON-Daten
daten.berater.forEach(berater => {
// Ein neues div-Element für die Karte erstellen
const card = document.createElement('div');
card.className = 'berater-card';
// Zertifikate verarbeiten (falls vorhanden)
let zertifikateHtml = '';
if (berater.zertifikate && berater.zertifikate.length > 0) {
zertifikateHtml = `<h4 class="bio-title" style="margin-top: 16px;">Zertifikate</h4><ul class="berater-liste">`;
berater.zertifikate.forEach(zert => {
zertifikateHtml += `<li>${zert}</li>`;
});
zertifikateHtml += `</ul>`;
}
// Links verarbeiten (falls vorhanden)
let linksHtml = '';
if (berater.links && berater.links.length > 0) {
linksHtml = `<div class="berater-links">`;
berater.links.forEach(link => {
linksHtml += `<a href="${link.url}" target="_blank" class="berater-link-btn">${link.text}</a>`;
});
linksHtml += `</div>`;
}
// Zusatzinformationen verarbeiten (falls vorhanden)
let zusatzHtml = '';
if (berater.zusatzInfo) {
zusatzHtml = `<p class="berater-zusatz">${berater.zusatzInfo}</p>`;
}
// Eigene/unbekannte dynamische Felder verarbeiten
// Zuerst definieren wir, welche Felder Standard sind und ignoriert werden sollen
const standardFelder = ['id', 'name', 'role', 'image', 'bioTitle', 'bioText', 'zertifikate', 'links', 'zusatzInfo'];
let eigeneFelderHtml = '';
// Wir durchlaufen jeden Eintrag in der JSON für diesen spezifischen Berater
for (const [schluessel, wert] of Object.entries(berater)) {
// Wenn das Feld kein Standardfeld ist, generieren wir daraus eine Überschrift und den zugehörigen Text
if (!standardFelder.includes(schluessel)) {
eigeneFelderHtml += `
<h4 class="bio-title" style="margin-top: 16px; text-transform: capitalize;">${schluessel}</h4>
<p class="bio-text">${wert}</p>
`;
}
}
// Die Karte mit allen gesammelten HTML-Bausteinen zusammenbauen
card.innerHTML = `
<div class="berater-image-wrapper">
<img src="${berater.image}" alt="${berater.name} Profilbild">
</div>
<h2 class="berater-name">${berater.name}</h2>
<h3 class="berater-rolle">${berater.role}</h3>
<div class="berater-bio-box">
<h4 class="bio-title">${berater.bioTitle}</h4>
<p class="bio-text">${berater.bioText}</p>
${eigeneFelderHtml}
${zusatzHtml}
${zertifikateHtml}
${linksHtml}
</div>
`;
// Die fertige Karte zum Container auf der Seite hinzufügen
container.appendChild(card);
});
});

51
js/beratung.js 100644
View File

@ -0,0 +1,51 @@
// ----- Mobile Navigation -----
(function () {
const toggle = document.querySelector(".nav-toggle");
const nav = document.getElementById("main-nav");
if (!toggle || !nav) return;
toggle.addEventListener("click", function () {
const open = nav.classList.toggle("open");
toggle.setAttribute("aria-expanded", String(open));
toggle.setAttribute("aria-label", open ? "Menü schließen" : "Menü öffnen");
});
// Menü nach Klick auf einen Link automatisch schließen
nav.querySelectorAll("a").forEach(function (link) {
link.addEventListener("click", function () {
nav.classList.remove("open");
toggle.setAttribute("aria-expanded", "false");
});
});
})();
// ----- Scroll-Reveal -----
(function () {
const elements = document.querySelectorAll(".beratung-bereich .reveal");
if (!elements.length) return;
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduceMotion || !("IntersectionObserver" in window)) {
elements.forEach(function (el) {
el.classList.add("visible");
});
return;
}
const observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.12, rootMargin: "0px 0px -40px 0px" }
);
elements.forEach(function (el) {
observer.observe(el);
});
})();

119
js/leistungen.js 100644
View File

@ -0,0 +1,119 @@
// US-01-02 Leistungsübersicht
// Markiert das gewählte Paket visuell und stellt die Auswahl bereit,
// damit US-01-03 (Pakete online buchen) später darauf aufbauen kann.
document.addEventListener("DOMContentLoaded", async () => {
const section = document.getElementById("leistungen");
if (!section) return;
// Integration: Der Datenpfad muss zum vorhandenen JSON-Ordner passen.
let daten;
try {
const response = await fetch("json/pakete.json");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
daten = await response.json();
} catch (error) {
section.querySelector(".pakete__text").textContent = "Die Pakete konnten nicht geladen werden. Bitte lade die Seite erneut.";
console.error("Pakete konnten nicht geladen werden:", error);
return;
}
// Elemente aus dem HTML holen
const titel = section.querySelector(".pakete__titel");
const text = section.querySelector(".pakete__text");
const grid = section.querySelector(".pakete__grid");
// Intro mit Daten aus JSON füllen
titel.textContent = daten.intro.titel;
text.textContent = daten.intro.text;
// Vorhandenen Inhalt entfernen
grid.innerHTML = "";
// Für jedes Paket eine Karte erstellen
daten.pakete.forEach(paket => {
// Artikel erstellen
const karte = document.createElement("article");
karte.classList.add("paket-karte");
// Empfohlenes Paket bekommt zusätzliche Klasse
if (paket.empfohlen) {
karte.classList.add("paket-karte--empfohlen");
}
// Badge nur erstellen, wenn eines vorhanden ist
if (paket.badge) {
const badge = document.createElement("p");
badge.classList.add("paket-karte__badge");
badge.textContent = paket.badge;
karte.appendChild(badge);
}
// Name
const name = document.createElement("h3");
name.classList.add("paket-karte__name");
name.textContent = paket.name;
karte.appendChild(name);
// Preis
const preis = document.createElement("p");
preis.classList.add("paket-karte__preis");
const betrag = document.createElement("span");
betrag.classList.add("paket-karte__betrag");
betrag.textContent = `${paket.preis} €`;
const zeitraum = document.createElement("span");
zeitraum.classList.add("paket-karte__zeitraum");
zeitraum.textContent = `/ ${paket.zeitraum}`;
preis.appendChild(betrag);
preis.appendChild(zeitraum);
karte.appendChild(preis);
// Beschreibung
const beschreibung = document.createElement("p");
beschreibung.classList.add("paket-karte__beschreibung");
beschreibung.textContent = paket.beschreibung;
karte.appendChild(beschreibung);
// Leistungen
const liste = document.createElement("ul");
liste.classList.add("paket-karte__leistungen");
paket.leistungen.forEach(leistung => {
const punkt = document.createElement("li");
punkt.textContent = leistung;
liste.appendChild(punkt);
});
karte.appendChild(liste);
// Button
const button = document.createElement("button");
button.classList.add("paket-karte__cta");
button.type = "button";
button.textContent = "Paket wählen";
button.dataset.paket = paket.dataPaket;
button.setAttribute("aria-pressed", "false");
// Die Paketauswahl aus der ersten Version auch nach dem JSON-Rendering erhalten.
button.addEventListener("click", () => {
grid.querySelectorAll(".paket-karte").forEach(andereKarte => {
andereKarte.classList.remove("paket-karte--ausgewaehlt");
andereKarte.querySelector("button").setAttribute("aria-pressed", "false");
});
karte.classList.add("paket-karte--ausgewaehlt");
button.setAttribute("aria-pressed", "true");
document.dispatchEvent(new CustomEvent("paket:ausgewaehlt", {
detail: { paket: button.dataset.paket }
}));
});
karte.appendChild(button);
// Karte ins Grid einfügen
grid.appendChild(karte);
});
});

52
json/berater.json 100644
View File

@ -0,0 +1,52 @@
{
"intro": {
"titel": "Deine Ernährungsberater und Coaches",
"text": "Erfahrene Triathleten und zertifizierte Coaches, die dich auf dem Weg zu deinen Zielen begleiten und dir helfen, deine Leistung zu optimieren."
},
"berater": [
{
"id": 1,
"name": "Relindis Agethen ",
"role": "TRIATHLET UND ERNÄHRUNGSBERATERIN",
"image": "images/relindis_agethen.png",
"bioTitle": "Kurzbiografie",
"bioText": "Relindis Agethen, genannt Lilli, ist seit 16 Jahren im Triathlon aktiv und bringt starke sportliche Erfolge mit: Vize-Europameisterin, Deutsche Meisterin und mehrfache Baden-Württembergische Meisterin. Als zertifizierte Ernährungsberaterin für Sportler B-Lizenz ergänzt sie das Team um Leistungsentwicklung und Ernährungswissen.",
"zertifikate": [
"Zertifizierter Triathlon-Trainer",
"Ernährungscoach B-Lizenz"
],
"links": [
{
"text": "Instagram Profil",
"url": "https://instagram.com"
},
{
"text": "Trainingsplan buchen",
"url": "https://tri-hub.de/booking"
}
]
},
{
"id": 2,
"name": "Relindis Agethen ",
"role": "TRIATHLET UND ERNÄHRUNGSBERATERIN",
"image": "images/relindis_agethen_1.jpg",
"bioTitle": "Kurzbiografie",
"bioText": "Relindis Agethen, genannt Lilli, ist seit 16 Jahren im Triathlon aktiv und bringt starke sportliche Erfolge mit: Vize-Europameisterin, Deutsche Meisterin und mehrfache Baden-Württembergische Meisterin. Als zertifizierte Ernährungsberaterin für Sportler B-Lizenz ergänzt sie das Team um Leistungsentwicklung und Ernährungswissen.",
"zertifikate": [
"Zertifizierter Triathlon-Trainer",
"Ernährungscoach B-Lizenz"
],
"links": [
{
"text": "Instagram Profil",
"url": "https://instagram.com"
},
{
"text": "Trainingsplan buchen",
"url": "https://tri-hub.de/booking"
}
]
}
]
}

55
json/pakete.json 100644
View File

@ -0,0 +1,55 @@
{
"intro": {
"titel": "Deine Pakete",
"text": "Drei Wege zu einer Ernährung, die zu deinem Training, deinem Alltag und deinem Alter passt – entwickelt für Triathletinnen und Triathleten ab 50."
},
"pakete": [
{
"name": "Starter",
"preis": 79,
"zeitraum": "Monat",
"beschreibung": "Für den Einstieg in eine bewusste Ernährung neben dem Training.",
"leistungen": [
"Erstgespräch & Bedarfsanalyse",
"Individueller Ernährungsplan",
"Monatliches Check-in per E-Mail",
"Zugang zu Beispielplänen"
],
"badge": null,
"empfohlen": false,
"dataPaket": "Starter"
},
{
"name": "STANDART",
"preis": 149,
"zeitraum": "Monat",
"beschreibung": "Laufende Begleitung für alle, die regelmäßig für Wettkämpfe trainieren.",
"leistungen": [
"Alles aus Starter",
"Plan-Anpassung je Trainingsphase",
"Zwei Beratungsgespräche pro Monat",
"Wettkampf-Ernährungsstrategie",
"Direkter Chat mit deiner Beraterin"
],
"badge": "Beliebteste Wahl",
"empfohlen": true,
"dataPaket": "Ausdauer"
},
{
"name": "Rundum Sorglos Paket",
"preis": 249,
"zeitraum": "Monat",
"beschreibung": "Volle Betreuung für ambitionierte Athletinnen und Athleten.",
"leistungen": [
"Alles aus Ausdauer",
"Wöchentliche Beratungsgespräche",
"Individuelle Supplement-Empfehlung",
"Betreuung am Wettkampftag",
"Priorisierter Support"
],
"badge": null,
"empfohlen": false,
"dataPaket": "Wettkampf"
}
]
}

View File

View File