// 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: <span>Telekommunikationsnetze von der Trasse bis zum Hausanschluss. <strong>Bundesweit, mit eigenen Kolonnen.</strong></span>,
    claims: [
      { t: <span>Über <em>1.000 km</em> Trasse pro Jahr</span> },
      { t: <span>Ausbau in <em>ganz Deutschland</em></span> },
      { t: <span>Von der Planung bis zur <em>Abnahme</em></span> }
    ],
    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: <span>Außenanlagen, Grünpflege, Winterdienst und Baumkontrolle. <strong>Ganzjährig, mit eigenem Personal.</strong></span>,
    claims: [
      { t: <span>Betreuung das <em>ganze Jahr</em></span> },
      { t: <span>Berlin und <em>Brandenburg</em></span> },
      { t: <span>Vom Beet bis zum <em>Pflasterbau</em></span> }
    ],
    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 <img className="pj-img" src={src} alt={project.title} />;
  return <div className="pj-ph"><span className="pj-ph__l">{placeholder}</span></div>;
}

// 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 (
    <div className="pj-mq" aria-label="Referenzprojekte">
      <div className="pj-mq__scroll" ref={ref}>
        <div className="pj-mq__track" ref={trackRef}>
          {loop.map((p, i) => (
            <div className="pj-tile" key={p.id + '-' + i} aria-hidden={i >= tiles.length}>
              <img src={p.src} alt="" draggable="false" decoding="async" className={p.tpl ? 'is-tpl' : null} style={p.pos ? {objectPosition: p.pos} : null} />
              <div className="pj-tile__cap">
                <div className="pj-tile__region">{p.region}</div>
                <div className="pj-tile__title">{p.title}</div>
                <div className="pj-tile__meta">{[(p.stats || [])[0] && (p.stats[0].num + ' ' + p.stats[0].label), p.period || p.year].filter(Boolean).join(' · ')}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

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 (
    <div className="pj-lb" role="dialog" aria-modal="true" aria-label={it.cap} onClick={onClose}>
      <button className="pj-lb__x" aria-label="Schließen" onClick={onClose}>×</button>
      {items.length > 1 && <button className="pj-lb__nav pj-lb__nav--prev" aria-label="Vorheriges Bild" onClick={e => { e.stopPropagation(); onStep(-1); }}>‹</button>}
      {items.length > 1 && <button className="pj-lb__nav pj-lb__nav--next" aria-label="Nächstes Bild" onClick={e => { e.stopPropagation(); onStep(1); }}>›</button>}
      <figure className="pj-lb__fig" onClick={e => e.stopPropagation()}>
        <img className="pj-lb__img" src={it.src} alt={it.cap} />
        <figcaption className="pj-lb__cap">{it.cap}{items.length > 1 && <span style={{opacity:.5}}>{'  —  ' + (index + 1) + '/' + items.length}</span>}</figcaption>
      </figure>
    </div>
  );
}

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 (
    <Layout brand={brand}>
      <PrjStyles />
      <div className="pj">

        <section className="pj-hero">
          <div className="pj-hero__bg">
            {c.heroImg
              ? <img src={c.heroImg} alt="" fetchPriority="high" style={c.heroPos ? {objectPosition: c.heroPos} : null} />
              : <div className="pj-hero__ph"><span>Kopfbild Banner</span></div>}
          </div>
          <div className="pj-hero__inner">
          <div className="pj-wrap">
            <div className="pj-hero__grid">
              <div>
                <div className="pj-kicker">{c.kicker}</div>
                <h1 className="pj-h1">{c.h1[0]}<br />{c.h1[1]}<br /><em>{c.h1[2]}</em></h1>
              </div>
              <div>
                <div className="pj-figure">
                  {c.figPre && <div className="pj-figure__pre">{c.figPre}</div>}
                  <div className="pj-figure__n">{c.figN}</div>
                  <div className="pj-figure__l">{c.figL}</div>
                </div>
                <p className="pj-lead">{c.lead1}</p>
                {c.heroInset && (
                  <figure className="pj-hero__inset">
                    <img src={c.heroInset} alt={c.heroInsetCap || ''} />
                    {c.heroInsetCap && <figcaption>{c.heroInsetCap}</figcaption>}
                  </figure>
                )}
              </div>
            </div>
          </div>
          <div className="pj-wrap">
            <div className="pj-claims">
              {c.claims.map((k, i) => (
                <div className="pj-claim" key={i}>
                  <div className="pj-claim__t">{k.t}</div>
                </div>
              ))}
            </div>
          </div>
          </div>
        </section>

        {/* Referenz-Karussell — bei IFM vorübergehend ausgeblendet (später wieder aktivieren: brand !== 'ifm' entfernen) */}
        {items.length > 0 && brand !== 'ifm' && (
        <section className="pj-sec">
          <div className="pj-wrap">
            <div className="pj-sec__head">
              <div>
                <h2 className="pj-sec__title">{c.showTitle}</h2>
                <p className="pj-sec__sub">{c.showSub}</p>
              </div>
              <div className="pj-sec__meta">Stand {new Date().getFullYear()}</div>
            </div>
          </div>
          <PjMarquee items={items} brand={brand} />
        </section>
        )}

        <section className="pj-sec">
          <div className="pj-wrap">
            <div className="pj-sec__head">
              <h2 className="pj-sec__title">{c.collageTitle}</h2>
              <div className="pj-sec__meta">{c.collageMeta}</div>
            </div>
            <div className="pj-collage">
              {(c.collage || [1,2,3,4,5,6].map(n => ({ ph: 'Bild ' + n }))).map((it, i) => (
                <div className={'pj-c' + (i + 1)} key={i}>
                  {it.src
                    ? <><button className="pj-cbtn" type="button" aria-label={it.cap + ' — vergrößern'} onClick={() => setLb(i)}><img className="pj-img" src={it.src} alt={it.cap} loading="lazy" decoding="async" /></button><div className="pj-ccap">{it.cap}</div></>
                    : <div className="pj-ph"><span className="pj-ph__l">{it.ph}</span></div>}
                </div>
              ))}
            </div>
          </div>
        </section>

        <div className="pj-wrap">
          <div className="pj-cta">
            <div>
              <div className="pj-cta__t">{c.ctaT}</div>
              <div className="pj-cta__s">{c.ctaS}</div>
            </div>
            <a className="pj-cta__btn" href={'/' + brand + '/kontakt'}>{c.ctaBtn}</a>
          </div>
        </div>
        <div className="pj-end"></div>
        {lb >= 0 && c.collage && (
          <PjLightbox
            items={c.collage}
            index={lb}
            onClose={() => setLb(-1)}
            onStep={d => setLb(p => (p + d + c.collage.length) % c.collage.length)}
          />
        )}
      </div>
    </Layout>
  );
}

function ProjectsPage(props) { return <ProjectsPageNew {...props} />; }
Object.assign(window, { ProjectsPage, ProjectsPageNew, PjMedia, PjMarquee, PrjStyles, PjLightbox });
