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

@ -837,6 +837,24 @@
width: 100%;
}
/* ============================================
STICKY HEADER (Portal-Frontend)
Das Inline-Script in web-master.blade.php schaltet auf
.header-sticky um, sobald die Topbar weggescrollt ist, und
schiebt einen Platzhalter in den Fluss, damit der Inhalt nicht
springt. Ohne diese Regeln blieb der Header wirkungslos.
============================================ */
.header-sticky {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50;
box-shadow:
0 1px 3px rgba(0, 0, 0, 0.08),
0 6px 20px rgba(0, 0, 0, 0.05);
}
/* ============================================
PAGINATION - Gradient für aktive Seite
============================================ */

View file

@ -22,7 +22,7 @@
@endphp
@if ($leadRelease)
<section class="max-w-layout mx-auto px-8 pt-8">
<section class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 pt-8">
<header class="flex items-baseline justify-between mb-4 flex-wrap gap-2">
<h2 class="font-serif text-[28px] font-semibold m-0 tracking-[-0.3px] text-ink">
{{ __('web.hero.title') }}
@ -32,43 +32,41 @@
<hr class="rule-strong mb-6">
<div class="grid gap-9 lg:grid-cols-[1.7fr_1fr] grid-cols-1">
{{-- HERO --}}
{{-- HERO: Text im Flow (min-h + flex), damit lange Titel auf Mobile nicht nach oben überlaufen --}}
<article>
<div class="relative">
<a href="{{ $leadHref }}" class="block group cursor-pointer">
<div class="relative overflow-hidden bg-hero-grad h-[500px]">
@if ($leadImageUrl)
<img src="{{ $leadImageUrl }}" alt="{{ $leadTitle }}"
class="absolute inset-0 h-full w-full object-cover opacity-90 transition-opacity group-hover:opacity-100"
loading="eager">
<div class="absolute inset-0 bg-black/10"></div>
@elseif ($leadPlaceholderUrl)
<img src="{{ $leadPlaceholderUrl }}" alt="" aria-hidden="true"
class="absolute inset-0 h-full w-full object-cover" loading="eager">
@else
<x-web.hero-fallback />
@endif
</div>
<a href="{{ $leadHref }}" class="block group cursor-pointer">
<div class="relative overflow-hidden bg-hero-grad min-h-[320px] sm:min-h-[420px] lg:min-h-[500px] flex flex-col justify-end">
@if ($leadImageUrl)
<img src="{{ $leadImageUrl }}" alt="{{ $leadTitle }}"
class="absolute inset-0 h-full w-full object-cover opacity-90 transition-opacity group-hover:opacity-100"
loading="eager">
<div class="absolute inset-0 bg-black/10"></div>
@elseif ($leadPlaceholderUrl)
<img src="{{ $leadPlaceholderUrl }}" alt="" aria-hidden="true"
class="absolute inset-0 h-full w-full object-cover" loading="eager">
@else
<x-web.hero-fallback />
@endif
<div class="absolute top-6 left-6 flex gap-2">
<div class="absolute top-4 left-4 sm:top-6 sm:left-6 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-9 pb-8 pt-[60px] text-white"
<div class="relative z-10 px-4 sm:px-9 pb-6 sm:pb-8 pt-16 sm:pt-[60px] text-white"
style="background:linear-gradient(180deg,transparent,rgba(0,0,0,0.92));">
@if ($leadCategoryName)
<div class="eyebrow on-dark mb-3">{{ $leadCategoryName }}</div>
@endif
<h1 class="font-serif text-[38px] font-semibold m-0 leading-[1.1] tracking-[-0.7px] max-w-[680px]">
<h1 class="font-serif text-[24px] sm:text-[32px] lg:text-[38px] font-semibold m-0 leading-[1.1] tracking-[-0.7px] max-w-[680px]">
{{ $leadTitle }}
</h1>
<p class="font-serif text-[15px] leading-[1.5] mt-3.5 max-w-[580px] text-white/85">
<p class="font-serif text-[13.5px] sm:text-[15px] leading-[1.5] mt-3 sm:mt-3.5 max-w-[580px] text-white/85">
{{ $leadTeaser }}
</p>
<div class="mt-4 flex items-center gap-3.5 text-[12px] text-white/65 flex-wrap">
<div class="mt-3 sm:mt-4 flex items-center gap-3.5 text-[12px] text-white/65 flex-wrap">
@if ($leadCompany)
<span>{{ $leadCompany }}</span>
<span aria-hidden="true">·</span>
@ -82,8 +80,8 @@
<span>{{ __('web.shared.read_time', ['minutes' => $leadReadTime]) }}</span>
</div>
</div>
</a>
</div>
</div>
</a>
</article>
{{-- SIDEBAR: Was sonst zählt --}}

View file

@ -19,7 +19,7 @@
@if ($context)
<div class="bg-hub-soft border-b border-hub-soft-2">
<div class="max-w-layout mx-auto px-8 py-3 flex items-center gap-4">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 py-3 flex items-center gap-4 flex-wrap">
<span class="inline-flex items-center justify-center w-6 h-6 rounded-full bg-hub text-white flex-shrink-0">
<svg width="11" height="11" viewBox="0 0 12 12" fill="none">
<path d="M7.5 2.5L4 6l3.5 3.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />

View file

@ -11,9 +11,9 @@
@endphp
<footer class="bg-hub-grad-2 text-ink-on-dark">
<div class="max-w-layout mx-auto px-8 py-14 grid gap-10" style="grid-template-columns:1.5fr 1fr 1fr 1fr;">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 py-12 sm:py-14 grid gap-10 grid-cols-1 sm:grid-cols-2 lg:grid-cols-[1.5fr_1fr_1fr_1fr]">
<div>
<div class="sm:col-span-2 lg:col-span-1">
<div class="text-[24px] font-bold leading-none tracking-[-0.5px]">
<x-web.brand-mark brand="pressekonto" variant="on-dark" :serif="false" />
</div>
@ -82,7 +82,7 @@
</div>
<div class="border-t border-white/15">
<div class="max-w-layout mx-auto px-8 py-5 flex items-center justify-between gap-4 text-[11.5px] text-white/55">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 py-5 flex flex-wrap items-center justify-between gap-4 text-[11.5px] text-white/55">
<span>{{ $footerLegal }}</span>
</div>
</div>

View file

@ -24,49 +24,109 @@
];
@endphp
<header class="bg-bg-elev border-b border-bg-rule">
<div class="max-w-layout mx-auto px-8 py-[18px] grid items-center gap-6" style="grid-template-columns:auto 1fr auto;">
<header class="bg-bg-elev border-b border-bg-rule" x-data="{ menuOpen: false }" @keydown.escape.window="menuOpen = false">
<div class="max-w-layout mx-auto px-3 sm:px-6 lg:px-8 py-3 sm:py-[18px] flex items-center gap-2 sm:gap-4">
<a href="{{ route('home') }}" class="flex items-baseline gap-2.5 cursor-pointer group"
<a href="{{ route('home') }}" class="flex items-baseline gap-2.5 cursor-pointer group min-w-0 flex-shrink-0"
aria-label="pressekonto Startseite">
<span class="text-[24px] font-bold tracking-[-0.5px] leading-none text-hub">
<span class="text-[19px] sm:text-[24px] font-bold tracking-[-0.5px] leading-none text-hub">
<x-web.brand-mark brand="pressekonto" :serif="false" />
</span>
<span class="hidden md:inline-block w-px h-[18px] bg-bg-rule"></span>
<span class="eyebrow muted text-[9.5px] tracking-[0.22em]">{{ $brandTagline }}</span>
<span class="eyebrow muted text-[9.5px] tracking-[0.22em] hidden md:inline">{{ $brandTagline }}</span>
</a>
<nav class="hidden lg:flex items-center justify-center gap-1 text-[13.5px] font-medium">
<nav class="hidden lg:flex flex-1 items-center justify-center gap-1 text-[13.5px] font-medium">
@foreach ($navigation as $item)
<a href="{{ $item['href'] }}"
class="px-3.5 py-2 text-ink-2 hover:text-hub transition-colors">{{ $item['label'] }}</a>
@endforeach
</nav>
<div class="flex items-center gap-2">
<span class="flex-1 lg:hidden"></span>
<div class="flex items-center gap-1.5 sm:gap-2 flex-shrink-0">
@auth
<a href="{{ \App\Support\LoginRedirect::homeFor(auth()->user()) }}"
class="inline-flex items-center gap-2 px-[18px] py-2.5 text-[13px] font-semibold text-white bg-hub hover:bg-hub-2 rounded-[4px] transition-colors">
Zum pressekonto
<svg width="11" height="11" viewBox="0 0 12 12" fill="none">
class="inline-flex items-center gap-2 px-3 sm:px-[18px] py-2 sm:py-2.5 text-[12.5px] sm:text-[13px] font-semibold text-white bg-hub hover:bg-hub-2 rounded-[4px] transition-colors">
<span class="sm:hidden">Konto</span>
<span class="hidden sm:inline">Zum pressekonto</span>
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" class="hidden sm:inline" aria-hidden="true">
<path d="M3 9L9 3M9 3H4M9 3v5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</a>
@else
{{-- Auf Mobile in das Burger-Panel verlagert, damit die Kopfzeile bei 320px nicht überläuft. --}}
<a href="{{ route('login') }}"
class="inline-flex items-center gap-2 px-4 py-2.5 text-[13px] font-semibold text-ink rounded-[4px] hover:bg-bg transition-colors">
class="hidden sm:inline-flex items-center gap-2 px-2.5 sm:px-4 py-2 sm:py-2.5 text-[12.5px] sm:text-[13px] font-semibold text-ink rounded-[4px] hover:bg-bg transition-colors">
Anmelden
</a>
<a href="{{ route('register') }}"
class="inline-flex items-center gap-2 px-[18px] py-2.5 text-[13px] font-semibold text-white bg-hub hover:bg-hub-2 rounded-[4px] transition-colors">
class="hidden sm:inline-flex items-center gap-2 px-[18px] py-2.5 text-[13px] font-semibold text-white bg-hub hover:bg-hub-2 rounded-[4px] transition-colors">
Konto erstellen
<svg width="11" height="11" viewBox="0 0 12 12" fill="none">
<svg width="11" height="11" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="M3 9L9 3M9 3H4M9 3v5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</a>
<a href="{{ route('register') }}"
class="sm:hidden inline-flex items-center justify-center px-3 py-2 text-[12.5px] font-semibold text-white bg-hub hover:bg-hub-2 rounded-[4px] transition-colors">
Registrieren
</a>
@endauth
<button type="button"
class="lg:hidden inline-flex items-center justify-center w-10 h-10 text-ink rounded-[4px] hover:bg-bg transition-colors cursor-pointer"
@click="menuOpen = !menuOpen"
:aria-expanded="menuOpen.toString()"
aria-controls="hub-mobile-nav"
aria-label="Menü öffnen">
<svg x-show="!menuOpen" width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
<path d="M3 5h14M3 10h14M3 15h14" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" />
</svg>
<svg x-show="menuOpen" x-cloak width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
<path d="M5 5l10 10M15 5L5 15" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" />
</svg>
</button>
</div>
</div>
<div id="hub-mobile-nav"
x-show="menuOpen"
x-cloak
x-transition.opacity.duration.150ms
class="lg:hidden border-t border-bg-rule bg-bg-elev">
<nav class="max-w-layout mx-auto px-4 sm:px-6 py-3 flex flex-col gap-0.5 text-[14px] font-medium" aria-label="Hauptnavigation">
@foreach ($navigation as $item)
<a href="{{ $item['href'] }}"
@click="menuOpen = false"
class="px-3 py-3 text-ink-2 hover:text-hub hover:bg-bg rounded-[4px] transition-colors">
{{ $item['label'] }}
</a>
@endforeach
{{-- Auth-Einstiege für Mobile (auf sm+ liegen sie in der Kopfzeile). --}}
<div class="mt-2 pt-2 border-t border-bg-rule flex flex-col gap-0.5">
@auth
<a href="{{ \App\Support\LoginRedirect::homeFor(auth()->user()) }}"
@click="menuOpen = false"
class="px-3 py-3 font-semibold text-hub hover:bg-bg rounded-[4px] transition-colors">
Zum pressekonto
</a>
@else
<a href="{{ route('login') }}"
@click="menuOpen = false"
class="px-3 py-3 text-ink-2 hover:text-hub hover:bg-bg rounded-[4px] transition-colors">
Anmelden
</a>
<a href="{{ route('register') }}"
@click="menuOpen = false"
class="px-3 py-3 font-semibold text-hub hover:bg-bg rounded-[4px] transition-colors">
Konto erstellen
</a>
@endauth
</div>
</nav>
</div>
</header>

View file

@ -8,6 +8,7 @@
@php
$displayDate = $date ?? now()->locale('de')->isoFormat('dddd, D. MMMM YYYY');
$shortDate = now()->locale('de')->isoFormat('dd, D. MMM');
$defaultUrls = [
'presseecho' => config('domains.domain_presseecho_url'),
@ -16,36 +17,39 @@
@endphp
<div class="bg-hub-grad text-ink-on-dark-2 border-b border-black/40">
<div class="max-w-layout mx-auto px-8 flex items-stretch text-[11.5px] tracking-wide">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 flex flex-wrap items-center gap-x-3 gap-y-1.5 text-[11.5px] tracking-wide py-2 sm:py-0 sm:items-stretch">
<span class="flex items-center pr-4 py-2.5 whitespace-nowrap border-r border-white/10">
{{ $displayDate }}
<span class="flex items-center sm:pr-4 sm:py-2.5 sm:border-r sm:border-white/10 whitespace-nowrap">
<span class="hidden sm:inline">{{ $displayDate }}</span>
<span class="sm:hidden">{{ $shortDate }}</span>
</span>
<span class="flex items-center gap-2.5 px-4 py-2.5 whitespace-nowrap text-white/70">
<svg width="13" height="13" viewBox="0 0 16 16" fill="none" class="opacity-65">
<span class="flex items-center gap-2 sm:gap-2.5 sm:px-4 sm:py-2.5 min-w-0 text-white/70">
<svg width="13" height="13" viewBox="0 0 16 16" fill="none" class="opacity-65 shrink-0 hidden sm:block">
<rect x="2" y="2" width="5.5" height="5.5" stroke="currentColor" stroke-width="1.2" />
<rect x="8.5" y="2" width="5.5" height="5.5" stroke="currentColor" stroke-width="1.2" />
<rect x="2" y="8.5" width="12" height="5.5" stroke="currentColor" stroke-width="1.2" />
</svg>
<span>Publisher-Hub für</span>
@foreach ($siblingPortals as $index => $portal)
@php
$brandKey = $portal['brand'] ?? 'presseecho';
$portalUrl = $portal['url'] ?? ($defaultUrls[$brandKey] ?? '#');
@endphp
<a href="{{ $portalUrl }}" class="text-white font-semibold hover:underline">
<x-web.brand-mark :brand="$brandKey" variant="on-dark" :serif="false" />
</a>
@if (! $loop->last)
<span class="text-white/30">·</span>
@endif
@endforeach
<span class="hidden md:inline shrink-0">Publisher-Hub für</span>
<span class="flex items-center gap-1.5 sm:gap-2 min-w-0 flex-wrap">
@foreach ($siblingPortals as $index => $portal)
@php
$brandKey = $portal['brand'] ?? 'presseecho';
$portalUrl = $portal['url'] ?? ($defaultUrls[$brandKey] ?? '#');
@endphp
<a href="{{ $portalUrl }}" class="text-white font-semibold hover:underline">
<x-web.brand-mark :brand="$brandKey" variant="on-dark" :serif="false" />
</a>
@if (! $loop->last)
<span class="text-white/30">·</span>
@endif
@endforeach
</span>
</span>
<span class="flex-1"></span>
<span class="flex-1 hidden sm:block"></span>
<span class="flex items-center gap-4 py-2.5 whitespace-nowrap text-white/65">
<span class="flex items-center gap-3 sm:gap-4 sm:py-2.5 whitespace-nowrap text-white/65 ml-auto sm:ml-0">
<a href="{{ route('faq', ['edition' => 'de']) }}" class="hover:text-white transition-colors">FAQ</a>
<a href="{{ route('hilfe', ['edition' => 'de']) }}" class="hover:text-white transition-colors">Hilfe</a>
<button type="button" x-data @click="$dispatch('open-contact-modal')" class="hover:text-white cursor-pointer">Kontakt</button>

View file

@ -17,7 +17,7 @@
@endphp
@if (! empty($industries))
<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">
<header class="flex items-baseline justify-between mb-4 flex-wrap gap-3">
<h2 class="font-serif text-[28px] font-semibold m-0 tracking-[-0.3px] text-ink">{{ __('web.industry_index.title') }}</h2>
<span class="eyebrow muted">{{ __('web.industry_index.window') }}</span>
@ -35,9 +35,9 @@
$barClass = $delta < 0 ? 'bg-brand' : 'bg-gain';
@endphp
<a href="{{ $industry['href'] ?? route('web.home') }}"
class="block px-5 py-[18px] {{ $isLastInRow ? '' : 'md:border-r border-bg-rule' }} {{ $isTopRow ? '' : 'border-t border-bg-rule' }} cursor-pointer hover:bg-bg-elev transition-colors group">
class="block px-4 sm:px-5 py-4 sm:py-[18px] {{ $isLastInRow ? '' : 'md:border-r border-bg-rule' }} {{ $isTopRow ? '' : 'border-t border-bg-rule' }} cursor-pointer hover:bg-bg-elev transition-colors group">
<div class="flex justify-between items-baseline mb-2 gap-2">
<span class="text-[14px] font-semibold text-ink group-hover:text-brand transition-colors">{{ $industry['name'] }}</span>
<span class="text-[13px] sm:text-[14px] font-semibold text-ink group-hover:text-brand transition-colors">{{ $industry['name'] }}</span>
<span class="font-mono text-[12px] font-semibold
@if ($direction === 'gain') text-gain
@elseif ($direction === 'loss') text-loss

View file

@ -10,7 +10,7 @@
@endphp
@if ($industry && $releases->isNotEmpty())
<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">
<header class="flex items-baseline justify-between mb-4 flex-wrap gap-3">
<h2 class="font-serif text-[28px] font-semibold m-0 tracking-[-0.3px] text-ink">
{{ __('web.spotlight.title') }} <span class="text-brand">· {{ $industry }}</span>

View file

@ -16,7 +16,7 @@
@endphp
@if ($plans->isNotEmpty())
<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">
<header class="flex items-baseline justify-between mb-4 flex-wrap gap-3">
<h2 class="font-serif text-[28px] font-semibold m-0 tracking-[-0.3px] text-ink">{{ __('web.pricing_teaser.title') }}</h2>
<a href="{{ $pricingHref }}" class="eyebrow muted hover:text-ink transition-colors inline-flex items-center gap-1.5 cursor-pointer">

View file

@ -1,15 +1,14 @@
@props(['stats' => []])
<section class="max-w-layout mx-auto mt-12 px-8">
<div class="grid items-center gap-7 p-6 bg-bg-card-warm border border-bg-rule-strong"
style="grid-template-columns: auto 1fr auto;">
<section class="max-w-layout mx-auto mt-12 px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 sm:grid-cols-[auto_minmax(0,1fr)_auto] items-start sm:items-center gap-4 sm:gap-7 p-5 sm:p-6 bg-bg-card-warm border border-bg-rule-strong">
<div class="w-11 h-11 rounded-full flex-shrink-0 bg-white border border-bg-rule-strong flex items-center justify-center text-brand">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M12 2l9 4v6c0 5-3.5 9-9 10-5.5-1-9-5-9-10V6z" stroke="currentColor" stroke-width="1.6" fill="none" />
<path d="M8 12l3 3 5-6" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
<div>
<div class="min-w-0">
<div class="eyebrow mb-1">{{ __('web.quality.eyebrow') }}</div>
<div class="text-[13.5px] text-ink leading-[1.5] font-medium">
{{ __('web.quality.claim') }}
@ -18,7 +17,7 @@
</span>
</div>
</div>
<a href="{{ route('richtlinien') }}" class="text-[12px] font-semibold text-brand whitespace-nowrap underline underline-offset-[3px] decoration-brand/40 cursor-pointer hover:text-brand-deep hover:decoration-brand transition-colors">
<a href="{{ route('richtlinien') }}" class="text-[12px] font-semibold text-brand sm:whitespace-nowrap underline underline-offset-[3px] decoration-brand/40 cursor-pointer hover:text-brand-deep hover:decoration-brand transition-colors">
{{ __('web.quality.guidelines') }} →
</a>
</div>

View file

@ -64,7 +64,7 @@
@foreach ($editions as $edition)
<a href="{{ route('web.home', ['edition' => $edition['code']]) }}"
class="flex items-center gap-1 sm:gap-1.5 px-1.5 sm:px-2.5 py-2 text-[11px] sm:text-[11.5px] whitespace-nowrap -mb-px border-b-2 transition-colors
class="flex items-center gap-1 sm:gap-1.5 px-2 sm:px-2.5 py-2.5 text-[11px] sm:text-[11.5px] whitespace-nowrap -mb-px border-b-2 transition-colors
@if ($edition['code'] === $activeEdition) font-semibold text-ink-on-dark bg-white/[0.06] border-brand
@else font-medium text-ink-on-dark-2 border-transparent hover:text-ink-on-dark hover:bg-white/[0.04] @endif"
aria-label="{{ __('web.header.edition') }} {{ $edition['label'] }}"
@ -103,9 +103,9 @@
@keydown.escape.window="searchOpen = false; loginOpen = false"
@keydown.window.prevent.cmd.k="$refs.desktopSearch ? $refs.desktopSearch.focus() : searchOpen = true"
@keydown.window.prevent.ctrl.k="$refs.desktopSearch ? $refs.desktopSearch.focus() : searchOpen = true">
<div class="max-w-layout mx-auto px-4 sm:px-6 lg:px-8 py-3 lg:py-[18px] flex items-center gap-3 sm:gap-4 lg:gap-6">
<a href="{{ route('web.home') }}" class="block cursor-pointer group flex-shrink-0" aria-label="{{ $brandName }}{{ $brandAccent }} {{ __('web.header.homepage') }}">
<div class="text-[22px] sm:text-[24px] lg:text-[28px] font-semibold leading-none tracking-[-0.5px]">
<div class="max-w-layout mx-auto px-3 sm:px-6 lg:px-8 py-3 lg:py-[18px] flex items-center gap-2 sm:gap-4 lg:gap-6">
<a href="{{ route('web.home') }}" class="block cursor-pointer group flex-shrink-0 min-w-0" aria-label="{{ $brandName }}{{ $brandAccent }} {{ __('web.header.homepage') }}">
<div class="text-[19px] sm:text-[24px] lg:text-[28px] font-semibold leading-none tracking-[-0.5px] truncate">
<x-web.brand-mark :brand="$themeKey" />
</div>
<div class="eyebrow muted mt-1 text-[9.5px] tracking-[0.18em] hidden sm:block">
@ -168,7 +168,7 @@
{{-- Veröffentlichen --}}
<a href="{{ route('veroeffentlichen') }}"
class="inline-flex items-center gap-1.5 sm:gap-2 px-3 sm:px-4 lg:px-[18px] py-2 lg:py-2.5 text-[12.5px] sm:text-[13px] font-semibold text-white bg-brand cursor-pointer hover:bg-brand-deep rounded-[2px] transition-colors whitespace-nowrap"
class="inline-flex items-center gap-1.5 sm:gap-2 px-2.5 sm:px-4 lg:px-[18px] py-2 lg:py-2.5 text-[12.5px] sm:text-[13px] font-semibold text-white bg-brand cursor-pointer hover:bg-brand-deep rounded-[2px] transition-colors whitespace-nowrap"
aria-label="{{ __('web.header.publish_aria') }}">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" class="sm:hidden" aria-hidden="true">
<path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" />
@ -391,7 +391,7 @@
<div class="max-w-layout mx-auto px-4 sm:px-6 py-2">
@foreach (collect($navigation)->concat($moreNavigation) as $item)
<a href="{{ $item['href'] }}"
class="flex items-center justify-between px-3 py-3 text-[14px] border-b border-bg-rule last:border-b-0 cursor-pointer transition-colors
class="flex items-center justify-between px-3 py-3 text-[14px] border-b border-bg-rule cursor-pointer transition-colors
@if ($item['active'] ?? false) font-semibold text-brand bg-brand/[0.04]
@else font-medium text-ink-2 hover:text-ink hover:bg-bg @endif">
<span>{{ $item['label'] }}</span>
@ -406,6 +406,19 @@
@endif
</a>
@endforeach
{{-- Service-Links: auf Mobile sonst nur im Footer erreichbar (FAQ/API liegen in der Topbar hinter lg:). --}}
<div class="mt-1 pt-1">
@foreach ([['label' => __('web.header.pricing'), 'href' => route('preise')], ['label' => 'FAQ', 'href' => route('faq')], ['label' => 'API', 'href' => route('api')]] as $service)
<a href="{{ $service['href'] }}"
class="flex items-center justify-between px-3 py-3 text-[13.5px] border-b border-bg-rule last:border-b-0 font-medium text-ink-3 hover:text-ink hover:bg-bg cursor-pointer transition-colors">
<span>{{ $service['label'] }}</span>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="text-ink-4" aria-hidden="true">
<path d="M4 2l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</a>
@endforeach
</div>
</div>
</div>
</nav>

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>