"Connection successful" only means the SMTP server accepted the
message, not that it was delivered. The test endpoint now captures the
full SMTP protocol exchange and shows it in the admin UI, plus flags
the common case where the sender address differs from the SMTP login
- many providers silently discard mail in that situation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a "Statistik" cookie category (alongside the existing external
media one), an admin-configurable Measurement ID field in Website
Settings, and a GoogleAnalytics component that only injects gtag.js
after the visitor has consented - mirrors the existing ExternalEmbed
pattern instead of loading tracking scripts unconditionally.
Also documents Google Analytics in the Datenschutzerklärung (new
section 8, remaining sections renumbered) since introducing a new
data processing purpose requires disclosure.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New admin panel "E-Mail" tab (Einstellungen -> E-Mail) lets the shop
owner configure their SMTP server, test the connection with a real
test email, set which address receives new-inquiry notifications, and
edit both the customer confirmation email and the shop notification
email as templates with {{placeholder}} variables.
Previously SMTP config only lived in a non-DB config.php file (with a
blank host, so mail sending was effectively off) and there was no
customer confirmation email at all - only a hardcoded owner
notification. ContactController now sends both emails using the
DB-configured (or config.php-fallback) settings; mail sending stays
best-effort so a contact form submission never fails because of it.
Backend: new Mailer support class (config resolution, PHPMailer setup,
placeholder rendering) and MailSettingsController (show/update/test),
following the existing WebsiteSettings/DatabaseSettings conventions
(password never returned in plaintext, empty password on save keeps
the existing one). New app_settings columns wired into Schema.php so
the "Datenbankstruktur aktualisieren" admin button picks them up on
existing installs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously the grain lived on .page-texture's own background-image, so
any section with its own opaque background color (bg-neutral-50 bands)
painted right over it. Moved the grain to a fixed, full-viewport overlay
that sits on top of everything instead.
Also fixed a failed attempt at using mix-blend-mode: overlay for a
single theme-agnostic texture - that blend mode has almost no visible
effect on backgrounds this close to pure white/black, since its math
compresses toward the backdrop at the extremes. Back to plain alpha
transparency with separate light/dark speckle colors, moderate opacity.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bumped the noise layer's alpha from 0.05/0.055 to 0.35/0.4 and coarsened
the turbulence frequency slightly - the previous version was too subtle
to notice at a glance.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Re-compressed the new source cut (1920x1080/30fps, 65s) at 1920px
width, CRF 22, no audio - same settings as before, 42.9MB.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The flat ambient-glow background (from an earlier "premium minimalism"
pass) read as plain white/black. Brings back the fine SVG noise grain
so the page background has some structure instead of a bare color.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous pass (1280px/CRF30, 8.2MB) looked visibly pixelated at
full hero width. Re-encoded from the original source at 1920px width
and a lower CRF for noticeably crisper detail, landing at 41MB - still
well under GitHub's 100MB limit and a fraction of the 177MB original.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the two-column badge/embed layout with a full-width background
video, dark overlay, and centered eyebrow/heading/CTA - matching the
cinematic teaser style used by other car-audio shops. The CTA links
directly to the specific YouTube video instead of just the channel.
The provided source video (177MB, 2560x1440@60fps) was compressed for
web delivery: 1280px width, 30fps, audio stripped (video is muted
background anyway), H.264 CRF 30 - down to 8.2MB with no visible
quality loss at this scale.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The scale-110 utility set the same CSS transform property that Framer
Motion's y-parallax already controlled inline, silently canceling the
scale. The image never actually zoomed in, so the parallax shift had no
overflow buffer and exposed a bare strip at the bottom of the hero.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Prevents the next section from partially peeking in above the fold on
first load, so it only appears once the visitor actually scrolls.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auto-detects the visitor's browser language on first visit, with a
manual dropdown switcher (flag icons) in the header and mobile menu.
Legal pages, the admin panel, and DB-driven content stay German-only.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New hero (dual subwoofers + purple-lit amp panels) is dark enough
top-to-bottom that the transparent header's white text/icons read
cleanly without any pill or backing behind the logo - removed that
workaround entirely. The old hero photo moves into the "Einblicke"
gallery grid instead of being dropped.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The logo has a transparent PNG background with a dark-gray wordmark,
so it needs a light backing to stay readable over the dark hero photo
- switched from solid white to a translucent frosted white (bg-white/50
+ backdrop-blur) so it reads darker/toned-down while keeping contrast.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drops the phone/WhatsApp/shop row that sat above the main navbar row
(still reachable via the fullscreen menu). On the homepage, the header
now starts fully transparent - merged with the hero image, icons in
white - and only becomes the opaque bar once the user scrolls past a
small threshold. Other pages keep the normal opaque header throughout,
since they don't have a hero to merge with.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 12% fade zone from the previous commit looked like a smeared band
rather than a subtle transition. Narrowed it to 3%.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the flat bg-neutral-950 with a gradient that's transparent at
the top/bottom edges and solid black through the middle, so the
section blends into the surrounding page background instead of
starting/ending abruptly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Used the frontend-design and ui-ux-pro-max skills to research a
Porsche/Rolex-level premium direction. Both point the same way: drop
visible surface texture (grain, dot grids) entirely, use a tiered,
never-pure base color (warm off-white / near-black instead of stark
white/black), and add soft, large ambient glow light instead of decor.
Applied that here with two large low-opacity brand-green radial glows
plus a calmer base tone in both themes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swaps the dot grid for a fine SVG noise grain (evokes lightly crumpled
paper rather than a geometric grid), and darkens the base background
color in both themes so it's not a stark, glaring white/black anymore.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Plain white/black backgrounds now have a faint brand-green dot grid
(24px spacing, very low opacity) instead of a flat fill, in both light
and dark mode. Applied site-wide via the public layout wrapper.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Measured the hamburger icon's rendered vertical position at both
breakpoints and matched the close button's top offset to it precisely
(pixel-exact at 390px and 1280px viewports). Also adds alpha to the
overlay's background gradient so the blurred page content shows
through subtly instead of being fully opaque.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The menu content is now wrapped in the same max-w-6xl mx-auto
container the header uses, so its left inset matches the hamburger
icon's position exactly at every viewport width - previously they only
lined up on narrow screens, since the header's centered container adds
extra outer margin on wide viewports that the overlay wasn't accounting
for.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The single requestAnimationFrame used to trigger the fade-in was
unreliable - the browser could coalesce the hidden and visible states
into one paint, so items appeared instantly instead of fading/flying
in. Switched to a double-rAF, which reliably guarantees a paint of the
hidden state first. Also moves the menu content and close button to
the left side per feedback.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The nav links no longer show inline on desktop - clicking the
hamburger icon now opens the same fullscreen overlay menu on every
screen size, instead of only on mobile.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nav links move back to the left side of the header (theme toggle back
to the right), logo is bigger, and the mobile fullscreen menu now
animates items back out in reverse order when closing instead of just
disappearing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mirrors the old site's Bildergalerie structure: a brand tile grid at
/galerie, project tiles within a brand, and a photo grid with a
lightbox for each project. Backed by new gallery_brands/gallery_projects/
gallery_photos tables and admin CRUD pages, gated by a new gallery.manage
permission.
Also fixes a real bug found while testing photo uploads: Apache's
mod_dir was redirecting POST /api/uploads to /api/uploads/ (a trailing
slash) because api/uploads/ exists as a real directory, silently
dropping the multipart body on every image upload across the whole
app. Fixed via DirectorySlash Off in .htaccess.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swaps navbar layout (theme toggle left, nav links right), replaces the
mobile dropdown with a fullscreen overlay whose items fly in top-to-bottom,
and renames the site-wide "slate" gray to "neutral" to remove a blue
undertone that clashed with the brand green. Also converts the flat
saturated-green YouTube and stats sections into dark backgrounds with
green used only as an accent, matching typical premium car-audio branding.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a Website settings tab (hero image, phone, WhatsApp, email) that
feeds the navbar, footer and contact page via a new SiteSettingsContext,
redesigns the navbar with a bigger centered logo plus phone/WhatsApp/shop
links, and adds a VIN/chassis-number field to the contact form, admin
inbox and notification email.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neben dem Dark/Light-Umschalter erscheint jetzt fuer eingeloggte
Admin-Nutzer ein zusaetzliches Icon, das direkt zu /admin fuehrt -
sowohl Desktop- als auch mobile Navigation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Symptom: Admin-Login zeigte "Cannot read properties of null (reading
'requires_2fa')". Ursache: falls vor den header()-Aufrufen in index.php
irgendeine Ausgabe passiert (z.B. eine PHP-Notice - passiert offenbar auf
PHP 8.4 anders als lokal auf 8.2), geht der Content-Type-Header verloren,
und der Client hat JSON-Antworten dann still als null behandelt statt
sie zu parsen. Backend puffert Ausgaben jetzt und verwirft ungewollten
Output vor den Headern; Client versucht JSON-Parsing jetzt unabhaengig
vom Content-Type-Header und wirft einen klaren Fehler statt still null
zurueckzugeben.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Die fixierte "Bereit fuer deinen Sound-Umbau?"-Leiste auf der Startseite
ueberdeckte am Seitenende die letzte Footer-Zeile (Impressum/Datenschutz/
AGB-Links), da fixed-position Elemente unabhaengig vom Dokumentenfluss
ueber allem liegen. Footer reserviert jetzt auf der Startseite zusaetzlichen
unteren Abstand fuer die Leiste, auf allen anderen Seiten unveraendert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
lucide-react/dynamic erzeugt pro Icon eine eigene Chunk-Datei, was beim
Deploy auf Shared-Hosting (Datei-Upload/Zip-Entpacken über Plesk) an
Datei-Limits scheitert. Per manualChunks jetzt alle Icons in eine
gemeinsame Datei gebündelt (1757 -> 12 Dateien im Build-Output).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Statt Env-Var-gesteuertem Dualbetrieb (lokal /hifi, live /) läuft jetzt
alles einheitlich unter der Domain-Wurzel - auch lokal (siehe neuer
VirtualHost auf Port 8080 in der Apache-Konfiguration, unabhängig von
Port 80 mit /hifi). Dabei einen Doppel-Slash-Bug in der Routenberechnung
gefunden und behoben (base_path '/' + '/api' ergab faelschlich '//api').
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bisher war /hifi an mehreren Stellen fest einprogrammiert (vite base,
Router basename, API-Client, Upload-URLs, .htaccess). Fuer den geplanten
Deploy auf IONOS unter der Domain-Wurzel wird das jetzt ueber
VITE_BASE_PATH (Frontend-Build) bzw. eine optionale base_path.php
(Backend, gleiches Muster wie db.php/setup.php) gesteuert - lokal ohne
diese Werte bleibt alles unveraendert bei /hifi.
.htaccess.ionos enthaelt die Root-Domain-Variante fuer den CI-Build.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Passwortgeschuetzter Assistent fuer die Ersteinrichtung auf einem neuen
Server: Datenbank-Zugangsdaten testen & speichern, Datenbankstruktur
anlegen, ersten Admin-Account erstellen. Sperrt sich danach dauerhaft
selbst, sobald ein Admin-Account existiert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>