// SloppyUniverse Landing — full Manifesto-in-Motion build // All sections live here. CSS is in the host HTML. function App() { // Single-language Landing: 'de' oder 'en'. Default aus localStorage, // sonst Browser-Sprache, sonst 'de'. Toggle in der Topbar. const [lang, setLang] = React.useState(() => { try { var saved = localStorage.getItem('su-landing-lang'); if (saved === 'de' || saved === 'en') return saved; var nav = (navigator.language || 'de').toLowerCase(); return nav.startsWith('en') ? 'en' : 'de'; } catch (e) { return 'de'; } }); React.useEffect(() => { try { localStorage.setItem('su-landing-lang', lang); } catch (e) {} document.documentElement.lang = lang; }, [lang]); const motion = true; const tilt = 0.7; // weniger aggressives Magazine-Tilt const bg = "navy"; React.useEffect(() => { document.documentElement.style.setProperty('--bg', bg === 'navy' ? '#0a0d2e' : '#0d0d0d'); document.documentElement.style.setProperty('--bg-alt', bg === 'navy' ? '#101537' : '#1a1a1a'); document.documentElement.style.setProperty('--tilt', `${tilt}`); document.documentElement.style.setProperty('--motion', motion ? '1' : '0'); }, []); return (
); } // ─── LANGUAGE HELPER ──────────────────────────────────────────────────────── // lang prop = 'de' oder 'en'. Single-language Render — keine Doppelausgabe // mehr (Accessibility + Locale-Erkennung). Sprache wird in der Topbar // umgeschaltet (Pill ist clickable). function Bi({en, de, lang, sep = " · ", className, asBlock}) { const text = lang === 'en' ? en : de; if (asBlock) { return
{text}
; } return {text}; } function pickBi(m, lang) { return lang === 'en' ? m.en : m.de; } function pickBoth(m, lang) { // Backwards-compat fuer Aufrufer die secondary mitlesen — beides gleich. const pri = lang === 'en' ? m.en : m.de; return { primary: pri, secondary: pri }; } // ─── TOPBAR ────────────────────────────────────────────────────────────────── function Topbar({lang, setLang}) { return (
SLOPPYUNIVERSE
{SU_MODULES_DATA.map(m => { const isLive = m.status === 'beta' || m.status === 'live'; return isLive ? ( {m.pair} ) : ( {m.pair} ); })}
LOGIN ↗
); } // ─── HERO ──────────────────────────────────────────────────────────────────── function Hero({lang}) { return (

{SU_HERO.word1} {SU_HERO.word2.split('').map((ch, i) => ( {ch} ))}

SLOPPY
BY
DESIGN
EST. 2026
); } // ─── TICKER ────────────────────────────────────────────────────────────────── function TickerBand({text, color, tiltDir}) { // Repeat text enough to fill 2x viewport for seamless loop const filled = text.repeat(6); return (
{filled} {filled}
); } // ─── MODULES ───────────────────────────────────────────────────────────────── function Modules({lang}) { return (
// 01 · MODULE



{SU_MODULES_DATA.map((m, i) => { const copy = pickBoth(m, lang); // Live + beta-Module verlinken auf das tatsaechliche Modul. SOON- // Module nur auf den In-Page-Anchor (es gibt noch keine Site). const moduleUrls = { pay: 'https://sloppypay.com/', scan: 'https://sloppyscan.com/', fix: 'https://sloppyfix.com/', plan: 'https://sloppyplan.com/', rent: 'https://sloppyrent.com/', }; const isClickable = m.status === 'beta' || m.status === 'live'; const href = isClickable ? moduleUrls[m.key] : `#${m.key}`; const target = isClickable ? '_blank' : undefined; const rel = isClickable ? 'noopener noreferrer' : undefined; return ( {m.status !== 'live' && (
{m.status === 'beta' ? 'BETA' : 'SOON · BALD'}
)}
{m.name}

{m.name}

{copy.primary.tag} · {copy.secondary.tag}
{copy.primary.claim}
{copy.secondary.claim}
{copy.primary.blurb}
{copy.secondary.blurb}
{isClickable ? '↗' : '→'}
); })}
); } // ─── BETA BANNER ───────────────────────────────────────────────────────────── function BetaBanner({lang}) { const primary = lang === 'de' ? SU_BETA.de : SU_BETA.en; const secondary = lang === 'de' ? SU_BETA.en : SU_BETA.de; return (
{primary.badge}
{primary.title}
{secondary.title}
{primary.sub}
{secondary.sub}

{primary.body}

{secondary.body}

{primary.catch}
{secondary.catch}
    {primary.points.map((p, i) => (
  • ·
    {p}
    {secondary.points[i]}
  • ))}
); } // ─── MANIFESTO ─────────────────────────────────────────────────────────────── function Manifesto({lang}) { return (
// 02 · WARUM SLOPPY · WHY SLOPPY



{SU_MANIFESTO.map((line, i) => { const copy = pickBoth(line, lang); return (
{String(i+1).padStart(2,'0')}
{copy.primary}
{copy.secondary}
); })}
); } // ─── DEMO ──────────────────────────────────────────────────────────────────── function Demo({lang}) { return (
// 03 · DEMO · KEIN PDF · NO PDF


); } function DemoScreen({size, mod, lang}) { const m = SU_MODULES_DATA.find(x => x.key === mod); return (
{m.name} {m.name}
{mod === 'scan' && } {mod === 'fix' && } {mod === 'pay' && } {mod === 'rent' && } {mod === 'plan' && }
); } function ScanContent({lang}) { const rows = [ { time:'09:14', who:'L. Becker', status: lang==='de'?'eingecheckt':'checked in', state:'ok' }, { time:'09:32', who:'Handwerker · Tech', status: lang==='de'?'eingecheckt':'checked in', state:'ok' }, { time:'10:01', who:lang==='de'?'Mietinteressent':'Prospective tenant', status: lang==='de'?'wartet':'waiting', state:'pend' }, { time:'10:18', who:lang==='de'?'Ablesung Wasser':'Water meter reading', status: lang==='de'?'eingecheckt':'checked in', state:'ok' }, { time:'11:02', who:lang==='de'?'Möbel-Lieferung':'Furniture delivery', status: lang==='de'?'wartet':'waiting', state:'pend' }, ]; return ( <>
{rows.map((r,i) => (
{r.time} {r.who} {r.status}
))}
); } function FixContent({lang}) { return ( <>
23
· Heizung 3.OG kalt
· Aufzug B steht
· Wasserhahn Whg. 14
); } function PayContent({lang}) { return ( <>
247
· 12
· 3
); } function RentContent({lang}) { return ( <>
96%
· 142
· 6
); } function PlanContent({lang}) { return ( <>
{/* hatched exterior wall */} {/* outer wall thick */} {/* interior walls */} {/* doors (arc + gap) */} {/* windows */} {/* fixtures - kitchen */} {/* bathroom */} {/* room labels */} 3.01 42 m² 3.02 56 m² 3.03 38 m² 3.04 41 m² {/* status dots */} {/* annotation: leaky pipe callout */} ! TICKET #218 {lang==='de'?'Wasserschaden':'water damage'} {/* annotation: vacant since */} {lang==='de'?'FREI · 47 TAGE':'VACANT · 47 DAYS'} {/* dimension line bottom */} 18.40 m {/* north arrow */} N
{lang==='de'?'belegt':'occupied'} · 2 {lang==='de'?'frei':'vacant'} · 1 {lang==='de'?'Schaden':'damage'} · 1
); } // ─── FAQ ───────────────────────────────────────────────────────────────────── function FAQ({lang}) { const [open, setOpen] = React.useState(0); return (
// 04 · FAQ · EHRLICH · HONESTLY


{SU_FAQ.map((item, i) => { const copy = pickBoth(item, lang); const isOpen = open === i; return (
setOpen(isOpen ? -1 : i)}>
{String(i+1).padStart(2,'0')}
{copy.primary.q}
{copy.secondary.q}
{isOpen ? '–' : '+'}
{isOpen && (
{copy.primary.a}
{copy.secondary.a}
)}
); })}
); } // ─── PRICING ───────────────────────────────────────────────────────────────── // Pricing-Section entfernt — waehrend Beta keine Preise kommunizieren. // ─── LOGIN CTA ─────────────────────────────────────────────────────────────── function LoginCTA({lang}) { return (

); } // ─── FOOTER WALL ───────────────────────────────────────────────────────────── function FooterWall({lang}) { return ( ); } window.SU_App = App;