diff --git a/index.html b/index.html index a750b86..6746c57 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ + 1:1-Ernährungsberatung -
- Ernährungsberatung -
+

Ernährung, die zu dir passt.

diff --git a/public/images/logo.png b/public/images/logo.png new file mode 100644 index 0000000..3063d26 Binary files /dev/null and b/public/images/logo.png differ diff --git a/src/components/navigationsbar/README.md b/src/components/navigationsbar/README.md new file mode 100644 index 0000000..e349d1c --- /dev/null +++ b/src/components/navigationsbar/README.md @@ -0,0 +1,14 @@ +# Navigation einbinden + +Füge an der gewünschten Stelle im HTML einen Platzhalter ein und binde CSS +und JavaScript separat ein: + +```html + + + +``` + +Das Script lädt `navigation.html` und initialisiert die Navigation automatisch, +`initNavbar()` muss nicht zusätzlich aufgerufen werden. Die Stylesheet-Datei wird +nicht vom Script geladen und muss deshalb separat eingebunden werden. diff --git a/src/components/navigationsbar/images/logo.png b/src/components/navigationsbar/images/logo.png new file mode 100644 index 0000000..3063d26 Binary files /dev/null and b/src/components/navigationsbar/images/logo.png differ diff --git a/src/components/navigationsbar/navigation.html b/src/components/navigationsbar/navigation.html new file mode 100644 index 0000000..255751a --- /dev/null +++ b/src/components/navigationsbar/navigation.html @@ -0,0 +1,84 @@ + + + diff --git a/src/components/navigationsbar/navigation.js b/src/components/navigationsbar/navigation.js new file mode 100644 index 0000000..a93a67c --- /dev/null +++ b/src/components/navigationsbar/navigation.js @@ -0,0 +1,99 @@ +import navigationHtml from "./navigation.html?raw"; + +/** + * Bindet das mit Vite gebündelte Navbar-Fragment (navigation.html) ein und + * ersetzt damit den Platzhalter im Header der jeweiligen Seite. + * Aufruf z. B. in main.js: initNavbar('#navbar-placeholder') + */ +export function initNavbar(placeholderSelector = "#navbar-placeholder") { + const placeholder = document.querySelector(placeholderSelector); + if (!placeholder) { + console.warn("Navbar-Platzhalter nicht gefunden:", placeholderSelector); + return; + } + + placeholder.outerHTML = navigationHtml; // Platzhalter durch echtes Navbar-Markup ersetzen + setupBehavior(); + markCurrentPage(); +} + +/** + * Richtet alle interaktiven Funktionen der Navbar ein: + * - Mobiles Menü öffnen/schließen per Klick + * - Automatischer Fokus auf ersten Link, wenn per Tastatur geöffnet + * - Escape schließt das Menü und gibt den Fokus zurück + * - Menü schließt sich, wenn der Fokus die Navbar per Tab verlässt + * - Klick außerhalb der Navbar schließt das Menü (Maus/Touch) + */ +export function setupBehavior() { + const navbar = document.querySelector(".navbar"); + const toggle = document.querySelector(".navbar__toggle"); + const nav = document.querySelector(".navbar__nav"); + const menu = document.querySelector(".navbar__menu"); + if (!navbar || !toggle || !nav || !menu) return; + + let openedViaKeyboard = false; + + toggle.addEventListener("keydown", (e) => { + if (e.key === "Enter" || e.key === " ") { + openedViaKeyboard = true; + } + }); + + toggle.addEventListener("click", () => { + const isOpen = nav.classList.toggle("is-open"); + toggle.setAttribute("aria-expanded", String(isOpen)); + toggle.setAttribute( + "aria-label", + isOpen ? "Menü schließen" : "Menü öffnen", + ); + + if (isOpen && openedViaKeyboard) { + const firstLink = menu.querySelector(".navbar__link"); + if (firstLink) firstLink.focus(); + } + openedViaKeyboard = false; + }); + + document.addEventListener("keydown", (e) => { + if (e.key === "Escape" && nav.classList.contains("is-open")) { + nav.classList.remove("is-open"); + toggle.setAttribute("aria-expanded", "false"); + toggle.setAttribute("aria-label", "Menü öffnen"); + toggle.focus(); + } + }); + + navbar.addEventListener("focusout", (e) => { + const leavingNavbar = !navbar.contains(e.relatedTarget); + if (leavingNavbar && nav.classList.contains("is-open")) { + nav.classList.remove("is-open"); + toggle.setAttribute("aria-expanded", "false"); + toggle.setAttribute("aria-label", "Menü öffnen"); + } + }); + + document.addEventListener("click", (e) => { + if (!navbar.contains(e.target) && nav.classList.contains("is-open")) { + nav.classList.remove("is-open"); + toggle.setAttribute("aria-expanded", "false"); + toggle.setAttribute("aria-label", "Menü öffnen"); + } + }); +} + +/** + * Markiert den Menüpunkt der aktuell geöffneten Seite mit aria-current="page", + * damit er optisch hervorgehoben wird (siehe .navbar__link[aria-current="page"] in der CSS). + */ +export function markCurrentPage() { + const links = document.querySelectorAll(".navbar__link"); + const current = window.location.pathname.replace(/\/index\.html$/, "/"); + links.forEach((link) => { + if (link.getAttribute("href") === current) { + link.setAttribute("aria-current", "page"); + } + }); +} + +document.addEventListener("DOMContentLoaded", () => initNavbar()); diff --git a/src/main.js b/src/main.js index 95efe73..a8ccb3d 100644 --- a/src/main.js +++ b/src/main.js @@ -1,3 +1,4 @@ import "./styles/styles.css"; +import "./components/navigationsbar/navigation.js"; document.querySelector("#year").textContent = new Date().getFullYear(); diff --git a/src/server/data/bookings.csv b/src/server/data/bookings.csv new file mode 100644 index 0000000..ba00ff8 --- /dev/null +++ b/src/server/data/bookings.csv @@ -0,0 +1,10 @@ +bookingId,createdAt,packageId,packageName,name,email,emailStatus,idempotencyKey,requestHash,bookedPackage,customer,acceptedTerms +TH-000001,2026-09-25T11:43:43.074Z,ernaehrung-standard,Für Best Ager mit ersten Erfahrungen und klaren Zielen,kk,kk@web.de,accepted,497662ce-278c-466f-9505-c2728f8973ca,d5c69de514e6de5552e43f99256a042b59df5bd53db0bd1685f849809a455ef9,,, +TH-000002,2026-09-25T19:22:37.801Z,ernaehrung-starter,Für den sicheren Einstieg in die Sporternährung,Marvin,marvin@web.de,accepted,06b9ad79-05c3-4e37-9135-0c3cf1da3f36,7650a36bd436390b5f79dde1ea1e0d8944f1320b29bad927dfd71157c3f4133c,,, +TH-000003,2026-09-25T19:52:53.927Z,ernaehrung-standard,Für Best Ager mit ersten Erfahrungen und klaren Zielen,M,test@web.de,accepted,9446e525-a714-4912-bb10-1906a75cc9cd,a8fbd181361e4de7713fb0c4b5e0bf88cd43acd3e16294e7b84b33d959551458,"{""packageId"":""ernaehrung-standard"",""variantId"":null,""variantLabel"":null,""type"":""STANDARD"",""title"":""Für Best Ager mit ersten Erfahrungen und klaren Zielen"",""subtitle"":""Gezielte Ernährungssteuerung für Alltag, Belastungsspitzen und deinen nächsten Wettkampf."",""summaryForBooking"":""Standard-Paket Sporternährung (24 Wochen Coaching inkl. Wettkampf-Verpflegungsstrategie)"",""durationWeeks"":24,""durationLabel"":""24 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Umfassende Anamnese inkl. Analyse der bisherigen Trainings- und Wettkampfernährung"",""Dynamischer Ernährungsplan (gekoppelt an deine Trainingsphasen)"",""Spezifisches Carb-Loading- und Pacing-Konzept für den Wettkampftag"",""Monatliche 1:1 Video-Calls (6x 45 Min.) zur Feinjustierung"",""Gezieltes Magen-Training (Gut-Training) für Gels, Riegel und Sportgetränke"",""Support per Messenger bei Fragen im Trainingsalltag (Antwort innerhalb von 48h)""],""processSteps"":[{""step"":""1. Tiefen-Anamnese"",""text"":""Präzise Erfassung von Trainingsrealität, Erfahrung, Belastbarkeit und Verträglichkeiten.""},{""step"":""2. Periodisierte Planung"",""text"":""Abstimmung der Makro- und Mikronährstoffe auf deine konkreten Trainingsblöcke.""},{""step"":""3. Wettkampf-Simulation"",""text"":""Erprobung der Raceday-Strategie im Training für maximale Sicherheit am Starttag.""}],""netPrice"":377.31,""taxRate"":19,""taxAmount"":71.69,""grossPrice"":449,""currency"":""EUR""}",, +TH-000004,2026-09-25T19:54:52.744Z,ernaehrung-premium,Für maximale Individualität mit klarem Fokus,m,test@web.de,accepted,1817271c-343e-4e27-ac60-9d225897ba28,4a9f445acdf5cef94e95d8cdf50e78f95884913799cd2f532aaa37302910a16b,"{""packageId"":""ernaehrung-premium"",""variantId"":""ernaehrung-premium-52"",""variantLabel"":""52-Wochen-Variante (Jahresbegleitung)"",""type"":""PREMIUM"",""title"":""Für maximale Individualität und intensive 1:1-Begleitung"",""subtitle"":""Enge Coaching-Beziehung, laufende Feinabstimmung und zwei wählbare Laufzeit-Varianten."",""summaryForBooking"":""Premium-Paket Sporternährung (Intensive 1:1-Begleitung inkl. Raceday- & Regenerations-Steuerung)"",""durationWeeks"":52,""durationLabel"":""52 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Exklusive 90-Minuten-Start-Anamnese inkl. Auswertung vorhandener Blut-/Laborwerte"",""Wöchentliche Feinabstimmung des Ernährungsplans parallel zum Trainingsplan"",""Individueller Supplement- & Mikronährstoff-Plan für optimale Regeneration ab 50"",""14-tägige 1:1 Video-Calls sowie direkter Priority-Messenger-Support"",""Detailliertes Raceday-Playbook (Stunde-für-Stunde-Plan für vor, während und nach dem Rennen)"",""Direkte Abstimmung mit deinem Triathlon-Trainer bei Tri-Hub""],""processSteps"":[{""step"":""1. Ganzheitliches Onboarding"",""text"":""Gemeinsame Analyse von Gesundheitsdaten, Leistungszielen und Alltagsstruktur.""},{""step"":""2. Laufende Steuerung"",""text"":""Wöchentliche Anpassung an Trainingsumfang, Schlafqualität und Regeneration.""},{""step"":""3. Punktlandung am Wettkampftag"",""text"":""Individuelle Tapering- und Wettkampfernährung für deine persönliche Bestleistung.""}],""netPrice"":1175.63,""taxRate"":19,""taxAmount"":223.37,""grossPrice"":1399,""currency"":""EUR""}",, +TH-000005,2026-09-25T20:14:51.874Z,ernaehrung-premium,Für maximale Individualität mit klarem Fokus,Marvin,m@web.de,accepted,678654e5-7db9-49af-97b0-64fe02257e77,89c188f086a2d72fb77ae52612288610d2f17846fb1a3e62b11e8caa011cf2b4,"{""packageId"":""ernaehrung-premium"",""variantId"":""ernaehrung-premium-52"",""variantLabel"":""52-Wochen-Variante (Jahresbegleitung)"",""type"":""PREMIUM"",""title"":""Für maximale Individualität und intensive 1:1-Begleitung"",""subtitle"":""Enge Coaching-Beziehung, laufende Feinabstimmung und zwei wählbare Laufzeit-Varianten."",""summaryForBooking"":""Premium-Paket Sporternährung (Intensive 1:1-Begleitung inkl. Raceday- & Regenerations-Steuerung)"",""durationWeeks"":52,""durationLabel"":""52 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Exklusive 90-Minuten-Start-Anamnese inkl. Auswertung vorhandener Blut-/Laborwerte"",""Wöchentliche Feinabstimmung des Ernährungsplans parallel zum Trainingsplan"",""Individueller Supplement- & Mikronährstoff-Plan für optimale Regeneration ab 50"",""14-tägige 1:1 Video-Calls sowie direkter Priority-Messenger-Support"",""Detailliertes Raceday-Playbook (Stunde-für-Stunde-Plan für vor, während und nach dem Rennen)"",""Direkte Abstimmung mit deinem Triathlon-Trainer bei Tri-Hub""],""processSteps"":[{""step"":""1. Ganzheitliches Onboarding"",""text"":""Gemeinsame Analyse von Gesundheitsdaten, Leistungszielen und Alltagsstruktur.""},{""step"":""2. Laufende Steuerung"",""text"":""Wöchentliche Anpassung an Trainingsumfang, Schlafqualität und Regeneration.""},{""step"":""3. Punktlandung am Wettkampftag"",""text"":""Individuelle Tapering- und Wettkampfernährung für deine persönliche Bestleistung.""}],""netPrice"":1175.63,""taxRate"":19,""taxAmount"":223.37,""grossPrice"":1399,""currency"":""EUR""}",, +TH-000006,2026-09-26T08:44:42.313Z,ernaehrung-standard,Für Best Ager mit ersten Erfahrungen und klaren Zielen,Marvin,m@web.de,accepted,a0a8c426-fc56-4887-a0e5-42172ff9cfb2,b83cf7b2ef4c42447bd83038c60d2ca565a8b37d24cae128f4fa2214dc43b185,"{""packageId"":""ernaehrung-standard"",""variantId"":null,""variantLabel"":null,""type"":""STANDARD"",""title"":""Für Best Ager mit ersten Erfahrungen und klaren Zielen"",""subtitle"":""Gezielte Ernährungssteuerung für Alltag, Belastungsspitzen und deinen nächsten Wettkampf."",""summaryForBooking"":""Standard-Paket Sporternährung (24 Wochen Coaching inkl. Wettkampf-Verpflegungsstrategie)"",""durationWeeks"":24,""durationLabel"":""24 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Umfassende Anamnese inkl. Analyse der bisherigen Trainings- und Wettkampfernährung"",""Dynamischer Ernährungsplan (gekoppelt an deine Trainingsphasen)"",""Spezifisches Carb-Loading- und Pacing-Konzept für den Wettkampftag"",""Monatliche 1:1 Video-Calls (6x 45 Min.) zur Feinjustierung"",""Gezieltes Magen-Training (Gut-Training) für Gels, Riegel und Sportgetränke"",""Support per Messenger bei Fragen im Trainingsalltag (Antwort innerhalb von 48h)""],""processSteps"":[{""step"":""1. Tiefen-Anamnese"",""text"":""Präzise Erfassung von Trainingsrealität, Erfahrung, Belastbarkeit und Verträglichkeiten.""},{""step"":""2. Periodisierte Planung"",""text"":""Abstimmung der Makro- und Mikronährstoffe auf deine konkreten Trainingsblöcke.""},{""step"":""3. Wettkampf-Simulation"",""text"":""Erprobung der Raceday-Strategie im Training für maximale Sicherheit am Starttag.""}],""netPrice"":377.31,""taxRate"":19,""taxAmount"":71.69,""grossPrice"":449,""currency"":""EUR""}",, +TH-000007,2026-09-26T08:50:50.112Z,ernaehrung-standard,Für Best Ager mit ersten Erfahrungen und klaren Zielen,m,k@web.de,accepted,92e12eff-321d-49e5-a9ad-674a7d61f9a7,14b1f6b3909696f8402be66b1de33956b84ca435f58567e57e31e7152b6bff6c,"{""packageId"":""ernaehrung-standard"",""variantId"":null,""variantLabel"":null,""type"":""STANDARD"",""title"":""Für Best Ager mit ersten Erfahrungen und klaren Zielen"",""subtitle"":""Gezielte Ernährungssteuerung für Alltag, Belastungsspitzen und deinen nächsten Wettkampf."",""summaryForBooking"":""Standard-Paket Sporternährung (24 Wochen Coaching inkl. Wettkampf-Verpflegungsstrategie)"",""durationWeeks"":24,""durationLabel"":""24 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Umfassende Anamnese inkl. Analyse der bisherigen Trainings- und Wettkampfernährung"",""Dynamischer Ernährungsplan (gekoppelt an deine Trainingsphasen)"",""Spezifisches Carb-Loading- und Pacing-Konzept für den Wettkampftag"",""Monatliche 1:1 Video-Calls (6x 45 Min.) zur Feinjustierung"",""Gezieltes Magen-Training (Gut-Training) für Gels, Riegel und Sportgetränke"",""Support per Messenger bei Fragen im Trainingsalltag (Antwort innerhalb von 48h)""],""processSteps"":[{""step"":""1. Tiefen-Anamnese"",""text"":""Präzise Erfassung von Trainingsrealität, Erfahrung, Belastbarkeit und Verträglichkeiten.""},{""step"":""2. Periodisierte Planung"",""text"":""Abstimmung der Makro- und Mikronährstoffe auf deine konkreten Trainingsblöcke.""},{""step"":""3. Wettkampf-Simulation"",""text"":""Erprobung der Raceday-Strategie im Training für maximale Sicherheit am Starttag.""}],""netPrice"":377.31,""taxRate"":19,""taxAmount"":71.69,""grossPrice"":449,""currency"":""EUR""}",, +TH-000008,2026-09-26T09:18:17.493Z,ernaehrung-standard,Für Best Ager mit ersten Erfahrungen und klaren Zielen,m,marvin@test.de,accepted,c74460a8-0315-4e0b-9d6b-48c854b0f71b,19ebc08e678515ea3a71f9b295ac1fbbf188bf54602a531f4f3bdc53698dcda7,"{""packageId"":""ernaehrung-standard"",""variantId"":null,""variantLabel"":null,""type"":""STANDARD"",""title"":""Für Best Ager mit ersten Erfahrungen und klaren Zielen"",""subtitle"":""Gezielte Ernährungssteuerung für Alltag, Belastungsspitzen und deinen nächsten Wettkampf."",""summaryForBooking"":""Standard-Paket Sporternährung (24 Wochen Coaching inkl. Wettkampf-Verpflegungsstrategie)"",""durationWeeks"":24,""durationLabel"":""24 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Umfassende Anamnese inkl. Analyse der bisherigen Trainings- und Wettkampfernährung"",""Dynamischer Ernährungsplan (gekoppelt an deine Trainingsphasen)"",""Spezifisches Carb-Loading- und Pacing-Konzept für den Wettkampftag"",""Monatliche 1:1 Video-Calls (6x 45 Min.) zur Feinjustierung"",""Gezieltes Magen-Training (Gut-Training) für Gels, Riegel und Sportgetränke"",""Support per Messenger bei Fragen im Trainingsalltag (Antwort innerhalb von 48h)""],""processSteps"":[{""step"":""1. Tiefen-Anamnese"",""text"":""Präzise Erfassung von Trainingsrealität, Erfahrung, Belastbarkeit und Verträglichkeiten.""},{""step"":""2. Periodisierte Planung"",""text"":""Abstimmung der Makro- und Mikronährstoffe auf deine konkreten Trainingsblöcke.""},{""step"":""3. Wettkampf-Simulation"",""text"":""Erprobung der Raceday-Strategie im Training für maximale Sicherheit am Starttag.""}],""netPrice"":377.31,""taxRate"":19,""taxAmount"":71.69,""grossPrice"":449,""currency"":""EUR""}",, +TH-000009,2026-09-26T09:43:16.704Z,ernaehrung-premium,Für maximale Individualität mit klarem Fokus,marvin,m@email.de,accepted,9c18134f-3a71-428b-8769-fda7d06790c7,eaa9a3f0dfc568c726f1b6fc26d92f8c4cc7df072f9fdd40fbea581661eeef9f,"{""packageId"":""ernaehrung-premium"",""variantId"":""ernaehrung-premium-24"",""variantLabel"":""24-Wochen-Variante"",""type"":""PREMIUM"",""title"":""Für maximale Individualität und intensive 1:1-Begleitung"",""subtitle"":""Enge Coaching-Beziehung, laufende Feinabstimmung und zwei wählbare Laufzeit-Varianten."",""summaryForBooking"":""Premium-Paket Sporternährung (Intensive 1:1-Begleitung inkl. Raceday- & Regenerations-Steuerung)"",""durationWeeks"":24,""durationLabel"":""24 Wochen Begleitung"",""quantity"":1,""billingInterval"":""einmalig"",""includedFeatures"":[""Exklusive 90-Minuten-Start-Anamnese inkl. Auswertung vorhandener Blut-/Laborwerte"",""Wöchentliche Feinabstimmung des Ernährungsplans parallel zum Trainingsplan"",""Individueller Supplement- & Mikronährstoff-Plan für optimale Regeneration ab 50"",""14-tägige 1:1 Video-Calls sowie direkter Priority-Messenger-Support"",""Detailliertes Raceday-Playbook (Stunde-für-Stunde-Plan für vor, während und nach dem Rennen)"",""Direkte Abstimmung mit deinem Triathlon-Trainer bei Tri-Hub""],""processSteps"":[{""step"":""1. Ganzheitliches Onboarding"",""text"":""Gemeinsame Analyse von Gesundheitsdaten, Leistungszielen und Alltagsstruktur.""},{""step"":""2. Laufende Steuerung"",""text"":""Wöchentliche Anpassung an Trainingsumfang, Schlafqualität und Regeneration.""},{""step"":""3. Punktlandung am Wettkampftag"",""text"":""Individuelle Tapering- und Wettkampfernährung für deine persönliche Bestleistung.""}],""netPrice"":671.43,""taxRate"":19,""taxAmount"":127.57,""grossPrice"":799,""currency"":""EUR""}",, diff --git a/src/server/data/bookings.csv.empty-backup-1790336594464 b/src/server/data/bookings.csv.empty-backup-1790336594464 new file mode 100644 index 0000000..e69de29 diff --git a/src/styles/navigation.css b/src/styles/navigation.css new file mode 100644 index 0000000..14cde15 --- /dev/null +++ b/src/styles/navigation.css @@ -0,0 +1,236 @@ +/* Google Fonts: Inter für Fließtext, Playfair Display für Akzente (falls später gebraucht) */ +@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:wght@600;700&family=Inter:wght@400;500;600;700&display=swap"); + +/* Zentrale Design-Werte der Navbar, passend zum TriHub-Farbschema */ +:root { + --nav-bg: #0d0d1a; + --nav-border: rgba(248, 250, 252, 0.08); + --nav-green: #10b981; + --nav-white: #ffffff; + --nav-light: #f8fafc; + --nav-muted: #94a3b8; +} + +/* Verhindert, dass Padding die Breite von Elementen zusätzlich vergrößert */ +.navbar, +.navbar *, +.navbar *::before, +.navbar *::after { + box-sizing: border-box; +} + +/* ---------- Kriterium 1: durchgehend fixiert am oberen Bildschirmrand ---------- */ +.navbar { + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 1000; + border-bottom: 1px solid var(--nav-border); + background: var(--nav-bg); + font-family: "Inter", system-ui, sans-serif; +} + +.navbar__inner { + width: 100%; + min-height: 76px; + padding: 0 20px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +/* ---------- Logo + Markenname (kein Link mehr, nur Anzeige) ---------- */ +.navbar__brand { + display: inline-flex; + align-items: center; + gap: 12px; + flex-shrink: 0; +} + +.navbar__logo-img { + height: 40px; + width: auto; + display: block; +} + +.navbar__brand-text { + display: flex; + flex-direction: column; + line-height: 1.25; +} + +.navbar__brand-title { + font-size: 0.7rem; + font-weight: 600; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--nav-muted); +} + +.navbar__brand-tagline { + font-size: 0.85rem; + font-weight: 500; + color: var(--nav-muted); +} + +/* ---------- Menüpunkte (rechts) ---------- */ +.navbar__menu { + display: flex; + align-items: center; + gap: 14px; + list-style: none; + margin: 0; + padding: 0; + color: var(--nav-muted); + font-size: 0.85rem; + font-weight: 500; + flex-shrink: 0; +} + +.navbar__link { + color: inherit; + text-decoration: none; + transition: color 0.2s ease; + padding: 0.35rem 0.1rem; + white-space: nowrap; +} + +.navbar__link:hover, +.navbar__link[aria-current="page"] { + color: var(--nav-white); +} + +/* ---------- "Startseite"-Button mit Haus-Icon, ganz rechts ---------- */ +.navbar__link--home { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 18px 6px 10px; + border: 1px solid rgba(148, 163, 184, 0.3); + border-radius: 999px; + color: var(--nav-light); + transition: + border-color 0.2s ease, + color 0.2s ease; +} + +.navbar__link--home:hover { + border-color: rgba(16, 185, 129, 0.55); + color: var(--nav-white); +} + +.navbar__home-icon { + display: inline-flex; + align-items: center; + justify-content: center; + color: #22d3ee; +} + +.navbar__home-icon svg { + width: 18px; + height: 18px; +} + +/* Linienstärke des Haus-Icons zentral hier steuern statt im SVG-Markup */ +.navbar__home-icon svg path { + stroke-width: 1.5; +} + +/* ---------- Kriterium 2: barrierefreie Tastatursteuerung ---------- */ +.skip-link { + position: absolute; + top: -40px; + left: 0; + background: var(--nav-green); + color: #06130f; + font-weight: 700; + padding: 0.75rem 1rem; + z-index: 1100; + transition: top 0.2s ease; +} + +.skip-link:focus { + top: 0; +} + +.navbar a:focus-visible, +.navbar button:focus-visible { + outline: 3px solid var(--nav-green); + outline-offset: 2px; + border-radius: 4px; +} + +/* ---------- Mobiler Hamburger-Button ---------- */ +.navbar__toggle { + display: none; + background: none; + border: none; + cursor: pointer; + padding: 0.5rem; +} + +.navbar__toggle-icon, +.navbar__toggle-icon::before, +.navbar__toggle-icon::after { + display: block; + width: 22px; + height: 2px; + background: var(--nav-white); + position: relative; +} +.navbar__toggle-icon::before, +.navbar__toggle-icon::after { + content: ""; + position: absolute; +} +.navbar__toggle-icon::before { + top: -7px; +} +.navbar__toggle-icon::after { + top: 7px; +} + +@media (max-width: 1300px) { + .navbar__toggle { + display: block; + } + + .navbar__nav { + position: absolute; + top: 76px; + left: 0; + right: 0; + background: var(--nav-bg); + border-bottom: 1px solid var(--nav-border); + display: none; + } + + .navbar__nav.is-open { + display: block; + } + + .navbar__menu { + flex-direction: column; + align-items: flex-start; + padding: 1rem 20px; + gap: 1rem; + font-size: 0.95rem; + } +} + +@media (max-width: 600px) { + .navbar__inner { + padding: 0 16px; + } + + .navbar__brand-tagline { + display: none; + } +} + +/* Platz für die fixierte Navbar */ +body { + padding-top: 76px; +} diff --git a/test-results/.last-run.json b/test-results/.last-run.json new file mode 100644 index 0000000..cbcc1fb --- /dev/null +++ b/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file