web: Responsive-/Mobile-Fixes fürs öffentliche Frontend

Behebt strukturelle Mobile-Bugs (320/390px) über presseecho,
businessportal24 und den pressekonto-Hub hinweg:

- Focus-/Kategorie-/Newsroom-Hero: Text im Flow (min-h + flex) statt
  fester Höhe, responsive Typo — Overlay überläuft nicht mehr nach oben.
- Quality-Summary: Grid stackt auf Mobile (behebt Seiten-Overflow).
- Hub: Utility-Bar mit Wrap, Header mit Mobile-Burger, Footer stackt,
  Architektur-Diagramm als gestapelte Mobile-Variante.
- Sticky-Header (Portal): fehlende .header-sticky-CSS ergänzt und Script
  mit Platzhalter, damit der Header beim Scrollen sichtbar bleibt.
- Header-Overflow bei 320px entschärft (Portal + Hub); Hub-Hero-H1
  verkleinert, damit die Wortmarke "businessportal24" umbricht.
- Mobile-Nav um Preise/FAQ/API ergänzt; Industry-Index-Dichte,
  Touch-Targets und Preise-Einzel-PM-Block für kleine Screens verbessert.
- Homepages/Shared: px-8 → px-4 sm:px-6 lg:px-8.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin Adametz 2026-07-16 09:33:49 +00:00
parent 9c67fc6c14
commit dec524989b
19 changed files with 263 additions and 118 deletions

View file

@ -27,7 +27,7 @@
:side-releases="$sideReleases ?? []"
:boosted-ids="$boostedIds ?? []" />
<section class="max-w-layout mx-auto px-8 mt-16">
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 mt-16">
<div class="grid gap-9 grid-cols-1 lg:grid-cols-[1.7fr_1fr]">
<livewire:web.press-release-feed :portal="\App\Enums\Portal::Businessportal24->value" :language="app()->getLocale()" />

View file

@ -119,8 +119,9 @@
<div class="grid gap-9 lg:grid-cols-[1.7fr_1fr]">
<article>
<a href="{{ route('release.detail', ['slug' => $leadRelease->slug]) }}" class="block group">
{{-- Kein hatch-dark: dessen background-image würde den bg-hero-grad-Verlauf überschreiben. --}}
<div class="relative overflow-hidden bg-hero-grad" style="aspect-ratio: 16 / 10;">
{{-- Kein hatch-dark: dessen background-image würde den bg-hero-grad-Verlauf überschreiben.
Text im Flow (min-h + flex), damit lange Titel auf Mobile nicht geclippt werden. --}}
<div class="relative overflow-hidden bg-hero-grad min-h-[240px] sm:min-h-[300px] lg:min-h-[360px] flex flex-col justify-end">
@if ($leadImageUrl)
<img src="{{ $leadImageUrl }}" alt="{{ $leadRelease->title }}" class="absolute inset-0 w-full h-full object-cover" loading="lazy">
@elseif ($leadPlaceholderUrl)
@ -128,23 +129,23 @@
@else
<x-web.hero-fallback />
@endif
<div class="absolute top-5 left-5 flex gap-2">
<div class="absolute top-4 left-4 sm:top-5 sm:left-5 z-10 flex gap-2">
<span class="bp-tag">{{ __('web.hero.top_story') }}</span>
@if (in_array($leadRelease->id, $boostedIds ?? [], true))
<span class="bp-tag">{{ __('web.shared.boosted_placement') }}</span>
@endif
</div>
<div class="absolute left-0 right-0 bottom-0 px-6 sm:px-9 pb-8 pt-[70px] text-white" style="background:linear-gradient(180deg,transparent,rgba(0,0,0,0.92));">
<div class="relative z-10 px-4 sm:px-9 pb-6 sm:pb-8 pt-14 sm:pt-[70px] text-white" style="background:linear-gradient(180deg,transparent,rgba(0,0,0,0.92));">
@if ($leadCatName)
<div class="eyebrow mb-3" style="color:#FF8B6F;">{{ $leadCatName }}</div>
@endif
<h2 class="font-serif text-[26px] sm:text-[32px] font-semibold m-0 leading-[1.12] tracking-[-0.6px] max-w-[680px] group-hover:text-white">
<h2 class="font-serif text-[22px] sm:text-[28px] lg:text-[32px] font-semibold m-0 leading-[1.12] tracking-[-0.6px] max-w-[680px] group-hover:text-white">
{{ $leadRelease->title }}
</h2>
@if ($leadLead)
<p class="font-serif text-[14.5px] leading-[1.5] mt-3.5 max-w-[600px] text-white/85">{{ $leadLead }}</p>
<p class="font-serif text-[13.5px] sm:text-[14.5px] leading-[1.5] mt-3 sm:mt-3.5 max-w-[600px] text-white/85">{{ $leadLead }}</p>
@endif
<div class="mt-[18px] flex items-center gap-3.5 text-[12px] text-white/70 flex-wrap">
<div class="mt-3.5 sm:mt-[18px] flex items-center gap-3.5 text-[12px] text-white/70 flex-wrap">
@if ($leadCompany)
<span class="inline-flex items-center gap-1.5">
<svg width="11" height="11" viewBox="0 0 11 11" style="color:#5BC07A;" aria-hidden="true"><circle cx="5.5" cy="5.5" r="5" fill="currentColor"/><path d="M3 5.5l1.8 1.8L8 4" stroke="white" stroke-width="1.4" fill="none" stroke-linecap="round"/></svg>

View file

@ -84,31 +84,48 @@
let topbarHeight = topbar.offsetHeight;
let isHeaderSticky = false;
// Platzhalter hält im Fluss die Header-Höhe frei, sobald der
// Header per position:fixed aus dem Fluss genommen wird —
// ohne den Spacer würde der Inhalt beim Fixieren nach oben springen.
const spacer = document.createElement('div');
spacer.setAttribute('aria-hidden', 'true');
function makeSticky() {
spacer.style.height = header.offsetHeight + 'px';
header.parentNode.insertBefore(spacer, header);
header.classList.remove('header-normal');
header.classList.add('header-sticky');
isHeaderSticky = true;
}
function clearSticky() {
header.classList.remove('header-sticky');
header.classList.add('header-normal');
if (spacer.parentNode) {
spacer.parentNode.removeChild(spacer);
}
isHeaderSticky = false;
}
function updateHeaderPosition() {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop >= topbarHeight && !isHeaderSticky) {
// TopBar ist nicht mehr sichtbar - Header wird sticky
header.classList.remove('header-normal');
header.classList.add('header-sticky');
isHeaderSticky = true;
makeSticky();
} else if (scrollTop < topbarHeight && isHeaderSticky) {
// TopBar ist wieder sichtbar - Header wird normal
header.classList.remove('header-sticky');
header.classList.add('header-normal');
isHeaderSticky = false;
clearSticky();
}
}
// Initial check
updateHeaderPosition();
// Listen for scroll events
window.addEventListener('scroll', updateHeaderPosition);
window.addEventListener('scroll', updateHeaderPosition, { passive: true });
// Listen for resize events (in case topbar height changes)
window.addEventListener('resize', function() {
topbarHeight = topbar.offsetHeight;
if (isHeaderSticky) {
spacer.style.height = header.offsetHeight + 'px';
}
updateHeaderPosition();
});
});

View file

@ -148,8 +148,9 @@
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 mt-10">
<article>
<a href="{{ route('release.detail', ['slug' => $leadRelease->slug]) }}" class="block group">
{{-- Kein hatch-dark: dessen background-image würde den bg-hero-grad-Verlauf überschreiben. --}}
<div class="relative overflow-hidden bg-hero-grad" style="aspect-ratio: 16 / 9;">
{{-- Kein hatch-dark: dessen background-image würde den bg-hero-grad-Verlauf überschreiben.
Text im Flow (min-h + flex), damit lange Titel auf Mobile nicht geclippt werden. --}}
<div class="relative overflow-hidden bg-hero-grad min-h-[220px] sm:min-h-[280px] lg:min-h-[340px] flex flex-col justify-end">
@if ($leadImageUrl)
<img src="{{ $leadImageUrl }}" alt="{{ $leadRelease->title }}" class="absolute inset-0 w-full h-full object-cover" loading="lazy">
@elseif ($leadPlaceholderUrl)
@ -157,20 +158,20 @@
@else
<x-web.hero-fallback />
@endif
<div class="absolute top-5 left-5 flex gap-2">
<div class="absolute top-4 left-4 sm:top-5 sm:left-5 z-10 flex gap-2">
<span class="bp-tag">{{ __('web.newsroom_page.latest') }}</span>
</div>
<div class="absolute left-0 right-0 bottom-0 px-6 sm:px-9 pb-8 pt-[70px] text-white" style="background:linear-gradient(180deg,transparent,rgba(0,0,0,0.92));">
<div class="relative z-10 px-4 sm:px-9 pb-6 sm:pb-8 pt-14 sm:pt-[70px] text-white" style="background:linear-gradient(180deg,transparent,rgba(0,0,0,0.92));">
@if ($leadCatName)
<div class="eyebrow mb-3" style="color:#FF8B6F;">{{ $leadCatName }}</div>
@endif
<h2 class="font-serif text-[26px] sm:text-[34px] font-semibold m-0 leading-[1.12] tracking-[-0.6px] max-w-[760px] group-hover:text-white">
<h2 class="font-serif text-[22px] sm:text-[28px] lg:text-[34px] font-semibold m-0 leading-[1.12] tracking-[-0.6px] max-w-[760px] group-hover:text-white">
{{ $leadRelease->title }}
</h2>
@if ($leadLead)
<p class="font-serif text-[14.5px] leading-[1.5] mt-3.5 max-w-[640px] text-white/85">{{ $leadLead }}</p>
<p class="font-serif text-[13.5px] sm:text-[14.5px] leading-[1.5] mt-3 sm:mt-3.5 max-w-[640px] text-white/85">{{ $leadLead }}</p>
@endif
<div class="mt-[18px] flex items-center gap-3.5 text-[12px] text-white/70 flex-wrap">
<div class="mt-3.5 sm:mt-[18px] flex items-center gap-3.5 text-[12px] text-white/70 flex-wrap">
@if ($leadRelease->published_at)
<span class="font-mono">{{ $leadRelease->published_at->translatedFormat('d.m.Y · H:i') }}</span>
<span aria-hidden="true">·</span>

View file

@ -154,7 +154,7 @@
<p class="text-[13.5px] leading-[1.6] text-ink-2 m-0 max-w-[560px]">
{{ __('pricing.single.description') }}
</p>
<div class="flex items-center gap-6 md:flex-col md:items-end md:gap-3">
<div class="flex flex-wrap items-center gap-4 md:flex-col md:flex-nowrap md:items-end md:gap-3">
<div class="md:text-right">
<div class="font-serif text-[34px] font-semibold leading-none tracking-[-0.6px] text-ink">{{ $euro($singlePmPriceCents) }}&nbsp;€</div>
<div class="text-[11.5px] text-ink-3 mt-1">{{ __('pricing.single.price_suffix') }} · {{ __('pricing.single.net') }}</div>

View file

@ -27,7 +27,7 @@
:side-releases="$sideReleases ?? []"
:boosted-ids="$boostedIds ?? []" />
<section class="max-w-layout mx-auto px-8 mt-16">
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 mt-16">
<div class="grid gap-9 grid-cols-1 lg:grid-cols-[1.7fr_1fr]">
<livewire:web.press-release-feed :portal="\App\Enums\Portal::Presseecho->value" :language="app()->getLocale()" />

View file

@ -25,13 +25,13 @@
{{-- ============== HERO ============== --}}
<section class="hero-grid">
<div
class="max-w-layout mx-auto px-8 pt-16 lg:pt-20 pb-20 lg:pb-24 grid items-start gap-10 lg:gap-12 grid-cols-1 lg:grid-cols-[1.4fr_1fr]">
class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-12 sm:pt-16 lg:pt-20 pb-16 sm:pb-20 lg:pb-24 grid items-start gap-10 lg:gap-12 grid-cols-1 lg:grid-cols-[1.4fr_1fr]">
<div>
<div class="section-eyebrow mb-6">Publisher-Hub</div>
<h1
class="text-[40px] sm:text-[48px] lg:text-[56px] font-bold leading-[1.05] tracking-[-1.2px] text-ink m-0">
class="text-[34px] sm:text-[48px] lg:text-[56px] font-bold leading-[1.05] tracking-[-1.2px] text-ink m-0">
Ein Konto.<br />
Zwei Reichweiten.<br />
<x-web.brand-mark brand="presseecho" /> und <x-web.brand-mark brand="businessportal24" />.
@ -102,7 +102,41 @@
<div class="relative bg-bg-elev border border-bg-rule rounded-[4px] p-7">
<div class="eyebrow muted mb-5">Architektur</div>
<div class="relative mx-auto" style="width:100%;height:320px;">
{{-- Mobile: gestapelte Karten. Ab lg: Diagramm mit absolut positionierten Knoten. --}}
<div class="lg:hidden flex flex-col gap-3">
<div class="px-3.5 py-3 bg-white border border-bg-rule rounded-[3px]">
<div class="text-[10px] font-bold tracking-[0.18em] uppercase text-ink-3">Brand-Portal</div>
<div class="text-[14px] font-bold text-ink mt-0.5 tracking-[-0.2px]">
<x-web.brand-mark brand="presseecho" />
</div>
<div class="text-[10.5px] text-ink-3 mt-0.5">Branchen-Presse · Archiv</div>
</div>
<div class="mx-auto w-[120px] h-[120px] rounded-full bg-hub-grad flex flex-col items-center justify-center text-white shadow-lg shadow-hub/30 text-center">
<div class="text-[10px] font-bold tracking-[0.22em] uppercase text-hub-line">Hub</div>
<div class="text-[14px] font-bold tracking-[-0.3px] mt-1">
<x-web.brand-mark brand="pressekonto" variant="on-dark" :serif="false" />
</div>
</div>
<div class="px-3.5 py-3 bg-white border border-bg-rule rounded-[3px]">
<div class="text-[10px] font-bold tracking-[0.18em] uppercase text-ink-3">Brand-Portal</div>
<div class="text-[14px] font-bold text-ink mt-0.5 tracking-[-0.2px]">
<x-web.brand-mark brand="businessportal24" />
</div>
<div class="text-[10.5px] text-ink-3 mt-0.5">Wirtschaft · Live</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div class="px-3.5 py-2 bg-bg border border-bg-rule rounded-[3px]">
<div class="text-[10px] text-ink-3 tracking-[0.14em] uppercase font-semibold">Veröffentlichung</div>
<div class="font-mono text-[13px] font-semibold text-ink mt-0.5">2× Portale, 1× Klick</div>
</div>
<div class="px-3.5 py-2 bg-bg border border-bg-rule rounded-[3px]">
<div class="text-[10px] text-ink-3 tracking-[0.14em] uppercase font-semibold">Reichweite</div>
<div class="font-mono text-[13px] font-semibold text-ink mt-0.5">zusammengeführt</div>
</div>
</div>
</div>
<div class="relative mx-auto hidden lg:block" style="width:100%;height:320px;">
<svg class="absolute inset-0" width="100%" height="100%" viewBox="0 0 380 320"
preserveAspectRatio="none">
<line x1="190" y1="160" x2="80" y2="60" stroke="var(--color-hub)"
@ -168,7 +202,7 @@
<hr class="rule mt-2" />
<div class="grid grid-cols-3 gap-4 mt-4">
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-4">
<div>
<div
class="font-mono text-[20px] font-semibold text-hub leading-none tracking-[-0.3px] tabular-nums">
@ -201,7 +235,7 @@
<hr class="rule" />
{{-- ============== WAS SIE HIER KÖNNEN ============== --}}
<section class="max-w-layout mx-auto px-8 pt-16 lg:pt-20 pb-12 lg:pb-16">
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-16 lg:pt-20 pb-12 lg:pb-16">
<header class="mb-10 flex flex-col lg:flex-row lg:items-baseline lg:justify-between gap-3">
<div>
<div class="section-eyebrow mb-4">Was Sie hier können</div>
@ -307,7 +341,7 @@
</section>
{{-- ============== SO FUNKTIONIERT ES — 4 STEPS ============== --}}
<section id="funktion" class="max-w-layout mx-auto px-8 pt-8 lg:pt-10 pb-16 lg:pb-20">
<section id="funktion" class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-8 lg:pt-10 pb-16 lg:pb-20">
<header class="mb-8">
<div class="section-eyebrow mb-4">So funktioniert es</div>
<h2
@ -383,7 +417,7 @@
{{-- ============== TARIFE ============== --}}
<section id="tarife" class="bg-hub-soft/40 border-y border-bg-rule" x-data="{ interval: 'monthly' }">
<div class="max-w-layout mx-auto px-8 pt-16 lg:pt-20 pb-16 lg:pb-20">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-16 lg:pt-20 pb-16 lg:pb-20">
<header class="mb-10 lg:mb-12 grid items-end gap-6 grid-cols-1 lg:grid-cols-[1fr_auto]">
<div>
@ -531,7 +565,7 @@
</section>
{{-- ============== PLATTFORM-FAMILIE ============== --}}
<section id="familie" class="max-w-layout mx-auto px-8 pt-16 lg:pt-20 pb-12 lg:pb-16">
<section id="familie" class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-16 lg:pt-20 pb-12 lg:pb-16">
<header class="mb-10">
<div class="section-eyebrow mb-4">Hinter pressekonto</div>
<h2
@ -661,7 +695,7 @@
<hr class="rule" />
{{-- ============== PLATTFORM IN ZAHLEN ============== --}}
<section class="max-w-layout mx-auto px-8 pt-12 lg:pt-16 pb-12 lg:pb-16">
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-12 lg:pt-16 pb-12 lg:pb-16">
<header class="mb-8 grid items-baseline gap-2 lg:gap-6 grid-cols-1 lg:grid-cols-[auto_1fr]">
<div class="section-eyebrow">Die Plattform in Zahlen</div>
<div class="text-[12px] text-ink-3 font-mono text-left lg:text-right">Stand
@ -712,7 +746,7 @@
{{-- ============== FAQ ============== --}}
<section id="faq" class="bg-bg-elev border-y border-bg-rule">
<div
class="max-w-layout mx-auto px-8 pt-12 lg:pt-16 pb-12 lg:pb-16 grid gap-10 lg:gap-12 grid-cols-1 lg:grid-cols-[1fr_2fr]">
class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-12 lg:pt-16 pb-12 lg:pb-16 grid gap-10 lg:gap-12 grid-cols-1 lg:grid-cols-[1fr_2fr]">
<div>
<div class="section-eyebrow mb-4">Häufige Fragen</div>
@ -890,7 +924,7 @@
</section>
{{-- ============== CTA-Wiederholung ============== --}}
<section class="max-w-layout mx-auto px-8 pt-12 lg:pt-16 pb-12 lg:pb-16">
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-12 lg:pt-16 pb-12 lg:pb-16">
<div
class="grid items-center gap-6 lg:gap-8 px-6 lg:px-10 py-10 lg:py-12 bg-hub-grad text-ink-on-dark rounded-[4px] relative overflow-hidden grid-cols-1 lg:grid-cols-[1fr_auto]">
<svg class="absolute inset-0 opacity-10 pointer-events-none" width="100%" height="100%"

View file

@ -405,7 +405,7 @@
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" class="transition-transform group-open:rotate-45"><path d="M6 2v8M2 6h8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
</span>
</summary>
<div class="text-[14px] leading-[1.6] text-ink-2 max-w-[640px] pb-[22px] pl-[60px]">{{ $faq['a'] }}</div>
<div class="text-[14px] leading-[1.6] text-ink-2 max-w-[640px] pb-[22px] pl-0 sm:pl-[60px]">{{ $faq['a'] }}</div>
</details>
@endforeach
</div>