// Pagina 'Over Buiten Buddies' — het verhaal van Sabrina in vijf hoofdstukken.
// Alle teksten komen letterlijk uit het contentdocument v4.0.

/* ---------------- helpers ---------------- */
function bbReduced() {
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches
    || document.documentElement.classList.contains("bb-rm-force");
}

function useParallax(ref, strength = 0.1) {
  useEffect(() => {
    const el = ref.current;
    if (!el || bbReduced()) return;
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const r = el.getBoundingClientRect();
        const offset = r.top + r.height / 2 - window.innerHeight / 2;
        el.style.setProperty("--py", (-offset * strength).toFixed(1) + "px");
      });
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      cancelAnimationFrame(raf);
    };
  }, [ref, strength]);
}

function WordReveal({ text, tag = "p", className = "", stagger = 85 }) {
  const ref = useRef(null);
  const [on, setOn] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    if (bbReduced()) { setOn(true); return; }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setOn(true); obs.disconnect(); } });
    }, { threshold: 0.35 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  const Tag = tag;
  const words = text.split(" ");
  return (
    <Tag ref={ref} className={"bb-wordreveal " + (on ? "in " : "") + className}>
      {words.map((w, i) => (
        <React.Fragment key={i}>
          <span style={{ transitionDelay: i * stagger + "ms" }}>{w + (i < words.length - 1 ? " " : "")}</span>
        </React.Fragment>
      ))}
    </Tag>
  );
}

/* Handschrift dat letter voor letter verschijnt, alsof je de pen volgt. De regels
   schrijven zichzelf na elkaar: pas als de vorige regel klaar is, begint de volgende. */
function HandLine({ text, className, stagger, delay, on }) {
  // Per woord een omhulling, zodat de regel alleen op woordgrenzen afbreekt en
  // nooit middenin een woord. De letternummering loopt door over de hele regel,
  // zodat het schrijftempo gelijk blijft.
  const woorden = text.split(" ");
  let n = 0;
  return (
    <p className={"bb-handsign " + (on ? "in " : "") + (className || "")} role="img" aria-label={text}>
      {woorden.map((woord, wi) => {
        const letters = woord.split("").map((l) => ({ l: l, i: n++ }));
        const spatie = wi < woorden.length - 1 ? { l: " ", i: n++ } : null;
        return (
          <React.Fragment key={wi}>
            <span className="bb-handsign__w" aria-hidden="true">
              {letters.map((s) => (
                <span key={s.i} style={{ transitionDelay: (delay + s.i * stagger) + "ms" }}>{s.l}</span>
              ))}
            </span>
            {spatie && <span aria-hidden="true" style={{ transitionDelay: (delay + spatie.i * stagger) + "ms" }}> </span>}
          </React.Fragment>
        );
      })}
    </p>
  );
}

function HandSign({ lines, wacht = 500 }) {
  const ref = useRef(null);
  const [on, setOn] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    if (bbReduced()) { setOn(true); return; }
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setOn(true); obs.disconnect(); } });
    }, { threshold: 0.4 });
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  let t = wacht;
  const metTijd = lines.map((l) => {
    const start = t;
    t += l.text.length * l.stagger + (l.pauze || 0);
    return Object.assign({}, l, { delay: start });
  });
  return (
    <div ref={ref} className="bb-handwriting">
      {metTijd.map((l, i) => <HandLine key={i} {...l} on={on} />)}
    </div>
  );
}

/* ---------------- hoofdstukken ---------------- */
const OVER_CHAPTERS = [
  { id: "missie", n: "Intro", intro: true, label: "Waar Buiten Buddies voor staat" },
  { id: "wat-ik-zag", n: "01", label: "Wat ik zag" },
  { id: "het-kwartje", n: "02", label: "Het kwartje" },
  { id: "waarom-buiten", n: "03", label: "Waarom buitenspelen werkt" },
  { id: "het-idee", n: "04", label: "Het idee" },
  { id: "en-toen", n: "05", label: "Zo ontstond Buiten Buddies" },
];

function ChapterRail({ active, uit, railRef, donkerLijst }) {
  return (
    <nav ref={railRef} className={"bb-rail" + (uit ? " is-uit" : "")} aria-label="Hoofdstukken in het verhaal" aria-hidden={uit ? "true" : undefined}>
      <span className="bb-rail__line" aria-hidden="true"></span>
      {OVER_CHAPTERS.map((c, i) => (
        <a
          key={c.id} href={"#" + c.id}
          className={"bb-rail__item" + (active === i ? " is-on" : "") + ((donkerLijst && donkerLijst[i]) ? " is-donker" : "")}
          tabIndex={uit ? -1 : undefined}
          onClick={(e) => {
            e.preventDefault();
            const el = document.getElementById(c.id);
            if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 96, behavior: bbReduced() ? "auto" : "smooth" });
          }}
          aria-current={active === i ? "true" : undefined}
        >
          <span className="bb-rail__dot" aria-hidden="true"></span>
          <span className={"bb-rail__n" + (c.intro ? " bb-rail__n--intro" : "")}>{c.n}</span>
          <span className="bb-rail__label">{c.label}</span>
        </a>
      ))}
    </nav>
  );
}

function ChapterHead({ n, label }) {
  return (
    <div className="bb-chapter__head">
      <span className="bb-chapter__n" aria-hidden="true">{n}</span>
      <h2 className="bb-chapter__label">{label}</h2>
    </div>
  );
}

/* ---------------- hero ---------------- */
function OverHero({ go }) {
  const photoRef = useRef(null);
  useParallax(photoRef, 0.035);
  return (
    <section className="bb-over-hero" aria-labelledby="over-heading" data-screen-label="Over, hero">
      <span className="bb-over-hero__blob" aria-hidden="true"></span>
      <Container>
        <div className="bb-over-hero__grid">
          <div className="bb-over-hero__text">
            <FadeUp>
              <p className="bb-over-hero__kicker">Het verhaal achter Buiten Buddies</p>
            </FadeUp>
            <FadeUp delay={90}>
              <h1 id="over-heading">
                Waarom Buiten{" "}
                <span className="bb-over-hero__mark">
                  Buddies?
                  <svg viewBox="0 0 300 20" preserveAspectRatio="none" aria-hidden="true">
                    <path d="M4 14 C60 4, 150 3, 296 9" />
                  </svg>
                </span>
              </h1>
            </FadeUp>
            <FadeUp delay={180}>
              <p className="bb-over-hero__lead">
                <span className="bb-word" style={{ animationDelay: "1900ms" }}>&bdquo;Log uit, </span>
                <span className="bb-word" style={{ animationDelay: "2350ms" }}>beleef </span>
                <span className="bb-word bb-word--write" style={{ animationDelay: "2800ms" }}>echt.&rdquo;</span>
              </p>
            </FadeUp>
          </div>

          <FadeUp className="bb-over-hero__media">
            <figure className="bb-over-portrait">
              <div className="bb-over-portrait__frame">
                <img
                  ref={photoRef}
                  src="assets/photos/sabrina-straat-ijshockey-web.jpg"
                  loading="eager"
                  decoding="sync"
                  fetchpriority="high"
                  alt="Sabrina Costermans, initiatiefnemer van Buiten Buddies, in een straat waar kinderen buitenspelen"
                />
              </div>
              <figcaption>
                <span className="bb-over-portrait__badge">
                  <img src="assets/logo/logo.png" alt="" />
                </span>
                <span>Sabrina Costermans, initiatiefnemer Buiten Buddies, pedagoog en moeder</span>
              </figcaption>
            </figure>
          </FadeUp>
        </div>
      </Container>
    </section>
  );
}

/* ---------------- verhaal ---------------- */
function OverStory() {
  const [active, setActive] = useState(0);
  const [railUit, setRailUit] = useState(true);
  const [donkerLijst, setDonkerLijst] = useState(() => OVER_CHAPTERS.map(() => false));
  const railRef = useRef(null);
  const wrapRef = useRef(null);
  const photo3 = useRef(null);
  useParallax(photo3, 0.03);

  // De rail komt pas in beeld bij hoofdstuk 02 en verdwijnt weer zodra de
  // ondertekening voorbij is. Daarnaast meet hij per regel welke kleur er
  // achter zit: is die donker, dan wordt die regel wit met geelgroen cijfer.
  useEffect(() => {
    const onder = document.querySelector("#en-toen .bb-handwriting");
    const groen = document.querySelector(".bb-chapter--dark");
    let raf = 0;

    // Zoekt de eerste echt gevulde achtergrond onder een punt, de rail zelf
    // overgeslagen, en zegt of die donker is.
    const isDonkerOp = (x, y) => {
      const stapel = document.elementsFromPoint(x, y);
      for (const el of stapel) {
        if (railRef.current && railRef.current.contains(el)) continue;
        const kleur = getComputedStyle(el).backgroundColor;
        const m = kleur.match(/[\d.]+/g);
        if (!m) continue;
        const a = m.length > 3 ? parseFloat(m[3]) : 1;
        if (a < 0.5) continue;
        const [r, g, b] = m.map(Number);
        // Relatieve helderheid volgens WCAG.
        const lin = (c) => { c /= 255; return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); };
        return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b) < 0.22;
      }
      return false;
    };

    const kijk = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const h = window.innerHeight;
        const tweede = document.getElementById("het-kwartje");
        const naTweede = tweede ? tweede.getBoundingClientRect().top < h * 0.8 : false;
        const rr = railRef.current ? railRef.current.getBoundingClientRect() : null;
        const railOnder = rr && rr.height ? rr.bottom : h * 0.5 + 130;
        // Weg zodra de onderrand van het groene vlak boven de rail uitkomt: hij is
        // dan nooit zichtbaar over het blok daaronder.
        const uitGroen = groen ? groen.getBoundingClientRect().bottom < railOnder : false;
        const voorbijOnder = onder ? onder.getBoundingClientRect().bottom < h * 0.45 : false;
        const weg = !naTweede || uitGroen || voorbijOnder;
        setRailUit(weg);

        const rail = railRef.current;
        // Ook meten als de rail net verborgen is, zodat de kleuren al kloppen
        // op het moment dat hij weer in beeld komt.
        if (!rail || getComputedStyle(rail).display === "none") return;
        const items = rail.querySelectorAll(".bb-rail__item");
        const nieuw = Array.from(items).map((item) => {
          const r = item.getBoundingClientRect();
          return isDonkerOp(r.left + Math.min(r.width, 40), r.top + r.height / 2);
        });
        // Via de state, want anders wist een nieuwe render de klasse weer weg.
        setDonkerLijst((oud) => (oud.length === nieuw.length && oud.every((v, i) => v === nieuw[i]) ? oud : nieuw));
      });
    };
    kijk();
    window.addEventListener("scroll", kijk, { passive: true });
    window.addEventListener("resize", kijk);
    return () => {
      window.removeEventListener("scroll", kijk);
      window.removeEventListener("resize", kijk);
      cancelAnimationFrame(raf);
    };
  }, []);

  useEffect(() => {
    const nodes = OVER_CHAPTERS.map((c) => document.getElementById(c.id)).filter(Boolean);
    if (!nodes.length) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          const i = nodes.indexOf(e.target);
          if (i > -1) setActive(i);
        }
      });
    }, { rootMargin: "-45% 0px -45% 0px" });
    nodes.forEach((n) => obs.observe(n));
    return () => obs.disconnect();
  }, []);

  return (
    <div className="bb-story" ref={wrapRef}>
      <ChapterRail active={active} uit={railUit} railRef={railRef} donkerLijst={donkerLijst} />

      {/* 01 */}
      <section className="bb-chapter bb-chapter--cream" id="wat-ik-zag" aria-label="Wat ik zag">
        <Container>
          <div className="bb-chapter__inner">
            <ChapterHead n="01" label="Wat ik zag" />
            <FadeUp>
              <p className="bb-chapter__body">
                Al geruime tijd zag ik hoe jongeren steeds vaker opgingen in hun telefoon, zelfs
                wanneer ze naast elkaar op de bank zaten. Met mijn achtergrond als pedagoog wist ik:
                dit is niet hoe gezonde ontwikkeling eruitziet. Dit vraagt om verandering.
              </p>
            </FadeUp>
          </div>
        </Container>
      </section>

      {/* 02 */}
      <section className="bb-chapter bb-chapter--mint" id="het-kwartje" aria-label="Het kwartje">
        <span className="bb-blob bb-blob--right bb-blob--cream" aria-hidden="true"></span>
        <Container>
          <div className="bb-chapter__inner">
            <ChapterHead n="02" label="Het kwartje" />
            <FadeUp>
              <p className="bb-chapter__body">
                Dat besef werd alleen maar sterker toen mijn zoon, toen 9 jaar oud, langs de deuren
                ging om te vragen of er iemand buiten kwam spelen. Steeds vaker kreeg hij hetzelfde
                antwoord:
              </p>
            </FadeUp>
            <div className="bb-pullquote">
              <p className="bb-pullquote__text">
                <span className="bb-pullquote__mark" aria-hidden="true">&bdquo;</span>
                <WordReveal tag="span" className="bb-pullquote__words" text="Ik wil eerst mijn schermtijd opmaken." stagger={120} />
                <span className="bb-pullquote__mark" aria-hidden="true">&rdquo;</span>
              </p>
            </div>
            <FadeUp>
              <p className="bb-chapter__body">
                Het zette me aan het denken. Hoe krijgen we kinderen weer naar buiten, weg van hun
                schermen en terug in echt contact met elkaar?
              </p>
            </FadeUp>
          </div>
        </Container>
      </section>

      {/* 03 */}
      <section className="bb-chapter bb-chapter--split" id="waarom-buiten" aria-label="Waarom buitenspelen werkt">
        <span className="bb-blob bb-blob--left bb-blob--grass" aria-hidden="true"></span>
        <Container>
          <div className="bb-chapter__split">
            <div className="bb-chapter__inner bb-chapter__inner--left">
              <ChapterHead n="03" label="Waarom buitenspelen werkt" />
              <FadeUp>
                <p className="bb-chapter__body">
                  Buitenspelen is zoveel meer dan alleen plezier. Het biedt een waardevolle
                  tegenhanger voor de constante afleiding van schermen. Het zorgt voor{" "}
                  <b>beweging</b>, <b>rust voor de ogen</b> en <b>echte sociale interactie</b>.
                </p>
              </FadeUp>
              <FadeUp delay={90}>
                <p className="bb-chapter__body bb-chapter__body--accent">
                  Maar misschien nog wel belangrijker: het creëert situaties waarin kinderen hun
                  weerbaarheid en veerkracht ontwikkelen, vaardigheden die ze hun hele leven nodig
                  hebben.
                </p>
              </FadeUp>
            </div>
            <FadeUp delay={140}>
              <div className="bb-chapter__photo">
                <img ref={photo3} src="assets/photos/bal-overgooiend-nova.jpg" alt="Twee kinderen gooien buiten een bal naar elkaar over" />
              </div>
            </FadeUp>
          </div>
        </Container>
      </section>

      {/* 04 */}
      <section className="bb-chapter bb-chapter--mint" id="het-idee" aria-label="Het idee">
        <span className="bb-blob bb-blob--right bb-blob--cream" aria-hidden="true"></span>
        <Container>
          <div className="bb-chapter__inner">
            <ChapterHead n="04" label="Het idee" />
            <FadeUp>
              <p className="bb-chapter__body">
                Toen ik zag hoe goed een buurtapp voor volwassenen werkte om verbinding te creëren,
                ontstond het idee: waarom niet iets soortgelijks voor jongeren? Zo startte ik een
                buitenspeel-buurtapp in onze buurt. Het effect was direct zichtbaar. Kinderen vonden
                elkaar weer, gingen samen naar buiten en er ontstond opnieuw verbinding.
              </p>
            </FadeUp>
          </div>
        </Container>

        <div className="bb-idea-quote">
          <Container>
            <WordReveal
              tag="p" className="bb-idea-quote__text" stagger={95}
              text="Er wordt nu zelfs weer bij elkaar aangebeld, de buurtapp bleek een middel om dat weer normaal te maken."
            />
          </Container>
        </div>

        <Container>
          <div className="bb-chapter__inner">
            <FadeUp>
              <p className="bb-chapter__body">
                De 13-jarigen komen nu zelfs op elkaars verjaardagen, logeren bij elkaar in de tuin
                en spreken af om naar de kermis te gaan.
              </p>
            </FadeUp>
            <FadeUp delay={100}>
              <div className="bb-photostrip">
                <img src="assets/photos/softbal-haarlem-kids-2.jpg" alt="Groepje kinderen overlegt samen buiten" />
                <img src="assets/photos/steppende-kinderen.jpg" alt="Kinderen steppen samen door de straat" />
                <img src="assets/photos/klimnet-meiden.jpg" alt="Twee meiden klimmen samen in een klimnet in het park" />
              </div>
            </FadeUp>
          </div>
        </Container>
      </section>

      {/* 05 */}
      <section className="bb-chapter bb-chapter--dark" id="en-toen" aria-label="Zo ontstond Buiten Buddies">
        <Container>
          <div className="bb-chapter__inner">
            <ChapterHead n="05" label="Zo ontstond Buiten Buddies" />
            <WordReveal
              tag="p" className="bb-chapter__statement" stagger={70}
              text="Het succes was zo groot dat ik wist: dit moet groter."
            />
            <FadeUp delay={120}>
              <p className="bb-chapter__body bb-chapter__body--light">
                Met het vertrouwen en enthousiasme van velen is Buiten Buddies ontstaan, een
                initiatief dat buurten helpt om jongeren weer samen buiten te laten spelen en
                verbonden, gezonde gemeenschappen op te bouwen.
              </p>
            </FadeUp>
            <HandSign
              lines={[
                { text: "\u201eLaten we samen van buitenspelen weer kinderspel maken.\u201d", className: "bb-chapter__signoff", stagger: 34, pauze: -450 },
                { text: "Sabrina", className: "bb-chapter__sign", stagger: 190 },
              ]}
            />
          </div>
        </Container>
      </section>
    </div>
  );
}

/* ---------------- missie ---------------- */
function OverMissie({ intro }) {
  const punten = [
    { icon: "hand", text: "Meer buitenspelen en bewegen stimuleren" },
    { icon: "users", text: "Echte, offline verbinding tussen jongeren bevorderen" },
    { icon: "heart", text: "Bijdragen aan mentale, fysieke en sociale gezondheid" },
    { icon: "sparkle", text: "Buitenspelen weer vanzelfsprekend maken" },
    { icon: "shield", text: "Veiligheid en vertrouwen als basis" },
  ];
  return (
    <section id="missie" className={"bb-section bb-missie " + (intro ? "bb-missie--intro" : "bb-section--cream")} aria-labelledby="missie-heading">
      <span className={"bb-blob bb-blob--left " + (intro ? "bb-blob--cream" : "bb-blob--mint")} aria-hidden="true"></span>
      <Container>
        <div className="bb-section__head">
          <FadeUp>
            <div className="bb-eyebrow">
              <span className="dot" aria-hidden="true"></span>
              Missie
            </div>
          </FadeUp>
          <FadeUp delay={80}>
            <h2 id="missie-heading">Waar Buiten Buddies voor staat</h2>
          </FadeUp>
        </div>
        <ul className="bb-missie__list">
          {punten.map((p, i) => (
            <FadeUp key={p.text} delay={i * 90} as="li">
              <span className="bb-missie__icon" aria-hidden="true"><Icon name={p.icon} size={22} /></span>
              <span className="bb-missie__text">{p.text}</span>
            </FadeUp>
          ))}
        </ul>
      </Container>
    </section>
  );
}

/* ---------------- partner en toekomst ---------------- */
function OverPartner({ go }) {
  return (
    <section className="bb-section bb-section--alt bb-partner" aria-labelledby="partner-heading">
      <Container>
        <div className="bb-partner__grid">
          <FadeUp>
            <div className="bb-partner__card">
              <h2 id="partner-heading">Partner</h2>
              <p>Buiten Buddies wordt mogelijk gemaakt met steun van de Gemeente Haarlem.</p>
              <a className="bb-logolink" href="https://haarlem.nl/" target="_blank" rel="noopener noreferrer" aria-label="Naar de website van de gemeente Haarlem, opent in een nieuw tabblad">
                <img className="bb-partner__logo" src="assets/logo/gemeente-haarlem.png" alt="Gemeente Haarlem" />
              </a>
            </div>
          </FadeUp>
          <FadeUp delay={110}>
            <div className="bb-partner__card bb-partner__card--future">
              <h2>Toekomst</h2>
              <p>
                Buiten Buddies wil stap voor stap uitbreiden naar meer buurten en steden. We werken
                ook aan een eigen app. Wil je op de hoogte blijven? Schrijf je in voor updates.
              </p>
              <div className="bb-partner__cta">
                <Button variant="yellow" onClick={() => go("nieuwsbrief")}>
                  Schrijf je in voor updates <Icon name="arrowRight" />
                </Button>
                <Button variant="ghost" onClick={() => go("contact")}>Neem contact op</Button>
              </div>
            </div>
          </FadeUp>
        </div>
      </Container>
    </section>
  );
}

function OverPage({ go }) {
  return (
    <main id="main" tabIndex="-1" data-screen-label="Over Buiten Buddies">
      <OverHero go={go} />
      <OverMissie intro />
      <OverStory />
      <OverPartner go={go} />
    </main>
  );
}

Object.assign(window, { OverPage, OverHero, OverStory, OverMissie, OverPartner, WordReveal, HandSign, HandLine });
