diff --git a/hifi-src/src/i18n/de.js b/hifi-src/src/i18n/de.js
index d40ed8a..83fe8ed 100644
--- a/hifi-src/src/i18n/de.js
+++ b/hifi-src/src/i18n/de.js
@@ -155,6 +155,8 @@ export default {
productLoading: 'Produkt wird geladen…',
requestContact: 'Kontakt anfragen',
featuredBadge: 'Empfohlen',
+ moreBullets: (n) => (n === 1 ? '+ 1 weitere Leistung' : `+ ${n} weitere Leistungen`),
+ lessBullets: 'Weniger anzeigen',
},
leistungen: {
metaTitle: 'Leistungen',
diff --git a/hifi-src/src/i18n/en.js b/hifi-src/src/i18n/en.js
index 1af9c9c..4a7e732 100644
--- a/hifi-src/src/i18n/en.js
+++ b/hifi-src/src/i18n/en.js
@@ -155,6 +155,8 @@ export default {
productLoading: 'Loading product…',
requestContact: 'Request contact',
featuredBadge: 'Recommended',
+ moreBullets: (n) => (n === 1 ? '+ 1 more feature' : `+ ${n} more features`),
+ lessBullets: 'Show less',
},
leistungen: {
metaTitle: 'Services',
diff --git a/hifi-src/src/pages/public/ModelPage.jsx b/hifi-src/src/pages/public/ModelPage.jsx
index 09fbb13..78b2fa9 100644
--- a/hifi-src/src/pages/public/ModelPage.jsx
+++ b/hifi-src/src/pages/public/ModelPage.jsx
@@ -85,6 +85,172 @@ const PRICE_COLOR = '#f2f2f2';
const LABEL_COLOR = '#8a8a8a';
const BULLET_COLOR = '#c4c4c4';
+// Mehr sichtbare Stichpunkte wuerden das Straßenbild verdraengen - gerade bei den teuren
+// Paketen (die laut Kunde die laengsten Listen haben) soll die Kachel ruhig bleiben. Der
+// Rest steckt hinter einem "+X weitere Leistungen"-Toggle, dessen Zaehler selbst als
+// Wertigkeitssignal wirkt.
+const VISIBLE_BULLETS = 5;
+
+function PackageCard({ pkg, tier, tierT, isStripLayout, bullets, formatPrice, contactUrl, t }) {
+ const [expanded, setExpanded] = useState(false);
+ const hiddenCount = bullets.length - VISIBLE_BULLETS;
+ const shownBullets = expanded ? bullets : bullets.slice(0, VISIBLE_BULLETS);
+
+ // Fuer die Themes ohne eigenes Straßenbild: neutrales Glow-Motiv, per Maske
+ // in die Akzentfarbe eingefaerbt (zwei Ebenen: weicher Halo + scharfe Kontur).
+ const glowMask = tier.img
+ ? null
+ : {
+ backgroundColor: tier.accent,
+ WebkitMaskImage: `url(${roadGlowTexture})`,
+ maskImage: `url(${roadGlowTexture})`,
+ maskMode: 'luminance',
+ WebkitMaskSize: 'cover',
+ maskSize: 'cover',
+ WebkitMaskPosition: 'center',
+ maskPosition: 'center',
+ WebkitMaskRepeat: 'no-repeat',
+ maskRepeat: 'no-repeat',
+ };
+
+ return (
+
+ {/* Vollflaechiges Straßen-Glow-Bild der Preisstufe (Referenzdesign). */}
+ {tier.img ? (
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+ {pkg.is_featured && (
+
+ {t('modelPage.featuredBadge')}
+
+ )}
+
+ {/* Kopf: Name + Trennlinie (exakt Referenz). */}
+
+
+ {/* Stichpunkte direkt unter dem Kopf, leicht abgedunkelter Hintergrund fuer
+ Lesbarkeit ueber dem Straßenbild - aufgeklappt deckender, da die Liste dann
+ weiter ins helle Bildzentrum hineinreicht. */}
+ {bullets.length > 0 && (
+
+
+ {shownBullets.map((line, i) => (
+
+
+ {line}
+
+ ))}
+
+ {hiddenCount > 0 && (
+
setExpanded((e) => !e)}
+ className="mt-2.5 flex items-center gap-1 hover:opacity-80"
+ style={{ fontSize: '13px', color: tier.accent }}
+ >
+ {expanded ? t('modelPage.lessBullets') : t('modelPage.moreBullets')(hiddenCount)}
+
+
+ )}
+
+ )}
+
+ {/* Freiraum, damit das Straßenbild zur Geltung kommt. */}
+
+
+ {/* Preis-Sektion mit dunklem Verlauf (Referenz): "ab ca." + Preis + CTA. */}
+
+
+
{t('modelPage.totalPrice')}
+
+ {formatPrice(pkg.total_price)}
+
+
+ {t('modelPage.requestContact')}
+
+
+
+
+ );
+}
+
export default function ModelPage() {
const { brandSlug, modelSlug } = useParams();
const [data, setData] = useState(null);
@@ -189,150 +355,26 @@ export default function ModelPage() {
{packages.map((pkg) => {
const { tier, tierT } = tierOf(pkg);
- const bullets = bulletsOf(pkg);
- // Fuer die Themes ohne eigenes Straßenbild: neutrales Glow-Motiv, per Maske
- // in die Akzentfarbe eingefaerbt (zwei Ebenen: weicher Halo + scharfe Kontur).
- const glowMask = tier.img
- ? null
- : {
- backgroundColor: tier.accent,
- WebkitMaskImage: `url(${roadGlowTexture})`,
- maskImage: `url(${roadGlowTexture})`,
- maskMode: 'luminance',
- WebkitMaskSize: 'cover',
- maskSize: 'cover',
- WebkitMaskPosition: 'center',
- maskPosition: 'center',
- WebkitMaskRepeat: 'no-repeat',
- maskRepeat: 'no-repeat',
- };
-
return (
-
- {/* Vollflaechiges Straßen-Glow-Bild der Preisstufe (Referenzdesign). */}
- {tier.img ? (
-
- ) : (
- <>
-
-
- >
- )}
-
- {pkg.is_featured && (
-
- {t('modelPage.featuredBadge')}
-
- )}
-
- {/* Kopf: Name + Trennlinie (exakt Referenz). */}
-
-
- {/* Stichpunkte direkt unter dem Kopf (von oben nach unten), leicht
- abgedunkelter Hintergrund fuer Lesbarkeit ueber dem Straßenbild. */}
- {bullets.length > 0 && (
-
- {bullets.map((line, i) => (
-
-
- {line}
-
- ))}
-
- )}
-
- {/* Freiraum, damit das Straßenbild zur Geltung kommt. */}
-
-
- {/* Preis-Sektion mit dunklem Verlauf (Referenz): "ab ca." + Preis + CTA. */}
-
-
-
{t('modelPage.totalPrice')}
-
- {formatPrice(pkg.total_price)}
-
-
- {t('modelPage.requestContact')}
-
-
-
-
+ pkg={pkg}
+ tier={tier}
+ tierT={tierT}
+ isStripLayout={isStripLayout}
+ bullets={bulletsOf(pkg)}
+ formatPrice={formatPrice}
+ contactUrl={contactUrl}
+ t={t}
+ />
);
})}