// Quick City — Projekte (Neuaufbau 2026): Aussage-Block, Referenz-Slideshow, Bild-Kollage. // Backup der alten Seite: backups/2026-08-20_pages-info_projekte-alt.jsx function PrjStyles() { React.useEffect(() => { if (document.getElementById('prj-new-styles')) return; const s = document.createElement('style'); s.id = 'prj-new-styles'; s.textContent = ` .pj { --pj-ink:#15151a; --pj-mute:#6f6f78; --pj-line:#e6e5e1; } .pj-wrap { max-width: 1320px; margin: 0 auto; padding: 0 40px; } @media (max-width: 720px) { .pj-wrap { padding: 0 20px; } } .pj-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; } /* BANNER — Vollbild-Bühne mit Kopfbild */ .pj-hero { position: relative; background: #101014; color: #fff; min-height: min(78vh, 720px); display: flex; flex-direction: column; justify-content: flex-end; overflow: hidden; } .pj-hero__bg { position: absolute; inset: 0; } .pj-hero__bg img { width: 100%; height: 100%; object-fit: cover; filter: saturate(0.85) contrast(1.03); } .pj-hero__bg::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(16,16,20,0.5) 0%, rgba(16,16,20,0.14) 34%, rgba(16,16,20,0.78) 100%); } .pj-hero__ph { position: absolute; inset: 0; display: grid; place-items: center; background: repeating-linear-gradient(135deg, #1b1b21 0 14px, #16161b 14px 28px); } .pj-hero__ph span { font-size: 10.5px; font-weight: 800; letter-spacing: 0.24em; text-transform: uppercase; color: rgba(255,255,255,0.28); } .pj-hero__inner { position: relative; z-index: 2; padding: 200px 0 0; } @media (max-width: 900px) { .pj-hero { min-height: 0; } .pj-hero__inner { padding-top: 148px; } } .pj-hero__grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 64px; align-items: end; padding-bottom: 44px; } @media (max-width: 900px) { .pj-hero__grid { grid-template-columns: 1fr; gap: 26px; padding-bottom: 32px; } } .pj-kicker { display: inline-flex; align-items: center; gap: 12px; font-size: 10.5px; font-weight: 800; letter-spacing: 0.34em; text-transform: uppercase; color: #fff; margin-bottom: 20px; } .pj-kicker::before { content: ''; width: 40px; height: 2px; background: var(--accent); } .pj-h1 { font-size: clamp(38px, 6.2vw, 88px); font-weight: 900; line-height: 0.94; letter-spacing: -0.035em; text-transform: none; margin: 0; text-shadow: 0 2px 40px rgba(0,0,0,0.35); } .pj-h1 em { font-style: normal; color: var(--accent); } .pj-lead { font-size: clamp(17px, 1.5vw, 21px); line-height: 1.6; color: rgba(255,255,255,0.9); font-weight: 400; text-wrap: pretty; margin: 0; text-shadow: 0 1px 24px rgba(0,0,0,0.5); } .pj-lead strong { font-weight: 700; color: #fff; } .pj-lead + .pj-lead { margin-top: 16px; } .pj-hero__inset { margin: 26px 0 0; position: relative; max-width: 440px; } .pj-hero__inset img { display: block; width: 100%; aspect-ratio: 16/10; object-fit: cover; outline: 1px solid rgba(255,255,255,0.55); box-shadow: 0 22px 54px rgba(0,0,0,0.45); } .pj-hero__inset figcaption { margin-top: 9px; font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: rgba(255,255,255,0.8); text-shadow: 0 1px 3px rgba(0,0,0,0.7); } @media (max-width: 900px) { .pj-hero__inset { margin-top: 20px; max-width: 100%; } } /* AUSSAGEN als Leiste im Banner */ .pj-claims { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; border-top: 1px solid rgba(255,255,255,0.5); } @media (max-width: 860px) { .pj-claims { grid-template-columns: 1fr; } } .pj-claim { padding: 26px 32px 30px 0; border-left: 1px solid rgba(255,255,255,0.5); padding-left: 26px; } .pj-claim:first-child { border-left: 0; padding-left: 0; } @media (max-width: 860px) { .pj-claim { border-left: 0; padding: 16px 0; border-bottom: 1px solid rgba(255,255,255,0.35); } .pj-claim:last-child { border-bottom: 0; } .pj-claim__t { font-size: 19px; } } .pj-claim__t { font-size: 24px; font-weight: 600; line-height: 1.35; color: #fff; text-wrap: pretty; text-shadow: 0 1px 3px rgba(0,0,0,0.75), 0 2px 24px rgba(0,0,0,0.6); } .pj-claim__t em { font-style: normal; font-weight: 900; color: #fff; } /* Eine herausstechende Zahl */ .pj-figure { display: flex; align-items: baseline; gap: 14px; margin-bottom: 26px; } .pj-figure__pre { font-size: clamp(20px, 2.2vw, 30px); font-weight: 700; letter-spacing: -0.01em; color: #fff; text-shadow: 0 1px 20px rgba(0,0,0,0.5); } .pj-figure__n { font-size: clamp(52px, 7vw, 104px); font-weight: 900; letter-spacing: -0.05em; line-height: 0.82; color: var(--accent); text-shadow: 0 2px 40px rgba(0,0,0,0.45); } .pj-figure__l { font-size: 13px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; line-height: 1.35; color: rgba(255,255,255,0.92); max-width: 15ch; text-shadow: 0 1px 20px rgba(0,0,0,0.5); } /* SEKTION */ .pj-sec { padding: 104px 0 0; } .pj-sec__head { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-bottom: 40px; } .pj-sec__title { font-size: clamp(24px, 3vw, 38px); font-weight: 800; letter-spacing: -0.02em; text-transform: uppercase; margin: 0; } .pj-sec__meta { font-size: 12px; font-weight: 700; letter-spacing: 0.2em; text-transform: uppercase; color: var(--pj-mute); } .pj-sec__sub { margin: 10px 0 0; font-size: 13.5px; font-weight: 300; line-height: 1.6; color: var(--pj-mute); max-width: 52ch; } /* REFERENZ-KARUSSELL — Bilderreihe, läuft durch */ .pj-mq { position: relative; overflow: hidden; background: #15151a; padding: 26px 0; } .pj-mq::before, .pj-mq::after { content: ''; position: absolute; top: 0; bottom: 0; width: 120px; z-index: 3; pointer-events: none; } .pj-mq::before { left: 0; background: linear-gradient(90deg, #15151a, rgba(21,21,26,0)); } .pj-mq::after { right: 0; background: linear-gradient(270deg, #15151a, rgba(21,21,26,0)); } .pj-mq__scroll { overflow: hidden; cursor: grab; touch-action: pan-y; } .pj-mq__scroll.is-drag { cursor: grabbing; } .pj-mq__track { display: flex; width: max-content; animation-name: pjmq; animation-timing-function: linear; animation-iteration-count: infinite; } @keyframes pjmq { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } } @media (prefers-reduced-motion: reduce) { .pj-mq__track { animation: none !important; } } .pj-tile { position: relative; width: 460px; height: 320px; flex: 0 0 auto; margin-right: 18px; overflow: hidden; background: #1f1f26; user-select: none; -webkit-user-drag: none; } @media (max-width: 720px) { .pj-tile { width: 300px; height: 240px; } } .pj-tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; } .pj-tile img.is-tpl { filter: grayscale(0.9) contrast(1.06) brightness(0.82); } .pj-tile::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(21,21,26,0.1) 0%, rgba(21,21,26,0.08) 38%, rgba(21,21,26,0.9) 100%); } .pj-tile__cap { position: absolute; left: 22px; right: 22px; bottom: 20px; z-index: 2; } .pj-tile__region { font-size: 14px; font-weight: 800; letter-spacing: 0.22em; text-transform: uppercase; color: #fff; text-shadow: 0 1px 16px rgba(0,0,0,0.6); } .pj-tile__title { margin-top: 8px; font-size: 29px; font-weight: 800; letter-spacing: -0.015em; color: #fff; line-height: 1.15; text-shadow: 0 2px 20px rgba(0,0,0,0.55); } .pj-tile__meta { margin-top: 8px; font-size: 18px; font-weight: 400; color: rgba(255,255,255,0.88); text-shadow: 0 1px 16px rgba(0,0,0,0.55); } /* KOLLAGE */ .pj-collage { margin-top: 28px; display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: 210px; gap: 8px; } @media (max-width: 900px) { .pj-collage { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 150px; } } .pj-collage > div { position: relative; overflow: hidden; background: #f3f2ef; } .pj-ph { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; padding: 16px; background: repeating-linear-gradient(135deg, #f4f3ef 0 12px, #efeee9 12px 24px); } .pj-ph__l { font-size: 10.5px; font-weight: 800; letter-spacing: 0.2em; text-transform: uppercase; color: #a6a6a0; } .pj-ccap { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; padding: 40px 18px 14px; font-size: 14px; font-weight: 600; color: #fff; background: linear-gradient(180deg, rgba(16,16,20,0) 0%, rgba(16,16,20,0.82) 100%); text-shadow: 0 1px 3px rgba(0,0,0,0.6); } @media (max-width: 900px) { .pj-ccap { font-size: 12px; padding: 30px 12px 10px; } } .pj-cbtn { position: absolute; inset: 0; padding: 0; border: 0; background: none; cursor: zoom-in; overflow: hidden; display: block; } .pj-cbtn img { transition: transform .5s cubic-bezier(.2,.7,.2,1); } .pj-cbtn:hover img { transform: scale(1.045); } .pj-cbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; } /* LIGHTBOX */ .pj-lb { position: fixed; inset: 0; z-index: 9999; background: rgba(12,12,15,0.94); display: grid; place-items: center; padding: 40px; } @media (max-width: 720px) { .pj-lb { padding: 16px; } } .pj-lb__fig { margin: 0; max-width: 1400px; width: 100%; display: flex; flex-direction: column; align-items: center; gap: 16px; } .pj-lb__img { max-width: 100%; max-height: 78vh; object-fit: contain; display: block; } .pj-lb__cap { font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.86); text-align: center; } .pj-lb__x, .pj-lb__nav { position: absolute; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.28); color: #fff; cursor: pointer; display: grid; place-items: center; transition: background .2s; } .pj-lb__x:hover, .pj-lb__nav:hover { background: rgba(255,255,255,0.24); } .pj-lb__x { top: 22px; right: 22px; width: 46px; height: 46px; font-size: 22px; line-height: 1; } .pj-lb__nav { top: 50%; transform: translateY(-50%); width: 52px; height: 76px; font-size: 26px; } .pj-lb__nav--prev { left: 18px; } .pj-lb__nav--next { right: 18px; } @media (max-width: 720px) { .pj-lb__nav { width: 40px; height: 58px; font-size: 20px; } .pj-lb__nav--prev { left: 6px; } .pj-lb__nav--next { right: 6px; } } .pj-c1 { grid-column: span 3; grid-row: span 2; } .pj-c2 { grid-column: span 3; } .pj-c3 { grid-column: span 2; } .pj-c4 { grid-column: span 1; } .pj-c5 { grid-column: span 2; } .pj-c6 { grid-column: span 2; } .pj-c7 { grid-column: span 2; } @media (max-width: 900px) { .pj-collage > div { grid-column: span 1 !important; grid-row: span 1 !important; } .pj-c1 { grid-column: span 2 !important; grid-row: span 2 !important; } } .pj-caption { margin-top: 14px; font-size: 12px; font-weight: 300; color: #9a9aa2; } .pj-collage > div { position: relative; } /* CTA */ .pj-cta { margin: 104px 0 0; background: var(--accent); color: #fff; padding: 64px 52px; display: grid; grid-template-columns: 1.3fr auto; gap: 40px; align-items: center; } @media (max-width: 820px) { .pj-cta { grid-template-columns: 1fr; padding: 40px 26px; } } .pj-cta__t { font-size: clamp(24px, 3vw, 40px); font-weight: 900; letter-spacing: -0.025em; line-height: 1.1; text-transform: uppercase; } .pj-cta__s { margin-top: 12px; font-size: 15px; font-weight: 300; line-height: 1.7; color: rgba(255,255,255,0.85); max-width: 52ch; } .pj-cta__btn { display: inline-flex; align-items: center; gap: 12px; background: #fff; color: var(--accent); padding: 18px 32px; font-size: 12px; font-weight: 800; letter-spacing: 0.2em; text-transform: uppercase; text-decoration: none; transition: transform .2s; white-space: nowrap; } .pj-cta__btn:hover { transform: translateX(4px); } .pj-end { height: 104px; } `; document.head.appendChild(s); }, []); return null; } const PJ_COPY = { lns: { kicker: 'Referenzen', h1: ['Gebaut,', 'wo das Netz', 'entsteht.'], lead1: Telekommunikationsnetze von der Trasse bis zum Hausanschluss. Bundesweit, mit eigenen Kolonnen., claims: [ { t: Über 1.000 km Trasse pro Jahr }, { t: Ausbau in ganz Deutschland }, { t: Von der Planung bis zur Abnahme } ], heroImg: 'assets/lns-steine.jpeg', figN: '1.000', figL: 'km Trasse pro Jahr', figPre: 'über', showTitle: 'Referenzen', showSub: 'Ein Auszug unserer Ausbaugebiete.', collageTitle: 'Von der Baustelle', collageMeta: 'Eigene Kolonnen · eigene Technik', collage: [ { src: 'assets/lns-proj-binz-closeup.jpeg', cap: 'Pflasterarbeiten nach der Verlegung' }, { src: 'assets/opt/lns-proj-netzverteiler.jpg', cap: 'Netzverteiler · Spleiß- und Montagearbeiten' }, { src: 'assets/opt/lns-proj-graben-kubota.jpg', cap: 'Trassengraben · Minibagger im Gehwegbereich' }, { src: 'assets/opt/lns-proj-trassenarbeiten-wohngebiet.jpg', cap: 'Trassenarbeiten im Wohngebiet' } ], ctaT: 'Ihr Ausbaugebiet als nächstes?', ctaS: 'Sagen Sie uns Region und Volumen — wir melden uns mit einem Vorschlag.', ctaBtn: 'Projekt anfragen →' }, ifm: { kicker: 'Referenzen', h1: ['Gepflegt,', 'gebaut,', 'betreut.'], lead1: Außenanlagen, Grünpflege, Winterdienst und Baumkontrolle. Ganzjährig, mit eigenem Personal., claims: [ { t: Betreuung das ganze Jahr }, { t: Berlin und Brandenburg }, { t: Vom Beet bis zum Pflasterbau } ], heroImg: 'assets/opt/ifm-proj-winterdienst-brandenburger-tor.jpg', heroPos: '50% 78%', figN: '365', figL: 'Tage im Einsatz', showTitle: 'Referenzen', showSub: 'Ein Auszug unserer Objekte.', collageTitle: 'Von unseren Objekten', collageMeta: 'Eigenes Personal · eigener Fuhrpark', collage: [ { src: 'assets/opt/ifm-proj-winterdienst-brandenburger-tor.jpg', cap: 'Winterdienst · Pariser Platz, Berlin' }, { src: 'assets/opt/ifm-proj-fruehjahr-stadtpark.jpg', cap: 'Frühjahrsschnitt · Stadtpark' }, { src: 'assets/opt/ifm-proj-gasometer-beet.jpg', cap: 'Beetpflege · Gasometer Schöneberg' }, { src: 'assets/opt/ifm-proj-baumpflege-hebebuehne.jpg', cap: 'Baumpflege mit Hebebühne' }, { src: 'assets/opt/ifm-proj-tiefbau-vorgarten.jpg', cap: 'Erd- und Pflasterarbeiten · Wohnanlage' }, { src: 'assets/opt/ifm-proj-pflanzung-park.jpg', cap: 'Neupflanzung · öffentliche Grünanlage' }, { src: 'assets/opt/ifm-proj-winterdienst-nacht-kudamm.jpg', cap: 'Nachtschicht Winterdienst · Berlin City West' } ], ctaT: 'Ihre Liegenschaft im Blick?', ctaS: 'Sagen Sie uns Objekt und Umfang — wir melden uns mit einem Angebot.', ctaBtn: 'Angebot anfragen →' } }; // Vorher/Nachher-Assets tragen eingebrannte Beschriftungen — im Referenz-Layout nicht verwenden. const PJ_SKIP_IMG = /projekt-(garten|winter|winterdienst)-(vorher|nachher)/; // Ersatz-Asset nur, wenn das Motiv inhaltlich zum Projekt passt (id 1 = Winterdienst → Schneeräumung). const PJ_FALLBACK_IMG = { 1: 'assets/opt/ifm-bg.jpg' }; // Feste Bildzuordnung je Projekt-ID (12 = Binz). const PJ_PIN_IMG = { 12: 'assets/opt/lns-proj-graben-kubota.jpg', 13: 'assets/opt/lns-proj-elbe-elster.jpg', 10: 'assets/opt/lns-tpl-berlin-nord.jpg', 7: 'assets/opt/lns-proj-trassenarbeiten-wohngebiet.jpg', 9: 'assets/opt/lns-tpl-bernau.jpg' }; // Stadt-/Stimmungsbilder statt Baustellenfoto — entsättigt, damit sie sich unterordnen. const PJ_TPL_IDS = [10, 9]; // Kachel-Variante: 960px, Graufilter bei Stimmungsbildern bereits eingebacken (kein Live-Filter im laufenden Band). const PJ_TILE_SRC = { 'assets/opt/lns-tpl-berlin-nord.jpg': 'assets/tile/lns-tpl-berlin-nord.jpg', 'assets/opt/lns-tpl-bernau.jpg': 'assets/tile/lns-tpl-bernau.jpg', 'assets/opt/lns-proj-graben-kubota.jpg': 'assets/tile/lns-proj-graben-kubota.jpg', 'assets/opt/lns-proj-elbe-elster.jpg': 'assets/tile/lns-proj-elbe-elster.jpg', 'assets/opt/lns-proj-trassenarbeiten-wohngebiet.jpg': 'assets/tile/lns-proj-trassenarbeiten-wohngebiet.jpg', 'assets/opt/lns-proj-netzverteiler.jpg': 'assets/tile/lns-proj-netzverteiler.jpg', 'assets/opt/lns-kabel.jpg': 'assets/tile/lns-kabel.jpg', 'assets/lns-steine.jpeg': 'assets/tile/lns-steine.jpg', 'assets/lns-proj-binz-closeup.jpeg': 'assets/tile/lns-proj-binz-closeup.jpg', 'assets/lns-hero.jpg': 'assets/tile/lns-hero.jpg', 'assets/lns-fleet.jpg': 'assets/tile/lns-fleet.jpg' }; // Bildausschnitt je Projekt-ID — oberes Drittel zeigen. const PJ_PIN_POS = { 12: '50% 28%' }; function PjMedia({ project, placeholder }) { const own = project && project.img && !PJ_SKIP_IMG.test(project.img) ? project.img : null; const src = own || (project && PJ_FALLBACK_IMG[project.id]) || null; if (src) return {project.title}; return
{placeholder}
; } // Marken-Assets als Motiv für Projekte ohne eigenes Bild (Reihenfolge rotiert). const PJ_POOL = { lns: ['assets/opt/lns-proj-netzverteiler.jpg', 'assets/lns-steine.jpeg', 'assets/opt/lns-kabel.jpg', 'assets/lns-proj-binz-closeup.jpeg', 'assets/lns-hero.jpg', 'assets/lns-fleet.jpg'], ifm: ['assets/opt/ifm-proj-gasometer-beet.jpg', 'assets/opt/ifm-proj-winterdienst-brandenburger-tor.jpg', 'assets/opt/ifm-proj-tiefbau-vorgarten.jpg', 'assets/opt/ifm-proj-baumpflege-hebebuehne.jpg', 'assets/opt/ifm-proj-pflanzung-park.jpg', 'assets/opt/ifm-proj-reinigung.jpg', 'assets/opt/ifm-proj-fruehjahr-stadtpark.jpg', 'assets/opt/ifm-proj-winterdienst-nacht-kudamm.jpg'] }; function PjMarquee({ items, brand }) { const pool = PJ_POOL[brand] || PJ_POOL.lns; const tiles = items.map((p, i) => { const own = p.img && !PJ_SKIP_IMG.test(p.img) ? p.img : null; const raw = PJ_PIN_IMG[p.id] || own || pool[i % pool.length]; return Object.assign({}, p, { src: PJ_TILE_SRC[raw] || raw, pos: PJ_PIN_POS[p.id], tpl: PJ_TPL_IDS.indexOf(p.id) !== -1 && !PJ_TILE_SRC[raw] }); }); const loop = tiles.concat(tiles); const ref = React.useRef(null); const trackRef = React.useRef(null); // Endlosband als reine CSS-Animation: läuft in Firefox auf dem Compositor, // JS ist im Ruhezustand still. Beim Ziehen wird die Animation kurz ersetzt und // danach mit negativem animation-delay an der neuen Position fortgesetzt. React.useEffect(() => { const el = ref.current, track = trackRef.current; if (!el || !track) return; const SPEED = 45; // px pro Sekunde let half = 0, dur = 0, pos = 0, dragging = false, startX = 0, startPos = 0; const currentPos = () => { const m = new DOMMatrixReadOnly(getComputedStyle(track).transform); return half > 0 ? ((-m.m41) % half + half) % half : 0; }; const run = p => { if (!(half > 0)) return; pos = ((p % half) + half) % half; track.style.animation = ''; track.style.animationDuration = dur + 's'; track.style.animationDelay = (-(pos / half) * dur) + 's'; }; const measure = () => { const w = track.offsetWidth / 2; if (!w || Math.abs(w - half) < 1) return; const keep = half > 0 ? pos / half : 0; half = w; dur = half / SPEED; if (!dragging) run(keep * half); }; measure(); const ro = window.ResizeObserver ? new ResizeObserver(measure) : null; if (ro) ro.observe(track); const down = e => { if (!(half > 0)) return; dragging = true; startX = e.clientX; startPos = currentPos(); el.classList.add('is-drag'); track.style.animation = 'none'; track.style.transform = 'translate3d(' + (-startPos) + 'px,0,0)'; el.setPointerCapture && el.setPointerCapture(e.pointerId); }; const move = e => { if (!dragging) return; pos = ((startPos - (e.clientX - startX)) % half + half) % half; track.style.transform = 'translate3d(' + (-pos) + 'px,0,0)'; }; const up = () => { if (!dragging) return; dragging = false; el.classList.remove('is-drag'); track.style.transform = ''; run(pos); }; el.addEventListener('pointerdown', down); el.addEventListener('pointermove', move); el.addEventListener('pointerup', up); el.addEventListener('pointercancel', up); return () => { if (ro) ro.disconnect(); el.removeEventListener('pointerdown', down); el.removeEventListener('pointermove', move); el.removeEventListener('pointerup', up); el.removeEventListener('pointercancel', up); }; }, [brand, items.length]); return (
{loop.map((p, i) => (
= tiles.length}>
{p.region}
{p.title}
{[(p.stats || [])[0] && (p.stats[0].num + ' ' + p.stats[0].label), p.period || p.year].filter(Boolean).join(' · ')}
))}
); } function PjLightbox({ items, index, onClose, onStep }) { React.useEffect(() => { const key = e => { if (e.key === 'Escape') onClose(); else if (e.key === 'ArrowRight') onStep(1); else if (e.key === 'ArrowLeft') onStep(-1); }; document.addEventListener('keydown', key); const prev = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => { document.removeEventListener('keydown', key); document.body.style.overflow = prev; }; }, [onClose, onStep]); const it = items[index]; if (!it) return null; return (
{items.length > 1 && } {items.length > 1 && }
e.stopPropagation()}> {it.cap}
{it.cap}{items.length > 1 && {' — ' + (index + 1) + '/' + items.length}}
); } function ProjectsPageNew({ brand }) { const [lb, setLb] = React.useState(-1); const c = PJ_COPY[brand] || PJ_COPY.lns; const all = (window.QC_DATA.projects || []).filter(p => p.brand === brand); const byTitle = s => all.find(p => p.title.indexOf(s) === 0 || p.title === s); const sorted = all.slice().sort((x, y) => String(y.period || y.year).localeCompare(String(x.period || x.year))); const doneTitles = brand === 'lns' ? [] : ['Außenanlage Stadtquartier Adlershof', 'Baumkataster Schlosspark Babelsberg']; const items = sorted.map(p => Object.assign({}, p, { done: doneTitles.indexOf(p.title) !== -1 })); return (
{c.heroImg ? :
Kopfbild Banner
}
{c.kicker}

{c.h1[0]}
{c.h1[1]}
{c.h1[2]}

{c.figPre &&
{c.figPre}
}
{c.figN}
{c.figL}

{c.lead1}

{c.heroInset && (
{c.heroInsetCap {c.heroInsetCap &&
{c.heroInsetCap}
}
)}
{c.claims.map((k, i) => (
{k.t}
))}
{/* Referenz-Karussell — bei IFM vorübergehend ausgeblendet (später wieder aktivieren: brand !== 'ifm' entfernen) */} {items.length > 0 && brand !== 'ifm' && (

{c.showTitle}

{c.showSub}

Stand {new Date().getFullYear()}
)}

{c.collageTitle}

{c.collageMeta}
{(c.collage || [1,2,3,4,5,6].map(n => ({ ph: 'Bild ' + n }))).map((it, i) => (
{it.src ? <>
{it.cap}
:
{it.ph}
}
))}
{c.ctaT}
{c.ctaS}
{c.ctaBtn}
{lb >= 0 && c.collage && ( setLb(-1)} onStep={d => setLb(p => (p + d + c.collage.length) % c.collage.length)} /> )}
); } function ProjectsPage(props) { return ; } Object.assign(window, { ProjectsPage, ProjectsPageNew, PjMedia, PjMarquee, PrjStyles, PjLightbox });