Fix mobile/responsive view across all pages and components
Comprehensive mobile pass over every page, form, layout and shared component: eliminate horizontal overflow, switch fixed-vh sections to auto height, collapse multi-column grids to single column, scale down display typography and padding, enforce 44px tap targets, and ensure embedded gold forms render and scroll without clipping on small screens. All changes gated behind isMobile; desktop layout unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import MunichSkylineBg from '@/components/ui/munich-skyline-bg';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
|
||||
@@ -15,6 +16,7 @@ export const TESTIMONIALS = [
|
||||
export default function TestimonialsSection() {
|
||||
const [active, setActive] = useState(0);
|
||||
const t = TESTIMONIALS[active];
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const prev = () => setActive(i => (i - 1 + TESTIMONIALS.length) % TESTIMONIALS.length);
|
||||
const next = () => setActive(i => (i + 1) % TESTIMONIALS.length);
|
||||
@@ -22,20 +24,20 @@ export default function TestimonialsSection() {
|
||||
return (
|
||||
<section style={{ background: '#fff', overflow: 'hidden', position: 'relative', isolation: 'isolate' }}>
|
||||
<MunichSkylineBg />
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '42% 58%', height: 560, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '42% 58%', height: isMobile ? 'auto' : 560, position: 'relative', zIndex: 1 }}>
|
||||
{/* Left — portrait photo */}
|
||||
<div style={{ position: 'relative', overflow: 'hidden' }}>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', height: isMobile ? 280 : 'auto' }}>
|
||||
<img
|
||||
key={t.img}
|
||||
src={t.img}
|
||||
alt={t.name}
|
||||
style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'top', display: 'block', transition: 'opacity 0.4s' }}
|
||||
/>
|
||||
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to right, transparent 60%, #fff 100%)' }} />
|
||||
<div style={{ position: 'absolute', inset: 0, background: isMobile ? 'linear-gradient(to bottom, transparent 70%, #fff 100%)' : 'linear-gradient(to right, transparent 60%, #fff 100%)' }} />
|
||||
</div>
|
||||
|
||||
{/* Right — quote */}
|
||||
<div style={{ padding: '80px 72px 80px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
|
||||
<div style={{ padding: isMobile ? '40px 22px 56px' : '80px 72px 80px 56px', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: '#4A8FC9', textTransform: 'uppercase', letterSpacing: '0.3em', fontWeight: 700, display: 'block', marginBottom: 32 }}>Stimmen der Preisträger</span>
|
||||
|
||||
<p style={{ fontFamily: FF, fontSize: 'clamp(1.4rem, 2.2vw, 2rem)', fontWeight: 300, color: '#101828', lineHeight: 1.55, margin: '0 0 40px' }}>
|
||||
@@ -50,13 +52,13 @@ export default function TestimonialsSection() {
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 40 }}>
|
||||
<button onClick={prev} style={{ width: 40, height: 40, border: '1.5px solid #D0D5DD', background: 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.15s' }}
|
||||
<button onClick={prev} style={{ width: isMobile ? 44 : 40, height: isMobile ? 44 : 40, border: '1.5px solid #D0D5DD', background: 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.15s' }}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.borderColor = '#111D55'; (e.currentTarget as HTMLElement).style.background = '#111D55'; (e.currentTarget as HTMLElement).style.color = '#fff'; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.borderColor = '#D0D5DD'; (e.currentTarget as HTMLElement).style.background = 'transparent'; (e.currentTarget as HTMLElement).style.color = 'inherit'; }}
|
||||
>
|
||||
<ChevronRight size={16} style={{ transform: 'rotate(180deg)' }} />
|
||||
</button>
|
||||
<button onClick={next} style={{ width: 40, height: 40, border: '1.5px solid #111D55', background: '#111D55', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.15s', color: '#fff' }}
|
||||
<button onClick={next} style={{ width: isMobile ? 44 : 40, height: isMobile ? 44 : 40, border: '1.5px solid #111D55', background: '#111D55', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.15s', color: '#fff' }}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = '#EFBF04'; (e.currentTarget as HTMLElement).style.borderColor = '#EFBF04'; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = '#111D55'; (e.currentTarget as HTMLElement).style.borderColor = '#111D55'; }}
|
||||
>
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
ProcessCardBody,
|
||||
ProcessCardTitle,
|
||||
} from '@/components/ui/process-timeline';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
const FB = '"Inter", sans-serif';
|
||||
@@ -21,6 +22,61 @@ const STEPS = [
|
||||
];
|
||||
|
||||
export default function WegZurAuszeichnungSection() {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
// ── MOBILE: stacked vertical list (no scroll-jack, no horizontal overflow) ──
|
||||
if (isMobile) {
|
||||
return (
|
||||
<section id="schritte" style={{ background: NAVY, padding: '56px 22px' }}>
|
||||
{/* Section header */}
|
||||
<div style={{ marginBottom: 36 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: '#4A8FC9', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 12 }}>Schritt für Schritt</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(1.9rem, 8vw, 2.6rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', lineHeight: 1.05, margin: '0 0 16px' }}>
|
||||
IHR WEG ZUR<br />AUSZEICHNUNG.
|
||||
</h2>
|
||||
<p style={{ fontFamily: FB, fontSize: 15, color: 'rgba(255,255,255,0.65)', lineHeight: 1.7, margin: 0 }}>
|
||||
Von der Einreichung bis zur Gala — vier klar definierte Schritte auf dem Weg zur höchsten Auszeichnung des bayerischen Mittelstands.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Stacked step cards */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
{STEPS.map((item, index) => {
|
||||
const Icon = item.Icon;
|
||||
return (
|
||||
<div key={item.step} style={{ border: '1px solid rgba(239,191,4,0.25)', background: '#111D55', padding: '24px 22px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 20 }}>
|
||||
<div style={{ width: 44, height: 44, border: '1px solid rgba(239,191,4,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
||||
<Icon size={18} style={{ color: GOLD }} strokeWidth={1.5} />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 4 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, color: GOLD, letterSpacing: '0.18em', textTransform: 'uppercase' }}>Schritt {item.step}</span>
|
||||
<span style={{ width: 1, height: 11, background: 'rgba(255,255,255,0.2)' }} />
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: 'rgba(255,255,255,0.62)', letterSpacing: '0.06em' }}>{item.date}</span>
|
||||
</div>
|
||||
<h3 style={{ fontFamily: FF, fontSize: '1.35rem', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.1, margin: 0 }}>
|
||||
{item.title}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p style={{ fontFamily: FB, fontSize: 15, color: 'rgba(255,255,255,0.68)', lineHeight: 1.7, margin: 0 }}>
|
||||
{item.desc}
|
||||
</p>
|
||||
{/* Step progress indicator */}
|
||||
<div style={{ display: 'flex', gap: 4, marginTop: 20 }}>
|
||||
{[0, 1, 2, 3].map(i => (
|
||||
<div key={i} style={{ height: 2, flex: i === index ? 2 : 1, background: i === index ? GOLD : 'rgba(255,255,255,0.1)' }} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ContainerScroll id="schritte" className="h-[380vh]" style={{ background: NAVY }}>
|
||||
<ContainerSticky className="top-0 h-screen flex flex-col">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { ArrowRight, ArrowLeft, Check, Trophy, User, Send, Building2, AlertCircle } from 'lucide-react';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
|
||||
@@ -183,14 +184,15 @@ function Field({ label, error, children, optional, c }: {
|
||||
|
||||
function StyledInput({ c, ...props }: React.InputHTMLAttributes<HTMLInputElement> & { c: C }) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
onFocus={e => { setFocused(true); props.onFocus?.(e); }}
|
||||
onBlur ={e => { setFocused(false); props.onBlur?.(e); }}
|
||||
style={{
|
||||
width: '100%', height: 38, padding: '0 12px',
|
||||
fontFamily: FF, fontSize: 13, color: c.inputText,
|
||||
width: '100%', height: isMobile ? 44 : 38, padding: isMobile ? '0 14px' : '0 12px',
|
||||
fontFamily: FF, fontSize: isMobile ? 16 : 13, color: c.inputText,
|
||||
border: `1px solid ${focused ? c.borderActive : c.inputBorder}`,
|
||||
background: focused ? c.inputBgFocus : c.inputBg,
|
||||
outline: 'none', boxSizing: 'border-box',
|
||||
@@ -221,16 +223,19 @@ function TypeCard({ selected, onClick, title, desc, c }: {
|
||||
);
|
||||
}
|
||||
|
||||
function OptionButton({ selected, onClick, label, c }: {
|
||||
selected: boolean; onClick: () => void; label: string; c: C;
|
||||
function OptionButton({ selected, onClick, label, c, style }: {
|
||||
selected: boolean; onClick: () => void; label: string; c: C; style?: React.CSSProperties;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<button type="button" onClick={onClick} style={{
|
||||
padding: '8px 16px', fontFamily: FF, fontSize: 12, fontWeight: 600, cursor: 'pointer',
|
||||
padding: isMobile ? '12px 18px' : '8px 16px', minHeight: isMobile ? 44 : undefined,
|
||||
fontFamily: FF, fontSize: isMobile ? 14 : 12, fontWeight: 600, cursor: 'pointer',
|
||||
border: `1.5px solid ${selected ? c.optBorderSel : c.optBorder}`,
|
||||
background: selected ? c.optBgSel : c.optBg,
|
||||
color: selected ? c.optTextSel : c.optText,
|
||||
transition: 'all 0.15s',
|
||||
...style,
|
||||
}}>
|
||||
{label}
|
||||
</button>
|
||||
@@ -240,10 +245,12 @@ function OptionButton({ selected, onClick, label, c }: {
|
||||
function YesNo({ value, onChange, c }: {
|
||||
value: 'ja' | 'nein' | ''; onChange: (v: 'ja' | 'nein') => void; c: C;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
const flexStyle = isMobile ? { flex: 1 } : undefined;
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<OptionButton selected={value === 'ja'} onClick={() => onChange('ja')} label="Ja" c={c} />
|
||||
<OptionButton selected={value === 'nein'} onClick={() => onChange('nein')} label="Nein" c={c} />
|
||||
<OptionButton selected={value === 'ja'} onClick={() => onChange('ja')} label="Ja" c={c} style={flexStyle} />
|
||||
<OptionButton selected={value === 'nein'} onClick={() => onChange('nein')} label="Nein" c={c} style={flexStyle} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -256,6 +263,7 @@ function isEligible(data: FormData) {
|
||||
|
||||
export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'gold' }) {
|
||||
const c = theme === 'gold' ? GOLD : DARK;
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const [step, setStep] = useState(0);
|
||||
const [dir, setDir] = useState(1);
|
||||
@@ -362,7 +370,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ padding: '20px 28px', flex: 1, minHeight: 0, overflowX: 'hidden', overflowY: 'auto' }}>
|
||||
<div style={{ padding: isMobile ? '18px 20px' : '20px 28px', flex: 1, minHeight: 0, overflowX: 'hidden', overflowY: 'auto' }}>
|
||||
<AnimatePresence mode="wait" custom={dir}>
|
||||
<motion.div key={`${step}-${data.type}`} custom={dir} variants={variants}
|
||||
initial="enter" animate="center" exit="exit"
|
||||
@@ -373,7 +381,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<div>
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 8 }}>Schritt 1</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 16, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em', marginBottom: 14 }}>Art der Einreichung</h3>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<div style={{ display: 'flex', flexDirection: isMobile ? 'column' : 'row', gap: 8 }}>
|
||||
<TypeCard c={c} selected={data.type === 'selbst'} title="Eigenbewerbung"
|
||||
desc="Ich bewerbe mein eigenes Unternehmen für den Bayerischen Mittelstandspreis."
|
||||
onClick={() => { set('type', 'selbst'); setDir(1); setStep(1); }} />
|
||||
@@ -437,7 +445,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 6 }}>Kontakt</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 16, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>Ihre Kontaktdaten</h3>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: 14 }}>
|
||||
<Field c={c} label="Firmenname" error={errors.firmenname}>
|
||||
<StyledInput c={c} value={data.firmenname} onChange={e => set('firmenname', e.target.value)} placeholder="Muster GmbH" />
|
||||
</Field>
|
||||
@@ -474,7 +482,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
].map(row => (
|
||||
<div key={row.label} style={{ display: 'grid', gridTemplateColumns: '90px 1fr', gap: 12, padding: '10px 0', borderBottom: `1px solid ${c.border}`, alignItems: 'baseline' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, color: c.rowLabel, textTransform: 'uppercase', letterSpacing: '0.12em' }}>{row.label}</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 13, color: c.rowValue }}>{row.value}</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 13, color: c.rowValue, overflowWrap: 'anywhere' }}>{row.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -488,7 +496,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 6 }}>Nominierung</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 16, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>Nominiertes Unternehmen</h3>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: 14 }}>
|
||||
<Field c={c} label="Firmenname" error={errors.nomFirma}>
|
||||
<StyledInput c={c} value={data.nomFirma} onChange={e => set('nomFirma', e.target.value)} placeholder="Muster GmbH" />
|
||||
</Field>
|
||||
@@ -509,7 +517,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<p style={{ fontFamily: FF, fontSize: 10, color: c.accentLabel, textTransform: 'uppercase', letterSpacing: '0.25em', fontWeight: 700, marginBottom: 6 }}>Nominierender</p>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 16, fontWeight: 900, color: c.heading, textTransform: 'uppercase', letterSpacing: '-0.01em' }}>Ihre Angaben</h3>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: 14 }}>
|
||||
<Field c={c} label="Ihr Name" error={errors.nomName}>
|
||||
<StyledInput c={c} value={data.nomName} onChange={e => set('nomName', e.target.value)} placeholder="Vor- und Nachname" />
|
||||
</Field>
|
||||
@@ -542,7 +550,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
].map(row => (
|
||||
<div key={row.label} style={{ display: 'grid', gridTemplateColumns: '100px 1fr', gap: 12, padding: '10px 0', borderBottom: `1px solid ${c.border}`, alignItems: 'baseline' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, color: c.rowLabel, textTransform: 'uppercase', letterSpacing: '0.12em' }}>{row.label}</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 13, color: c.rowValue }}>{row.value}</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 13, color: c.rowValue, overflowWrap: 'anywhere' }}>{row.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -555,12 +563,13 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
|
||||
{/* Navigation */}
|
||||
{step > 0 && (
|
||||
<div style={{ padding: '12px 28px', borderTop: `1px solid ${c.border}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
|
||||
<div style={{ padding: isMobile ? '12px 20px' : '12px 28px', borderTop: `1px solid ${c.border}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
|
||||
<button type="button" onClick={prev} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase',
|
||||
letterSpacing: '0.1em', color: c.backText, background: 'none',
|
||||
border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 5,
|
||||
padding: 0, transition: 'color 0.15s',
|
||||
padding: isMobile ? '12px 4px' : 0, minHeight: isMobile ? 44 : undefined,
|
||||
transition: 'color 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => (e.currentTarget.style.color = c.backTextHover)}
|
||||
onMouseLeave={e => (e.currentTarget.style.color = c.backText)}
|
||||
@@ -573,7 +582,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<button type="button" onClick={next} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase',
|
||||
letterSpacing: '0.1em', color: c.btnText, background: c.btnBg,
|
||||
border: 'none', cursor: 'pointer', padding: '10px 22px',
|
||||
border: 'none', cursor: 'pointer', padding: isMobile ? '13px 24px' : '10px 22px',
|
||||
display: 'flex', alignItems: 'center', gap: 6, transition: 'background 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = c.btnBgHover; }}
|
||||
@@ -585,7 +594,7 @@ export default function BewerbungsForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<button type="button" onClick={submit} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase',
|
||||
letterSpacing: '0.1em', color: c.btnText, background: c.btnBg,
|
||||
border: 'none', cursor: 'pointer', padding: '10px 22px',
|
||||
border: 'none', cursor: 'pointer', padding: isMobile ? '13px 24px' : '10px 22px',
|
||||
display: 'flex', alignItems: 'center', gap: 6, transition: 'background 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = c.btnBgHover; }}
|
||||
|
||||
@@ -115,14 +115,15 @@ const variants = {
|
||||
|
||||
function StyledInput({ c, ...props }: React.InputHTMLAttributes<HTMLInputElement> & { c: C }) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
onFocus={e => { setFocused(true); props.onFocus?.(e); }}
|
||||
onBlur ={e => { setFocused(false); props.onBlur?.(e); }}
|
||||
style={{
|
||||
width: '100%', height: 42, padding: '0 12px',
|
||||
fontSize: 14, color: c.inputText, fontFamily: FF,
|
||||
width: '100%', height: isMobile ? 46 : 42, padding: '0 12px',
|
||||
fontSize: isMobile ? 16 : 14, color: c.inputText, fontFamily: FF,
|
||||
border: `1.5px solid ${focused ? c.inputBorderFoc : c.inputBorder}`,
|
||||
background: focused ? c.inputBgFocus : c.inputBg,
|
||||
outline: 'none', boxSizing: 'border-box',
|
||||
@@ -135,6 +136,7 @@ function StyledInput({ c, ...props }: React.InputHTMLAttributes<HTMLInputElement
|
||||
|
||||
function StyledTextarea({ c, ...props }: React.TextareaHTMLAttributes<HTMLTextAreaElement> & { c: C }) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<textarea
|
||||
{...props}
|
||||
@@ -142,7 +144,7 @@ function StyledTextarea({ c, ...props }: React.TextareaHTMLAttributes<HTMLTextAr
|
||||
onBlur ={e => { setFocused(false); props.onBlur?.(e); }}
|
||||
style={{
|
||||
width: '100%', padding: '10px 12px',
|
||||
fontSize: 14, color: c.inputText, fontFamily: FF,
|
||||
fontSize: isMobile ? 16 : 14, color: c.inputText, fontFamily: FF,
|
||||
border: `1.5px solid ${focused ? c.inputBorderFoc : c.inputBorder}`,
|
||||
background: focused ? c.inputBgFocus : c.inputBg,
|
||||
outline: 'none', boxSizing: 'border-box',
|
||||
@@ -223,7 +225,7 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
<h3 style={{ fontSize: 20, fontWeight: 800, color: c.successHeading, marginBottom: 10, letterSpacing: '-0.02em', fontFamily: FF }}>
|
||||
Nachricht gesendet
|
||||
</h3>
|
||||
<p style={{ fontSize: 15, color: c.successBody, lineHeight: 1.7, maxWidth: 280, margin: '0 auto', fontFamily: FF }}>
|
||||
<p style={{ fontSize: 15, color: c.successBody, lineHeight: 1.7, maxWidth: 280, margin: '0 auto', fontFamily: FF, overflowWrap: 'anywhere' }}>
|
||||
Danke, <strong style={{ color: c.successHeading }}>{data.name}</strong>. Wir melden uns zeitnah bei{' '}
|
||||
<strong style={{ color: c.successIcon }}>{data.email}</strong>.
|
||||
</p>
|
||||
@@ -313,7 +315,7 @@ export default function KontaktForm({ theme = 'dark' }: { theme?: 'dark' | 'gold
|
||||
<button type="button" onClick={prev} style={{
|
||||
fontSize: 12, fontWeight: 600, color: c.backText, background: 'none', border: 'none', cursor: 'pointer',
|
||||
display: 'flex', alignItems: 'center', justifyContent: isMobile ? 'center' : 'flex-start', gap: 5,
|
||||
padding: isMobile ? '8px 0' : 0, fontFamily: FF, transition: 'color 0.15s',
|
||||
padding: isMobile ? '12px 0' : 0, minHeight: isMobile ? 44 : undefined, fontFamily: FF, transition: 'color 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => (e.currentTarget.style.color = c.backTextHover)}
|
||||
onMouseLeave={e => (e.currentTarget.style.color = c.backText)}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { ArrowRight, ArrowLeft, Check, Layers, Building2, Mail } from 'lucide-react';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
|
||||
const FF = '"IBM Plex Sans", sans-serif';
|
||||
|
||||
@@ -122,14 +123,15 @@ function Field({ c, label, error, children }: { c: C; label: string; error?: str
|
||||
|
||||
function StyledInput({ c, ...props }: React.InputHTMLAttributes<HTMLInputElement> & { c: C }) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
onFocus={e => { setFocused(true); props.onFocus?.(e); }}
|
||||
onBlur ={e => { setFocused(false); props.onBlur?.(e); }}
|
||||
style={{
|
||||
width: '100%', height: 44, padding: '0 14px',
|
||||
fontFamily: FF, fontSize: 14, color: c.inputText,
|
||||
width: '100%', height: isMobile ? 46 : 44, padding: '0 14px',
|
||||
fontFamily: FF, fontSize: isMobile ? 16 : 14, color: c.inputText,
|
||||
border: `1px solid ${focused ? c.inputBorderFoc : c.inputBorder}`,
|
||||
background: focused ? c.inputBgFocus : c.inputBg,
|
||||
outline: 'none', boxSizing: 'border-box',
|
||||
@@ -165,6 +167,7 @@ function PaketCard({ c, pkg, selected, onClick }: { c: C; pkg: typeof PAKETE[0];
|
||||
|
||||
export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'gold' }) {
|
||||
const c = theme === 'gold' ? GOLD : DARK;
|
||||
const isMobile = useIsMobile();
|
||||
const [step, setStep] = useState(0);
|
||||
const [dir, setDir] = useState(1);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
@@ -301,7 +304,9 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<button type="button" onClick={prev} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em',
|
||||
color: c.backText, background: 'none', border: 'none', cursor: 'pointer',
|
||||
display: 'flex', alignItems: 'center', gap: 6, padding: 0, transition: 'color 0.15s',
|
||||
display: 'flex', alignItems: 'center', gap: 6,
|
||||
padding: isMobile ? '12px 4px' : 0, minHeight: isMobile ? 44 : undefined,
|
||||
transition: 'color 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => (e.currentTarget.style.color = c.backTextHover)}
|
||||
onMouseLeave={e => (e.currentTarget.style.color = c.backText)}
|
||||
@@ -314,7 +319,8 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<button type="button" onClick={next} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em',
|
||||
color: c.btnText, background: c.btnBg, border: 'none', cursor: 'pointer',
|
||||
padding: '12px 24px', display: 'flex', alignItems: 'center', gap: 7, transition: 'background 0.15s',
|
||||
padding: isMobile ? '14px 24px' : '12px 24px', minHeight: isMobile ? 44 : undefined,
|
||||
display: 'flex', alignItems: 'center', gap: 7, transition: 'background 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = c.btnBgHover; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = c.btnBg; }}
|
||||
@@ -325,7 +331,8 @@ export default function SponsoringForm({ theme = 'dark' }: { theme?: 'dark' | 'g
|
||||
<button type="button" onClick={submit} style={{
|
||||
fontFamily: FF, fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em',
|
||||
color: c.btnText, background: c.btnBg, border: 'none', cursor: 'pointer',
|
||||
padding: '12px 24px', display: 'flex', alignItems: 'center', gap: 7, transition: 'background 0.15s',
|
||||
padding: isMobile ? '14px 24px' : '12px 24px', minHeight: isMobile ? 44 : undefined,
|
||||
display: 'flex', alignItems: 'center', gap: 7, transition: 'background 0.15s',
|
||||
}}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = c.btnBgHover; }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = c.btnBg; }}
|
||||
|
||||
@@ -256,7 +256,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
<div style={{ display:'flex', alignItems:'center', justifyContent:'flex-end', padding:'0 12px', height:'100%' }}>
|
||||
{/* Mobile CTA */}
|
||||
<Link to="/teilnahme#bewerben"
|
||||
style={{ fontFamily:FF_DISPLAY, fontSize:9, fontWeight:700, textTransform:'uppercase', letterSpacing:'.1em', color:'#101828', background:GOLD, padding:'7px 12px', textDecoration:'none', marginRight:8, whiteSpace:'nowrap' }}
|
||||
style={{ display:'inline-flex', alignItems:'center', minHeight:36, fontFamily:FF_DISPLAY, fontSize:10, fontWeight:700, textTransform:'uppercase', letterSpacing:'.1em', color:'#101828', background:GOLD, padding:'0 14px', textDecoration:'none', marginRight:8, whiteSpace:'nowrap' }}
|
||||
>BMP</Link>
|
||||
{/* Mobile hamburger */}
|
||||
<button
|
||||
@@ -551,10 +551,10 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
</div>
|
||||
|
||||
{/* Mobile secondary links */}
|
||||
<div style={{ padding:'0 24px 24px', display:'flex', flexWrap:'wrap', gap:'10px 24px' }}>
|
||||
<div style={{ padding:'0 24px 24px', display:'flex', flexWrap:'wrap', gap:'4px 8px' }}>
|
||||
{SECONDARY.map(item => (
|
||||
<Link key={item.path} to={item.path} onClick={() => setMobileMenuOpen(false)}
|
||||
style={{ fontSize:12, color:MUTED, textDecoration:'none', fontFamily:FF_BODY }}
|
||||
style={{ display:'inline-flex', alignItems:'center', minHeight:44, padding:'0 8px', fontSize:13, color:MUTED, textDecoration:'none', fontFamily:FF_BODY }}
|
||||
>{item.label}</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useIsMobile } from "@/hooks/useIsMobile";
|
||||
|
||||
// ─── CONSTANTS ────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -210,6 +211,7 @@ function Input({
|
||||
maxLength?: number;
|
||||
}) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
@@ -221,6 +223,8 @@ function Input({
|
||||
onBlur={() => { setFocused(false); onBlur?.(); }}
|
||||
style={{
|
||||
...fieldBase,
|
||||
// ≥16px on mobile prevents iOS auto-zoom on focus
|
||||
fontSize: isMobile ? 16 : fieldBase.fontSize,
|
||||
borderColor: error ? GOLD : focused ? "rgba(239,191,4,0.6)" : "rgba(255,255,255,0.15)",
|
||||
background: focused ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.07)",
|
||||
}}
|
||||
@@ -235,6 +239,7 @@ function Select({
|
||||
options: { value: string; label: string }[]; placeholder?: string; error?: string;
|
||||
}) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<select
|
||||
value={value}
|
||||
@@ -243,6 +248,8 @@ function Select({
|
||||
onBlur={() => setFocused(false)}
|
||||
style={{
|
||||
...fieldBase,
|
||||
// ≥16px on mobile prevents iOS auto-zoom on focus
|
||||
fontSize: isMobile ? 16 : fieldBase.fontSize,
|
||||
cursor: "pointer",
|
||||
appearance: "none",
|
||||
borderColor: error ? GOLD : focused ? "rgba(239,191,4,0.6)" : "rgba(255,255,255,0.15)",
|
||||
@@ -271,6 +278,7 @@ function Textarea({
|
||||
maxLength?: number; error?: string;
|
||||
}) {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<div>
|
||||
<textarea
|
||||
@@ -283,6 +291,8 @@ function Textarea({
|
||||
rows={4}
|
||||
style={{
|
||||
...fieldBase,
|
||||
// ≥16px on mobile prevents iOS auto-zoom on focus
|
||||
fontSize: isMobile ? 16 : fieldBase.fontSize,
|
||||
resize: "vertical",
|
||||
borderColor: error ? GOLD : focused ? "rgba(239,191,4,0.6)" : "rgba(255,255,255,0.15)",
|
||||
background: focused ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,0.07)",
|
||||
@@ -419,8 +429,9 @@ function ReviewRow({ label, value }: { label: string; value: string }) {
|
||||
// ─── PROGRESS BAR ─────────────────────────────────────────────────────────────
|
||||
|
||||
function ProgressBar({ current, total }: { current: number; total: number }) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<div style={{ marginBottom: 36 }}>
|
||||
<div style={{ marginBottom: isMobile ? 24 : 36 }}>
|
||||
{/* Step dots + connecting lines */}
|
||||
<div style={{ position: "relative", display: "flex", alignItems: "center", marginBottom: 12 }}>
|
||||
{/* Background track */}
|
||||
@@ -502,7 +513,21 @@ function ProgressBar({ current, total }: { current: number; total: number }) {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Step labels */}
|
||||
{/* Step labels — full list on desktop; on mobile only the active label
|
||||
(the 5-up text row would overflow / wrap on narrow screens) */}
|
||||
{isMobile ? (
|
||||
<div style={{
|
||||
textAlign: "center",
|
||||
fontSize: 11,
|
||||
fontWeight: 700,
|
||||
letterSpacing: "0.1em",
|
||||
textTransform: "uppercase",
|
||||
color: GOLD,
|
||||
fontFamily: '"IBM Plex Sans", sans-serif',
|
||||
}}>
|
||||
{STEPS.find((s) => s.id === current)?.label} · {current}/{total}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: "flex" }}>
|
||||
{STEPS.map((step) => {
|
||||
const done = step.id < current;
|
||||
@@ -524,6 +549,7 @@ function ProgressBar({ current, total }: { current: number; total: number }) {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -587,6 +613,7 @@ function NavButtons({
|
||||
}: {
|
||||
step: number; onBack: () => void; onNext: () => void; onSubmit: () => void; disabled?: boolean;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
const isLast = step === 5;
|
||||
return (
|
||||
<div style={{
|
||||
@@ -602,7 +629,8 @@ function NavButtons({
|
||||
onClick={onBack}
|
||||
style={{
|
||||
flex: "0 0 auto",
|
||||
padding: "12px 20px",
|
||||
padding: isMobile ? "12px 16px" : "12px 20px",
|
||||
minHeight: 44,
|
||||
background: "transparent",
|
||||
border: "1px solid rgba(255,255,255,0.2)",
|
||||
borderRadius: 8,
|
||||
@@ -613,6 +641,7 @@ function NavButtons({
|
||||
cursor: "pointer",
|
||||
letterSpacing: "0.05em",
|
||||
transition: "all 0.2s",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
(e.target as HTMLButtonElement).style.borderColor = "rgba(255,255,255,0.5)";
|
||||
@@ -633,17 +662,21 @@ function NavButtons({
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: "13px 20px",
|
||||
minHeight: 44,
|
||||
background: disabled ? "rgba(239,191,4,0.3)" : GOLD,
|
||||
border: "none",
|
||||
borderRadius: 8,
|
||||
color: disabled ? "rgba(17,29,85,0.5)" : NAVY,
|
||||
fontFamily: '"IBM Plex Sans", sans-serif',
|
||||
fontSize: 13,
|
||||
// long final-step label needs a smaller size + wrapping on mobile
|
||||
fontSize: isMobile && isLast ? 12 : 13,
|
||||
fontWeight: 700,
|
||||
cursor: disabled ? "not-allowed" : "pointer",
|
||||
letterSpacing: "0.1em",
|
||||
letterSpacing: isMobile && isLast ? "0.04em" : "0.1em",
|
||||
textTransform: "uppercase",
|
||||
transition: "all 0.2s",
|
||||
lineHeight: 1.3,
|
||||
overflowWrap: "anywhere",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (!disabled) (e.target as HTMLButtonElement).style.background = "#f5ca1a";
|
||||
@@ -663,6 +696,7 @@ function NavButtons({
|
||||
function Step1({ data, onChange, errors }: {
|
||||
data: FormData; onChange: (k: keyof FormData, v: string | boolean) => void; errors: Errors;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
const rechtsformen = [
|
||||
"GmbH","GmbH & Co. KG","AG","UG","KG","OHG","GbR",
|
||||
"Einzelunternehmen","e.K.","Sonstige",
|
||||
@@ -672,7 +706,7 @@ function Step1({ data, onChange, errors }: {
|
||||
<>
|
||||
<StepHeading step={1} title="Ihr Unternehmen" subtitle="Angaben zum antragstellenden Unternehmen" />
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0 16px" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr", gap: "0 16px" }}>
|
||||
<div style={{ gridColumn: "1 / -1" }}>
|
||||
<Field label="Firmenname" required error={errors.firmenname}>
|
||||
<Input value={data.firmenname} onChange={(v) => onChange("firmenname", v)} placeholder="Muster GmbH" error={errors.firmenname} />
|
||||
@@ -713,17 +747,18 @@ function Step1({ data, onChange, errors }: {
|
||||
function Step2({ data, onChange, errors }: {
|
||||
data: FormData; onChange: (k: keyof FormData, v: string | boolean) => void; errors: Errors;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<>
|
||||
<StepHeading step={2} title="Kontaktperson" subtitle="Ansprechpartner für die Mitgliedschaft" />
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0 16px" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr", gap: "0 16px" }}>
|
||||
<Field label="Anrede" required error={errors.anrede}>
|
||||
<Select value={data.anrede} onChange={(v) => onChange("anrede", v)}
|
||||
options={[{value:"Herr",label:"Herr"},{value:"Frau",label:"Frau"},{value:"Divers",label:"Divers"}]}
|
||||
placeholder="Bitte wählen" error={errors.anrede} />
|
||||
</Field>
|
||||
<div /> {/* spacer */}
|
||||
{!isMobile && <div />} {/* spacer (desktop only) */}
|
||||
<Field label="Vorname" required error={errors.vorname}>
|
||||
<Input value={data.vorname} onChange={(v) => onChange("vorname", v)} placeholder="Max" error={errors.vorname} />
|
||||
</Field>
|
||||
@@ -755,6 +790,7 @@ function Step2({ data, onChange, errors }: {
|
||||
function Step3({ data, onChange, errors }: {
|
||||
data: FormData; onChange: (k: keyof FormData, v: string | boolean) => void; errors: Errors;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
const beitrag = calcBeitrag(data.mitarbeiter);
|
||||
return (
|
||||
<>
|
||||
@@ -800,7 +836,7 @@ function Step3({ data, onChange, errors }: {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0 16px" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr", gap: "0 16px" }}>
|
||||
<Field label="Gewünschtes Eintrittsdatum" required error={errors.eintrittsdatum}>
|
||||
<Input value={data.eintrittsdatum} onChange={(v) => onChange("eintrittsdatum", v)} type="date" error={errors.eintrittsdatum} />
|
||||
</Field>
|
||||
@@ -826,6 +862,7 @@ function Step3({ data, onChange, errors }: {
|
||||
function Step4({ data, onChange, errors }: {
|
||||
data: FormData; onChange: (k: keyof FormData, v: string | boolean) => void; errors: Errors;
|
||||
}) {
|
||||
const isMobile = useIsMobile();
|
||||
const ibanIsValid = validateIBAN(data.iban);
|
||||
|
||||
return (
|
||||
@@ -849,7 +886,7 @@ function Step4({ data, onChange, errors }: {
|
||||
Ich ermächtige den BMP e.V., Zahlungen von meinem Konto mittels Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die vom BMP e.V. auf mein Konto gezogenen Lastschriften einzulösen. Hinweis: Ich kann innerhalb von acht Wochen, beginnend mit dem Belastungsdatum, die Erstattung des belasteten Betrages verlangen. Es gelten dabei die mit meinem Kreditinstitut vereinbarten Bedingungen. Die Mandatsreferenz wird separat mitgeteilt. Gläubiger-Identifikationsnummer: DE98ZZZ09999999999.
|
||||
</div>
|
||||
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0 16px" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: isMobile ? "1fr" : "1fr 1fr", gap: "0 16px" }}>
|
||||
<div style={{ gridColumn: "1 / -1" }}>
|
||||
<Field label="Kontoinhaber" required error={errors.kontoinhaber}>
|
||||
<Input value={data.kontoinhaber} onChange={(v) => onChange("kontoinhaber", v)} placeholder="Max Mustermann" error={errors.kontoinhaber} />
|
||||
@@ -1084,6 +1121,7 @@ function SuccessScreen() {
|
||||
// ─── MAIN COMPONENT ───────────────────────────────────────────────────────────
|
||||
|
||||
function MembershipWizard() {
|
||||
const isMobile = useIsMobile();
|
||||
const [step, setStep] = useState(1);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [errors, setErrors] = useState<Errors>({});
|
||||
@@ -1162,7 +1200,7 @@ function MembershipWizard() {
|
||||
backdropFilter: "blur(8px)",
|
||||
borderRadius: 16,
|
||||
border: "1px solid rgba(255,255,255,0.08)",
|
||||
padding: "32px 28px",
|
||||
padding: isMobile ? "20px 16px" : "32px 28px",
|
||||
color: WHITE,
|
||||
fontFamily: '"IBM Plex Sans", sans-serif',
|
||||
boxShadow: "0 24px 64px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.06)",
|
||||
@@ -1191,7 +1229,7 @@ function MembershipWizard() {
|
||||
<>
|
||||
<ProgressBar current={step} total={STEPS.length} />
|
||||
|
||||
<div ref={contentRef} style={{ minHeight: 380 }}>
|
||||
<div ref={contentRef} style={{ minHeight: isMobile ? 300 : 380 }}>
|
||||
{step === 1 && <Step1 data={data} onChange={onChange} errors={errors} />}
|
||||
{step === 2 && <Step2 data={data} onChange={onChange} errors={errors} />}
|
||||
{step === 3 && <Step3 data={data} onChange={onChange} errors={errors} />}
|
||||
|
||||
@@ -24,10 +24,10 @@ const buttonVariants = cva(
|
||||
"bg-accent text-accent-foreground shadow-xs hover:bg-accent/90",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
||||
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
||||
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
||||
icon: "size-9",
|
||||
default: "h-9 px-4 py-2 has-[>svg]:px-3 max-md:min-h-11",
|
||||
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5 max-md:min-h-11",
|
||||
lg: "h-10 rounded-md px-6 has-[>svg]:px-4 max-md:min-h-11",
|
||||
icon: "size-9 max-md:min-h-11 max-md:min-w-11",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
||||
@@ -9,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-11 w-full border border-stone-200 bg-white px-4 py-2 text-sm text-[#101828] placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-[#EFBF04] focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50 transition-all",
|
||||
"flex h-11 w-full border border-stone-200 bg-white px-4 py-2 text-base md:text-sm text-[#101828] placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-[#EFBF04] focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50 transition-all",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
@@ -8,7 +8,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[100px] w-full border border-stone-200 bg-white px-4 py-3 text-sm text-[#101828] placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-[#EFBF04] focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50 transition-all resize-none",
|
||||
"flex min-h-[100px] w-full border border-stone-200 bg-white px-4 py-3 text-base md:text-sm text-[#101828] placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-[#EFBF04] focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50 transition-all resize-none",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
@@ -115,11 +115,11 @@ const About: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* Right — full-bleed image */}
|
||||
<div style={{ position: 'relative', overflow: 'hidden' }}>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', minHeight: isMobile ? 220 : undefined }}>
|
||||
<img
|
||||
src="/images/preistraeger-gruppe.jpg"
|
||||
alt="BMP Gala Preisverleihung"
|
||||
style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center', display: 'block' }}
|
||||
style={{ position: isMobile ? 'relative' : 'absolute', inset: 0, width: '100%', height: isMobile ? 220 : '100%', objectFit: 'cover', objectPosition: 'center', display: 'block' }}
|
||||
/>
|
||||
<div style={{ position: 'absolute', inset: 0, background: `linear-gradient(to right, ${CREAM} 0%, transparent 25%), linear-gradient(to top, rgba(3,9,58,0.75) 0%, transparent 60%)` }} />
|
||||
<div style={{ position: 'absolute', bottom: 36, left: 36 }}>
|
||||
@@ -423,6 +423,7 @@ function HighlightCard({ winner }: { winner: import('@/data/winners').Winner })
|
||||
|
||||
function GoalItem({ n, text, sub, last }: { n: string; text: string; sub?: string; last: boolean }) {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<div
|
||||
style={{ display: 'grid', gridTemplateColumns: '36px 1fr', gap: '0 16px', padding: '16px 0', borderBottom: last ? 'none' : '1px solid rgba(255,255,255,0.07)', cursor: 'default', transition: 'background 0.15s', alignItems: 'center' }}
|
||||
@@ -430,9 +431,9 @@ function GoalItem({ n, text, sub, last }: { n: string; text: string; sub?: strin
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, fontWeight: 700, color: hovered ? GOLD : 'rgba(239,191,4,0.45)', letterSpacing: '0.1em', transition: 'color 0.2s' }}>{n}</span>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 12 }}>
|
||||
<div style={{ display: 'flex', flexDirection: isMobile ? 'column' : 'row', justifyContent: 'space-between', alignItems: isMobile ? 'flex-start' : 'baseline', gap: isMobile ? 3 : 12 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 15, fontWeight: 700, color: hovered ? '#fff' : 'rgba(255,255,255,0.75)', textTransform: 'uppercase', letterSpacing: '0.08em', transition: 'color 0.2s' }}>{text}</span>
|
||||
{sub && <span style={{ fontFamily: FB, fontSize: 15, color: 'rgba(255,255,255,0.3)', flexShrink: 0 }}>{sub}</span>}
|
||||
{sub && <span style={{ fontFamily: FB, fontSize: 15, color: 'rgba(255,255,255,0.3)', flexShrink: isMobile ? 1 : 0 }}>{sub}</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function BlogDetail() {
|
||||
<div>
|
||||
|
||||
{/* ── HERO ──────────────────────────────────────────────────────────── */}
|
||||
<section style={{ position: 'relative', height: '70vh', minHeight: 520, overflow: 'hidden', display: 'flex', alignItems: 'flex-end' }}>
|
||||
<section style={{ position: 'relative', height: isMobile ? 'auto' : '70vh', minHeight: 520, overflow: 'hidden', display: 'flex', alignItems: 'flex-end' }}>
|
||||
<img
|
||||
src={article.img}
|
||||
alt={article.title}
|
||||
|
||||
@@ -113,7 +113,7 @@ const Contact: React.FC = () => {
|
||||
{!isMobile && <div style={{ background: 'rgba(255,255,255,0.07)' }} />}
|
||||
|
||||
{/* Right — gold form panel */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden', minHeight: 0, position: 'relative', background: 'linear-gradient(160deg,#DDB84A 0%,#C9A227 52%,#A87800 100%)' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: isMobile ? 'visible' : 'hidden', height: isMobile ? 'auto' : undefined, minHeight: 0, position: 'relative', background: 'linear-gradient(160deg,#DDB84A 0%,#C9A227 52%,#A87800 100%)' }}>
|
||||
<svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 0 }} aria-hidden="true">
|
||||
<defs>
|
||||
<pattern id="kontaktCross" width="18" height="18" patternUnits="userSpaceOnUse">
|
||||
@@ -139,7 +139,7 @@ const Contact: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding: isMobile ? '40px 24px' : '32px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ padding: isMobile ? '36px 20px' : '32px 48px 32px 40px', flex: isMobile ? 'none' : 1, display: 'flex', flexDirection: 'column', minHeight: isMobile ? 480 : 0, position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 10, color: 'rgba(17,29,85,0.5)', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 8 }}>Kontaktformular</span>
|
||||
<h3 style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 'clamp(1.2rem, 1.8vw, 1.6rem)', fontWeight: 900, color: '#111D55', letterSpacing: '-0.025em', textTransform: 'uppercase', lineHeight: 1.1, marginBottom: 24 }}>
|
||||
Schreiben Sie uns
|
||||
|
||||
@@ -221,6 +221,7 @@ const body: React.CSSProperties = {
|
||||
color: 'rgba(58,58,58,0.82)',
|
||||
lineHeight: 1.85,
|
||||
margin: '0 0 16px',
|
||||
overflowWrap: 'anywhere',
|
||||
};
|
||||
|
||||
function Section({ id, title, children }: { id: string; title: string; children: React.ReactNode }) {
|
||||
@@ -231,7 +232,7 @@ function Section({ id, title, children }: { id: string; title: string; children:
|
||||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
<div style={{ background: '#fff', padding: '28px 32px', boxShadow: '0 1px 3px rgba(0,0,0,0.06)' }}>
|
||||
<div style={{ background: '#fff', padding: 'clamp(20px, 5vw, 28px) clamp(20px, 5vw, 32px)', boxShadow: '0 1px 3px rgba(0,0,0,0.06)' }}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
@@ -251,16 +252,18 @@ function SubSection({ num, title, children }: { num: string; title: string; chil
|
||||
}
|
||||
|
||||
function AddressBlock({ children }: { children: React.ReactNode }) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<address style={{ fontFamily: '"Inter", sans-serif', fontSize: 14, color: 'rgba(58,58,58,0.75)', lineHeight: 1.9, fontStyle: 'normal', background: 'rgba(17,29,85,0.04)', padding: '16px 20px', borderLeft: '2px solid rgba(239,191,4,0.4)', marginBottom: 16 }}>
|
||||
<address style={{ fontFamily: '"Inter", sans-serif', fontSize: isMobile ? 15 : 14, color: 'rgba(58,58,58,0.75)', lineHeight: 1.9, fontStyle: 'normal', background: 'rgba(17,29,85,0.04)', padding: '16px 20px', borderLeft: '2px solid rgba(239,191,4,0.4)', marginBottom: 16, overflowWrap: 'anywhere' }}>
|
||||
{children}
|
||||
</address>
|
||||
);
|
||||
}
|
||||
|
||||
function Legal({ children }: { children: React.ReactNode }) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<p style={{ fontFamily: '"Inter", sans-serif', fontSize: 14, color: NAVY, lineHeight: 1.75, background: 'rgba(17,29,85,0.04)', padding: '12px 16px', borderLeft: `3px solid ${NAVY}`, margin: '0 0 16px', fontWeight: 500 }}>
|
||||
<p style={{ fontFamily: '"Inter", sans-serif', fontSize: isMobile ? 15 : 14, color: NAVY, lineHeight: 1.75, background: 'rgba(17,29,85,0.04)', padding: '12px 16px', borderLeft: `3px solid ${NAVY}`, margin: '0 0 16px', fontWeight: 500, overflowWrap: 'anywhere' }}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
|
||||
@@ -97,7 +97,7 @@ export default function EventDetail() {
|
||||
<div style={{ paddingTop: 60, background: CREAM, minHeight: '100vh', fontFamily: '"Inter", sans-serif' }}>
|
||||
|
||||
{/* ── Hero ─────────────────────────────────────────────────────────── */}
|
||||
<section style={{ position: 'relative', height: '65vh', minHeight: 480, overflow: 'hidden' }}>
|
||||
<section style={{ position: 'relative', height: isMobile ? 'auto' : '65vh', minHeight: isMobile ? 520 : 480, overflow: 'hidden' }}>
|
||||
<img
|
||||
src={event.img}
|
||||
alt={event.title}
|
||||
@@ -116,7 +116,7 @@ export default function EventDetail() {
|
||||
</div>
|
||||
|
||||
{/* Hero content */}
|
||||
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: isMobile ? '0 24px 48px' : '40px 80px', zIndex: 10, display: 'flex', flexDirection: isMobile ? 'column' : 'row', justifyContent: 'space-between', alignItems: isMobile ? 'flex-start' : 'flex-end', gap: isMobile ? 20 : 40 }}>
|
||||
<div style={{ position: isMobile ? 'relative' : 'absolute', bottom: 0, left: 0, right: 0, padding: isMobile ? '88px 24px 48px' : '40px 80px', zIndex: 10, display: 'flex', flexDirection: isMobile ? 'column' : 'row', justifyContent: isMobile ? 'flex-end' : 'space-between', alignItems: isMobile ? 'flex-start' : 'flex-end', gap: isMobile ? 20 : 40, minHeight: isMobile ? 520 : undefined, boxSizing: 'border-box' }}>
|
||||
{/* Left */}
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14, flexWrap: 'wrap' }}>
|
||||
@@ -136,15 +136,15 @@ export default function EventDetail() {
|
||||
</div>
|
||||
|
||||
{/* Right — key facts */}
|
||||
<div style={{ display: 'flex', flexDirection: isMobile ? 'row' : 'column', flexWrap: isMobile ? 'wrap' : undefined, gap: 12, flexShrink: 0, background: 'rgba(3,9,58,0.55)', backdropFilter: 'blur(12px)', borderRadius: 16, padding: isMobile ? '16px 20px' : '24px 28px', border: '1px solid rgba(255,255,255,0.1)', width: isMobile ? '100%' : undefined }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, flexShrink: 0, background: 'rgba(3,9,58,0.55)', backdropFilter: 'blur(12px)', borderRadius: 16, padding: isMobile ? '16px 20px' : '24px 28px', border: '1px solid rgba(255,255,255,0.1)', width: isMobile ? '100%' : undefined, boxSizing: 'border-box' }}>
|
||||
{[
|
||||
{ icon: Calendar, label: event.date },
|
||||
{ icon: Clock, label: event.time },
|
||||
{ icon: MapPin, label: `${event.venue}, ${event.location}` },
|
||||
].map(({ icon: Icon, label }, i) => (
|
||||
<div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: isMobile ? 'auto' : undefined }}>
|
||||
<Icon size={15} color={GOLD} />
|
||||
<span style={{ fontSize: 14, color: '#fff', fontWeight: 500 }}>{label}</span>
|
||||
<div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
|
||||
<Icon size={15} color={GOLD} style={{ flexShrink: 0 }} />
|
||||
<span style={{ fontSize: 14, color: '#fff', fontWeight: 500, overflowWrap: 'anywhere' }}>{label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -180,7 +180,13 @@ export default function EventDetail() {
|
||||
<div key={i} style={{
|
||||
padding: '20px 24px',
|
||||
background: i % 2 === 0 ? '#fff' : 'rgba(255,255,255,0.6)',
|
||||
borderRadius: i === 0 ? '12px 0 0 0' : i === 1 ? '0 12px 0 0' : i === event.eckdaten.length - 2 ? '0 0 0 12px' : i === event.eckdaten.length - 1 ? '0 0 12px 0' : '0',
|
||||
borderRadius: isMobile
|
||||
? (i === 0
|
||||
? '12px 12px 0 0'
|
||||
: i === event.eckdaten.length - 1
|
||||
? '0 0 12px 12px'
|
||||
: '0')
|
||||
: (i === 0 ? '12px 0 0 0' : i === 1 ? '0 12px 0 0' : i === event.eckdaten.length - 2 ? '0 0 0 12px' : i === event.eckdaten.length - 1 ? '0 0 12px 0' : '0'),
|
||||
border: '1px solid rgba(3,9,58,0.06)',
|
||||
}}>
|
||||
<div style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.12em', color: 'rgba(58,58,58,0.4)', marginBottom: 6 }}>
|
||||
@@ -195,7 +201,7 @@ export default function EventDetail() {
|
||||
</div>
|
||||
|
||||
{/* CTA */}
|
||||
<div style={{ marginTop: 40, display: 'flex', gap: 12 }}>
|
||||
<div style={{ marginTop: 40, display: 'flex', gap: 12, flexWrap: 'wrap' }}>
|
||||
{event.status === 'anmeldung-offen' && (
|
||||
<Link to="/teilnahme" style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 8,
|
||||
@@ -258,7 +264,7 @@ export default function EventDetail() {
|
||||
)}
|
||||
|
||||
{/* Timeline */}
|
||||
<div style={{ maxHeight: 560, overflowY: 'auto', paddingRight: 4 }}>
|
||||
<div style={{ maxHeight: isMobile ? 'none' : 560, overflowY: isMobile ? 'visible' : 'auto', paddingRight: 4 }}>
|
||||
{event.updates.map((update, i) => (
|
||||
<UpdateCard key={update.id} update={update} index={i} />
|
||||
))}
|
||||
|
||||
@@ -193,8 +193,8 @@ export default function FormularUpload() {
|
||||
<span style={{ fontFamily: FF, fontSize: 11, color: 'rgba(255,255,255,0.3)' }}>{formatBytes(f.size)}</span>
|
||||
{f.status === 'uploading' && <div style={{ width: 14, height: 14, border: '2px solid rgba(255,255,255,0.2)', borderTopColor: GOLD, borderRadius: '50%', animation: 'spin 0.8s linear infinite' }} />}
|
||||
{f.status !== 'uploading' && f.status !== 'done' && (
|
||||
<button onClick={() => remove(i)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'rgba(255,255,255,0.3)', padding: 0, display: 'flex' }}>
|
||||
<X size={14} />
|
||||
<button onClick={() => remove(i)} aria-label="Datei entfernen" style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'rgba(255,255,255,0.3)', padding: isMobile ? 12 : 0, margin: isMobile ? -12 : 0, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
||||
<X size={isMobile ? 18 : 14} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -398,7 +398,7 @@ const Home: React.FC = () => {
|
||||
{/* Subtle radial glow behind left copy */}
|
||||
<div style={{ position: 'absolute', left: -120, top: '50%', transform: 'translateY(-50%)', width: 600, height: 600, borderRadius: '50%', background: 'radial-gradient(circle, rgba(5,26,135,0.35) 0%, transparent 70%)', pointerEvents: 'none' }} />
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', position: 'relative', flex: 1, minHeight: 0, overflow: 'hidden' }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', position: 'relative', flex: isMobile ? 'none' : 1, minHeight: 0, overflow: 'hidden' }}>
|
||||
|
||||
{/* Left — pitch copy */}
|
||||
<div style={{ padding: isMobile ? '32px 24px 24px' : '36px 36px 32px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'center', overflow: 'hidden' }}>
|
||||
@@ -473,7 +473,7 @@ const Home: React.FC = () => {
|
||||
)}
|
||||
|
||||
{/* Form area */}
|
||||
<div style={{ padding: isMobile ? '32px 24px' : '24px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ padding: isMobile ? '32px 24px' : '24px 48px 32px 40px', flex: isMobile ? 'none' : 1, height: isMobile ? '82svh' : undefined, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: 'rgba(17,29,85,0.5)', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 8 }}>Direktbewerbung 2026</span>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 'clamp(1.2rem, 1.8vw, 1.6rem)', fontWeight: 900, color: '#111D55', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.1, marginBottom: 24 }}>Kostenlos bewerben</h3>
|
||||
<BewerbungsForm theme="gold" />
|
||||
@@ -483,8 +483,8 @@ const Home: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* Footnote row */}
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: '14px 56px 18px', display: 'flex', justifyContent: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 15, color: 'rgba(255,255,255,0.45)', marginRight: 10 }}>Kostenlos und unverbindlich —</span>
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: isMobile ? '16px 24px 20px' : '14px 56px 18px', display: 'flex', flexWrap: 'wrap', justifyContent: 'center', textAlign: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 15, color: 'rgba(255,255,255,0.45)', marginRight: isMobile ? 6 : 10 }}>Kostenlos und unverbindlich —</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 15, fontWeight: 700, color: 'rgba(239,191,4,0.8)' }}>keine Teilnahmegebühr</span>
|
||||
</div>
|
||||
<div style={{ height: 2, background: 'linear-gradient(to right, #EFBF04, rgba(239,191,4,0.25), transparent)', flexShrink: 0 }} />
|
||||
|
||||
@@ -216,6 +216,7 @@ const body: React.CSSProperties = {
|
||||
color: 'rgba(58,58,58,0.82)',
|
||||
lineHeight: 1.85,
|
||||
margin: '0 0 16px',
|
||||
overflowWrap: 'anywhere',
|
||||
};
|
||||
|
||||
function Section({ id, title, children }: { id: string; title: string; children: React.ReactNode }) {
|
||||
@@ -226,7 +227,7 @@ function Section({ id, title, children }: { id: string; title: string; children:
|
||||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
<div style={{ background: '#fff', padding: '28px 32px', boxShadow: '0 1px 3px rgba(0,0,0,0.06)' }}>
|
||||
<div style={{ background: '#fff', padding: 'clamp(20px, 5vw, 28px) clamp(20px, 5vw, 32px)', boxShadow: '0 1px 3px rgba(0,0,0,0.06)' }}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,16 +247,18 @@ function SubSection({ num, title, children }: { num: string; title: string; chil
|
||||
}
|
||||
|
||||
function AddressBlock({ children }: { children: React.ReactNode }) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<address style={{ fontFamily: '"Inter", sans-serif', fontSize: 14, color: 'rgba(58,58,58,0.75)', lineHeight: 1.9, fontStyle: 'normal', background: 'rgba(17,29,85,0.04)', padding: '16px 20px', borderLeft: '2px solid rgba(239,191,4,0.4)', marginBottom: 16 }}>
|
||||
<address style={{ fontFamily: '"Inter", sans-serif', fontSize: isMobile ? 15 : 14, color: 'rgba(58,58,58,0.75)', lineHeight: 1.9, fontStyle: 'normal', background: 'rgba(17,29,85,0.04)', padding: '16px 20px', borderLeft: '2px solid rgba(239,191,4,0.4)', marginBottom: 16, overflowWrap: 'anywhere' }}>
|
||||
{children}
|
||||
</address>
|
||||
);
|
||||
}
|
||||
|
||||
function Legal({ children }: { children: React.ReactNode }) {
|
||||
const isMobile = useIsMobile();
|
||||
return (
|
||||
<p style={{ fontFamily: '"Inter", sans-serif', fontSize: 14, color: NAVY, lineHeight: 1.75, background: 'rgba(17,29,85,0.04)', padding: '12px 16px', borderLeft: `3px solid ${NAVY}`, margin: '0 0 16px', fontWeight: 500 }}>
|
||||
<p style={{ fontFamily: '"Inter", sans-serif', fontSize: isMobile ? 15 : 14, color: NAVY, lineHeight: 1.75, background: 'rgba(17,29,85,0.04)', padding: '12px 16px', borderLeft: `3px solid ${NAVY}`, margin: '0 0 16px', fontWeight: 500, overflowWrap: 'anywhere' }}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
|
||||
@@ -240,20 +240,20 @@ function BeitragsrechnerSection({ isMobile }: { isMobile: boolean }) {
|
||||
</button>
|
||||
{tableOpen && (
|
||||
<div style={{ background: '#fff', border: '1px solid rgba(16,24,40,0.12)', borderTop: 'none', borderRadius: '0 0 8px 8px', overflow: 'hidden' }}>
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: FF }}>
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: FF, tableLayout: isMobile ? 'fixed' : 'auto' }}>
|
||||
<thead>
|
||||
<tr style={{ background: NAVY }}>
|
||||
<th style={{ padding: '12px 18px', textAlign: 'left', fontSize: 10, fontWeight: 700, letterSpacing: '0.15em', textTransform: 'uppercase', color: GOLD }}>Mitarbeiter</th>
|
||||
<th style={{ padding: '12px 18px', textAlign: 'right', fontSize: 10, fontWeight: 700, letterSpacing: '0.15em', textTransform: 'uppercase', color: GOLD }}>Netto / Jahr</th>
|
||||
<th style={{ padding: '12px 18px', textAlign: 'right', fontSize: 10, fontWeight: 700, letterSpacing: '0.15em', textTransform: 'uppercase', color: GOLD }}>Brutto / Jahr</th>
|
||||
<th style={{ padding: isMobile ? '10px 10px' : '12px 18px', textAlign: 'left', fontSize: 10, fontWeight: 700, letterSpacing: '0.15em', textTransform: 'uppercase', color: GOLD }}>Mitarbeiter</th>
|
||||
<th style={{ padding: isMobile ? '10px 10px' : '12px 18px', textAlign: 'right', fontSize: 10, fontWeight: 700, letterSpacing: '0.15em', textTransform: 'uppercase', color: GOLD }}>Netto / Jahr</th>
|
||||
<th style={{ padding: isMobile ? '10px 10px' : '12px 18px', textAlign: 'right', fontSize: 10, fontWeight: 700, letterSpacing: '0.15em', textTransform: 'uppercase', color: GOLD }}>Brutto / Jahr</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{BEITRAGS_TIERS.map((t, i) => (
|
||||
<tr key={t.label} style={{ background: i % 2 === 0 ? 'rgba(239,191,4,0.04)' : '#fff', borderBottom: '1px solid rgba(16,24,40,0.06)' }}>
|
||||
<td style={{ padding: '12px 18px', fontSize: 14, color: '#101828', fontWeight: selected === t.label ? 700 : 400 }}>{t.label}</td>
|
||||
<td style={{ padding: '12px 18px', fontSize: 14, textAlign: 'right', color: 'rgba(16,24,40,0.6)' }}>{formatEurLocal(t.annual)}</td>
|
||||
<td style={{ padding: '12px 18px', fontSize: 14, textAlign: 'right', fontWeight: 600, color: selected === t.label ? NAVY : '#101828' }}>{formatEurLocal(t.annual * (1 + BEITRAGS_VAT))}</td>
|
||||
<td style={{ padding: isMobile ? '10px 10px' : '12px 18px', fontSize: isMobile ? 13 : 14, color: '#101828', fontWeight: selected === t.label ? 700 : 400 }}>{t.label}</td>
|
||||
<td style={{ padding: isMobile ? '10px 10px' : '12px 18px', fontSize: isMobile ? 13 : 14, textAlign: 'right', color: 'rgba(16,24,40,0.6)' }}>{formatEurLocal(t.annual)}</td>
|
||||
<td style={{ padding: isMobile ? '10px 10px' : '12px 18px', fontSize: isMobile ? 13 : 14, textAlign: 'right', fontWeight: 600, color: selected === t.label ? NAVY : '#101828' }}>{formatEurLocal(t.annual * (1 + BEITRAGS_VAT))}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -745,7 +745,7 @@ const MitgliedWerden: React.FC = () => {
|
||||
<h1
|
||||
style={{
|
||||
fontFamily: FF,
|
||||
fontSize: 'clamp(2.8rem, 6vw, 5rem)',
|
||||
fontSize: isMobile ? 'clamp(2rem, 9vw, 2.6rem)' : 'clamp(2.8rem, 6vw, 5rem)',
|
||||
fontWeight: 900,
|
||||
color: '#fff',
|
||||
textTransform: 'uppercase',
|
||||
@@ -1157,7 +1157,7 @@ const MitgliedWerden: React.FC = () => {
|
||||
gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr',
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflow: 'hidden',
|
||||
overflow: isMobile ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
{/* Left — pitch */}
|
||||
@@ -1167,7 +1167,7 @@ const MitgliedWerden: React.FC = () => {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
overflow: 'hidden',
|
||||
overflow: isMobile ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
@@ -1255,8 +1255,10 @@ const MitgliedWerden: React.FC = () => {
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: isMobile ? 'column' : 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'baseline',
|
||||
alignItems: isMobile ? 'flex-start' : 'baseline',
|
||||
gap: isMobile ? 4 : 0,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
@@ -1274,7 +1276,7 @@ const MitgliedWerden: React.FC = () => {
|
||||
<span
|
||||
style={{
|
||||
fontFamily: FB,
|
||||
fontSize: 17,
|
||||
fontSize: isMobile ? 15 : 17,
|
||||
color: 'rgba(255,255,255,0.3)',
|
||||
}}
|
||||
>
|
||||
@@ -1295,7 +1297,7 @@ const MitgliedWerden: React.FC = () => {
|
||||
/>
|
||||
|
||||
{/* Right — wizard */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', background: 'rgba(0,0,0,0.18)', overflowY: 'auto', minHeight: 0 }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', background: 'rgba(0,0,0,0.18)', overflowY: isMobile ? 'visible' : 'auto', minHeight: 0 }}>
|
||||
{!isMobile && (
|
||||
<div style={{ height: 180, position: 'relative', overflow: 'hidden', flexShrink: 0 }}>
|
||||
<img src="/images/gewinner-gruppenfoto.jpg" alt="BMP Mitglieder" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'center 30%' }} />
|
||||
@@ -1307,7 +1309,7 @@ const MitgliedWerden: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding: isMobile ? '24px' : '28px 40px 32px', flex: 1, overflowY: 'auto' }}>
|
||||
<div style={{ padding: isMobile ? '24px' : '28px 40px 32px', flex: 1, overflowY: isMobile ? 'visible' : 'auto' }}>
|
||||
<MembershipWizard />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,9 +33,10 @@ interface PersonCardProps {
|
||||
|
||||
function PersonCard({ imgSrc, imgAlt, name, titleLine1, titleLine2, institution, borderRight }: PersonCardProps) {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCard = useIsMobile();
|
||||
return (
|
||||
<div
|
||||
style={{ borderRight: borderRight ? '1px solid rgba(255,255,255,0.08)' : 'none', display: 'flex', flexDirection: 'column' }}
|
||||
style={{ borderRight: borderRight && !isMobileCard ? '1px solid rgba(255,255,255,0.08)' : 'none', borderBottom: borderRight && isMobileCard ? '1px solid rgba(255,255,255,0.08)' : 'none', display: 'flex', flexDirection: 'column' }}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
@@ -48,7 +49,7 @@ function PersonCard({ imgSrc, imgAlt, name, titleLine1, titleLine2, institution,
|
||||
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to top, rgba(3,9,58,0.8) 0%, transparent 60%)', pointerEvents: 'none' }} />
|
||||
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, height: 3, background: GOLD }} />
|
||||
</div>
|
||||
<div style={{ padding: '36px 40px', background: NAVY, flex: 1 }}>
|
||||
<div style={{ padding: isMobileCard ? '28px 24px' : '36px 40px', background: NAVY, flex: 1 }}>
|
||||
<div style={{ fontFamily: FF, fontSize: 20, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.02em', lineHeight: 1.1, marginBottom: 10 }}>{name}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 17, fontWeight: 400, color: `${GOLD}CC`, lineHeight: 1.6, marginBottom: 2 }}>{titleLine1}</div>
|
||||
<div style={{ fontFamily: FF, fontSize: 17, fontWeight: 400, color: 'rgba(255,255,255,0.5)', lineHeight: 1.6 }}>{titleLine2}</div>
|
||||
@@ -69,11 +70,12 @@ interface JuryMember {
|
||||
|
||||
const JuryCard: React.FC<{ member: JuryMember; idx: number }> = ({ member, idx }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCard = useIsMobile();
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
style={{ borderLeft: idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', display: 'flex', flexDirection: 'column', cursor: 'default', background: hovered ? 'rgba(255,255,255,0.03)' : 'transparent', transition: 'background 0.2s' }}
|
||||
style={{ borderLeft: !isMobileCard && idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', borderTop: isMobileCard && idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', display: 'flex', flexDirection: 'column', cursor: 'default', background: hovered ? 'rgba(255,255,255,0.03)' : 'transparent', transition: 'background 0.2s' }}
|
||||
>
|
||||
<div style={{ position: 'relative', overflow: 'hidden', aspectRatio: '3/4' }}>
|
||||
<img src={member.img} alt={member.name} style={{ width: '100%', height: '100%', objectFit: 'cover', filter: hovered ? 'none' : 'grayscale(100%)', transition: 'filter 0.5s', display: 'block' }} />
|
||||
@@ -105,16 +107,17 @@ interface Partner {
|
||||
linkedin?: string;
|
||||
}
|
||||
|
||||
const PartnerCell: React.FC<{ partner: Partner; idx: number; onClick: () => void }> = ({ partner, idx, onClick }) => {
|
||||
const PartnerCell: React.FC<{ partner: Partner; idx: number; total: number; onClick: () => void }> = ({ partner, idx, total, onClick }) => {
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const isMobileCell = useIsMobile();
|
||||
const borderLeft = isMobileCell ? (idx % 2 === 0 ? 'none' : '1px solid rgba(3,9,58,0.08)') : (idx % 4 === 0 ? 'none' : '1px solid rgba(3,9,58,0.08)');
|
||||
const borderLeft = isMobileCell ? 'none' : (idx % 4 === 0 ? 'none' : '1px solid rgba(3,9,58,0.08)');
|
||||
const showBottom = isMobileCell ? idx < total - 1 : idx < 8;
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
style={{ padding: isMobileCell ? '24px 20px' : '36px 32px', borderLeft, borderBottom: (isMobileCell ? idx < 10 : idx < 8) ? '1px solid rgba(3,9,58,0.08)' : 'none', display: 'flex', flexDirection: 'column', gap: 16, cursor: 'pointer', background: hovered ? '#E8E5E4' : 'transparent', transition: 'background 0.15s' }}
|
||||
style={{ padding: isMobileCell ? '24px 20px' : '36px 32px', borderLeft, borderBottom: showBottom ? '1px solid rgba(3,9,58,0.08)' : 'none', display: 'flex', flexDirection: 'column', gap: 16, cursor: 'pointer', background: hovered ? '#E8E5E4' : 'transparent', transition: 'background 0.15s' }}
|
||||
>
|
||||
<div style={{ height: 48, display: 'flex', alignItems: 'center' }}>{partner.logo}</div>
|
||||
<div style={{ width: hovered ? 48 : 20, height: 1, background: GOLD, transition: 'width 0.3s ease' }} />
|
||||
@@ -613,9 +616,9 @@ const Netzwerk: React.FC = () => {
|
||||
Ein starkes Netzwerk für einen starken Mittelstand. Klicken für Details.
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr 1fr' : 'repeat(4, 1fr)' }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(4, 1fr)' }}>
|
||||
{partners.map((partner, idx) => (
|
||||
<PartnerCell key={partner.id} partner={partner} idx={idx} onClick={() => setSelectedPartner(partner)} />
|
||||
<PartnerCell key={partner.id} partner={partner} idx={idx} total={partners.length} onClick={() => setSelectedPartner(partner)} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
@@ -627,9 +630,9 @@ const Netzwerk: React.FC = () => {
|
||||
height: isMobile ? 'auto' : 'calc(100vh - 60px)',
|
||||
display: 'flex', flexDirection: 'column',
|
||||
}}>
|
||||
<div style={{ flex: 1, position: 'relative', zIndex: 1, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', minHeight: 0, overflow: 'hidden' }}>
|
||||
<div style={{ flex: 1, position: 'relative', zIndex: 1, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', minHeight: 0, overflow: isMobile ? 'visible' : 'hidden' }}>
|
||||
{/* Left — pitch */}
|
||||
<div style={{ padding: isMobile ? '32px 24px 24px' : '36px 36px 32px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'center', overflow: 'hidden' }}>
|
||||
<div style={{ padding: isMobile ? '32px 24px 24px' : '36px 36px 32px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'center', overflow: isMobile ? 'visible' : 'hidden' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: GOLD, display: 'block', marginBottom: 8 }}>Wachstum durch Partnerschaft</span>
|
||||
<h2 style={{ fontFamily: FF, fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', fontSize: 'clamp(1.6rem, 2.4vw, 2.4rem)', lineHeight: 1.0, margin: '0 0 12px' }}>WIR FREUEN UNS ÜBER NEUE SPONSOREN.</h2>
|
||||
<div style={{ width: 36, height: 2, background: GOLD, margin: '0 0 14px', flexShrink: 0 }} />
|
||||
@@ -653,7 +656,7 @@ const Netzwerk: React.FC = () => {
|
||||
{/* Center divider */}
|
||||
{!isMobile && <div style={{ background: 'rgba(255,255,255,0.07)' }} />}
|
||||
{/* Right — gold form panel */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden', minHeight: 0, position: 'relative', background: 'linear-gradient(160deg,#DDB84A 0%,#C9A227 52%,#A87800 100%)' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: isMobile ? 'visible' : 'hidden', minHeight: 0, position: 'relative', background: 'linear-gradient(160deg,#DDB84A 0%,#C9A227 52%,#A87800 100%)' }}>
|
||||
<svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 0 }} aria-hidden="true">
|
||||
<defs>
|
||||
<pattern id="sponsoringCross" width="18" height="18" patternUnits="userSpaceOnUse">
|
||||
@@ -679,14 +682,14 @@ const Netzwerk: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding: isMobile ? '32px 24px' : '24px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ padding: isMobile ? '28px 20px' : '24px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: isMobile ? 560 : 0, position: 'relative', zIndex: 1 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, color: 'rgba(17,29,85,0.5)', display: 'block', marginBottom: 8 }}>Sponsoring 2026</span>
|
||||
<SponsoringForm theme="gold" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Footnote */}
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: '14px 56px 18px', display: 'flex', justifyContent: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: isMobile ? '16px 20px 20px' : '14px 56px 18px', display: 'flex', flexWrap: 'wrap', justifyContent: 'center', alignItems: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 15, color: 'rgba(255,255,255,0.45)', marginRight: 10 }}>Oder:</span>
|
||||
<Link
|
||||
to="/mitglied-werden"
|
||||
|
||||
@@ -194,9 +194,9 @@ const Participation: React.FC = () => {
|
||||
|
||||
{/* ── FORM SECTION ─────────────────────────────────────────────────────── */}
|
||||
<section style={{ background: NAVY, position: 'relative', overflow: 'hidden', height: isMobile ? 'auto' : 'calc(100vh - 60px)', display: 'flex', flexDirection: 'column' }} id="bewerben">
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', flex: 1, minHeight: 0, overflow: 'hidden' }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '4fr 1px 8fr', flex: 1, minHeight: 0, overflow: isMobile ? 'visible' : 'hidden' }}>
|
||||
{/* Left — copy */}
|
||||
<div style={{ padding: isMobile ? '32px 24px 24px' : '36px 36px 32px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'center', overflow: 'hidden' }}>
|
||||
<div style={{ padding: isMobile ? '32px 24px 24px' : '36px 36px 32px 52px', display: 'flex', flexDirection: 'column', justifyContent: 'center', overflow: isMobile ? 'visible' : 'hidden' }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: '#EFBF04', textTransform: 'uppercase', letterSpacing: '0.32em', fontWeight: 700, display: 'block', marginBottom: 20 }}>Direktbewerbung</span>
|
||||
<h2 style={{ fontFamily: FF, fontSize: 'clamp(2rem, 3.2vw, 2.8rem)', fontWeight: 900, color: '#fff', textTransform: 'uppercase', letterSpacing: '-0.025em', lineHeight: 1.04, margin: '0 0 20px' }}>
|
||||
BEWERBEN ODER<br />VORSCHLAGEN.
|
||||
@@ -226,7 +226,7 @@ const Participation: React.FC = () => {
|
||||
{!isMobile && <div style={{ background: 'rgba(255,255,255,0.07)' }} />}
|
||||
|
||||
{/* Right — gold form panel */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden', minHeight: 0, position: 'relative', background: 'linear-gradient(160deg,#DDB84A 0%,#C9A227 52%,#A87800 100%)' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', overflow: isMobile ? 'visible' : 'hidden', minHeight: 0, position: 'relative', background: 'linear-gradient(160deg,#DDB84A 0%,#C9A227 52%,#A87800 100%)' }}>
|
||||
<svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 0 }} aria-hidden="true">
|
||||
<defs>
|
||||
<pattern id="participationCross" width="18" height="18" patternUnits="userSpaceOnUse">
|
||||
@@ -252,7 +252,7 @@ const Participation: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ padding: isMobile ? '32px 24px' : '24px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ padding: isMobile ? '28px 20px' : '24px 48px 32px 40px', flex: 1, display: 'flex', flexDirection: 'column', minHeight: isMobile ? 560 : 0, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, marginBottom: 24 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 10, color: 'rgba(17,29,85,0.5)', textTransform: 'uppercase', letterSpacing: '0.28em', fontWeight: 700 }}>Bewerbung 2026</span>
|
||||
<Link
|
||||
@@ -270,7 +270,7 @@ const Participation: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: '14px 56px 18px', display: 'flex', justifyContent: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<div style={{ position: 'relative', zIndex: 1, padding: isMobile ? '16px 20px 20px' : '14px 56px 18px', display: 'flex', justifyContent: 'center', textAlign: 'center', borderTop: '1px solid rgba(255,255,255,0.06)', flexShrink: 0 }}>
|
||||
<Link to="/formular-hochladen" style={{ fontFamily: FF, fontSize: 15, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'rgba(239,191,4,0.7)', textDecoration: 'none', display: 'inline-flex', alignItems: 'center', gap: 6, borderBottom: '1px solid rgba(239,191,4,0.3)', paddingBottom: 1 }}>
|
||||
Formular hochladen →
|
||||
</Link>
|
||||
@@ -315,9 +315,10 @@ function QualRow({ item, Icon, last }: { item: { num: string; title: string; bod
|
||||
|
||||
function CriteriaCell({ crit, idx }: { crit: { percentage: string; title: string; desc: string }; idx: number }) {
|
||||
const [hovered, setHovered] = React.useState(false);
|
||||
const isMobileCell = useIsMobile();
|
||||
return (
|
||||
<div
|
||||
style={{ padding: '56px 40px', borderLeft: idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', display: 'flex', flexDirection: 'column', gap: 0, cursor: 'default', transition: 'background 0.2s', background: hovered ? 'rgba(255,255,255,0.03)' : 'transparent' }}
|
||||
style={{ padding: isMobileCell ? '32px 24px' : '56px 40px', borderLeft: !isMobileCell && idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', borderTop: isMobileCell && idx > 0 ? '1px solid rgba(255,255,255,0.07)' : 'none', display: 'flex', flexDirection: 'column', gap: 0, cursor: 'default', transition: 'background 0.2s', background: hovered ? 'rgba(255,255,255,0.03)' : 'transparent' }}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
|
||||
@@ -55,14 +55,15 @@ export default function Preistraeger() {
|
||||
</h1>
|
||||
|
||||
{/* Year Tabs */}
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 0, marginBottom: 32, borderBottom: `2px solid ${BORDER}` }}>
|
||||
<div style={{ display: 'flex', flexWrap: isMobile ? 'nowrap' : 'wrap', gap: 0, marginBottom: 32, borderBottom: `2px solid ${BORDER}`, overflowX: isMobile ? 'auto' : 'visible', WebkitOverflowScrolling: 'touch', maxWidth: '100%' }}>
|
||||
{YEARS.map(year => (
|
||||
<button
|
||||
key={year}
|
||||
onClick={() => { setActiveYear(year); reset(); }}
|
||||
style={{
|
||||
fontFamily: FF, fontSize: 16, fontWeight: 700,
|
||||
padding: '12px 32px',
|
||||
padding: isMobile ? '12px 20px' : '12px 32px',
|
||||
flexShrink: 0,
|
||||
background: 'none', border: 'none', cursor: 'pointer',
|
||||
color: activeYear === year ? NAVY : GRAY,
|
||||
borderBottom: activeYear === year ? `2px solid ${GOLD}` : '2px solid transparent',
|
||||
@@ -135,7 +136,7 @@ export default function Preistraeger() {
|
||||
|
||||
{/* Grid */}
|
||||
{filtered.length === 0 ? (
|
||||
<div style={{ padding: '80px', textAlign: 'center', color: GRAY, fontFamily: FF }}>
|
||||
<div style={{ padding: isMobile ? '56px 24px' : '80px', textAlign: 'center', color: GRAY, fontFamily: FF }}>
|
||||
Keine Preisträger für diese Auswahl.
|
||||
</div>
|
||||
) : (
|
||||
@@ -162,7 +163,7 @@ export default function Preistraeger() {
|
||||
>
|
||||
Jetzt kostenlos bewerben <ArrowRight size={14} />
|
||||
</Link>
|
||||
<div style={{ marginTop: 20, display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<div style={{ marginTop: 20, display: 'flex', alignItems: 'center', justifyContent: isMobile ? 'center' : undefined, flexWrap: isMobile ? 'wrap' : 'nowrap', gap: 8 }}>
|
||||
<span style={{ width: 20, height: 1, background: 'rgba(239,191,4,0.3)', display: 'inline-block' }} />
|
||||
<span style={{ fontFamily: '"IBM Plex Sans", sans-serif', fontSize: 11, color: 'rgba(16,24,40,0.4)' }}>Diese Arbeit unterstützen:</span>
|
||||
<Link
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function PreistraegerDetail() {
|
||||
|
||||
{/* Header block */}
|
||||
<div style={{ padding: isMobile ? '32px 24px 28px' : '48px 80px 40px', borderBottom: `1px solid ${BORDER}` }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 16 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 16, flexWrap: 'wrap' }}>
|
||||
<span style={{
|
||||
fontFamily: FF, fontSize: 11, fontWeight: 700, color: '#fff',
|
||||
background: NAVY, padding: '4px 14px', borderRadius: 999,
|
||||
@@ -121,7 +121,7 @@ export default function PreistraegerDetail() {
|
||||
].map(row => (
|
||||
<div key={row.label} style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
<span style={{ fontFamily: FF, fontSize: 11, color: GRAY, textTransform: 'uppercase', letterSpacing: '0.08em' }}>{row.label}</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 17, fontWeight: 700, color: '#101828' }}>{row.value}</span>
|
||||
<span style={{ fontFamily: FF, fontSize: 17, fontWeight: 700, color: '#101828', overflowWrap: 'anywhere' }}>{row.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -138,7 +138,7 @@ export default function PreistraegerDetail() {
|
||||
color: '#101828', border: `2px solid ${NAVY}`,
|
||||
padding: '12px 20px', textDecoration: 'none',
|
||||
textTransform: 'uppercase', letterSpacing: '0.08em',
|
||||
transition: 'all 0.2s', borderRadius: 0,
|
||||
transition: 'all 0.2s', borderRadius: 0, overflowWrap: 'anywhere',
|
||||
}}
|
||||
onMouseEnter={e => { const el = e.currentTarget as HTMLElement; el.style.background = NAVY; el.style.color = '#fff'; }}
|
||||
onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = 'transparent'; el.style.color = NAVY; }}
|
||||
|
||||
@@ -111,7 +111,7 @@ function NewsCard({ item, idx, isMobile }: { item: typeof news[0]; idx: number;
|
||||
/>
|
||||
</div>
|
||||
{/* body */}
|
||||
<div style={{ padding: '32px 36px 40px', display: 'flex', flexDirection: 'column', flex: 1 }}>
|
||||
<div style={{ padding: isMobile ? '24px 24px 32px' : '32px 36px 40px', display: 'flex', flexDirection: 'column', flex: 1 }}>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: FF,
|
||||
@@ -294,6 +294,7 @@ const Press: React.FC = () => {
|
||||
letterSpacing: '-0.03em',
|
||||
textTransform: 'uppercase',
|
||||
margin: '0 0 24px',
|
||||
overflowWrap: 'anywhere',
|
||||
}}
|
||||
>
|
||||
EVENTS &<br />BERICHTERSTATTUNG.
|
||||
@@ -399,7 +400,7 @@ const Press: React.FC = () => {
|
||||
<div style={{ padding: isMobile ? '24px 24px 32px' : '40px 56px 40px 48px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
|
||||
<div style={{ fontFamily: FF, fontSize: 9, color: '#4A8FC9', textTransform: 'uppercase' as const, letterSpacing: '0.22em', fontWeight: 700, marginBottom: 10 }}>{event.cat}</div>
|
||||
<h3 style={{ fontFamily: FF, fontSize: 'clamp(1.3rem, 2vw, 1.7rem)', fontWeight: 900, color: '#101828', textTransform: 'uppercase' as const, letterSpacing: '-0.02em', margin: '0 0 14px' }}>{event.title}</h3>
|
||||
<div style={{ display: 'flex', gap: 28, alignItems: 'center', marginBottom: 16 }}>
|
||||
<div style={{ display: 'flex', gap: isMobile ? 16 : 28, alignItems: 'center', flexWrap: 'wrap', marginBottom: 16 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, fontFamily: FB, fontSize: 18, color: 'rgba(16,24,40,0.5)' }}>
|
||||
<Calendar size={14} color={GOLD} />{event.date}
|
||||
</div>
|
||||
@@ -623,6 +624,7 @@ const Press: React.FC = () => {
|
||||
fontSize: 18,
|
||||
color: 'rgba(16,24,40,0.55)',
|
||||
lineHeight: 1.8,
|
||||
overflowWrap: 'anywhere',
|
||||
}}
|
||||
>
|
||||
presse@bmp-bayern.de
|
||||
|
||||
Reference in New Issue
Block a user