{"id":1306,"date":"2026-04-30T12:48:00","date_gmt":"2026-04-30T12:48:00","guid":{"rendered":"https:\/\/watermolenfeesten.be\/?page_id=1306"},"modified":"2026-05-26T19:05:57","modified_gmt":"2026-05-26T19:05:57","slug":"vrijwilligers","status":"publish","type":"page","link":"https:\/\/watermolenfeesten.be\/?page_id=1306","title":{"rendered":"Vrijwilligers"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"1306\" class=\"elementor elementor-1306\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c4a09bf e-flex e-con-boxed e-con e-parent\" data-id=\"c4a09bf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c7260f1 elementor-widget elementor-widget-html\" data-id=\"c7260f1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"nl\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Vrijwilligers \u2014 Watermolenfeesten 2026<\/title>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Playfair+Display:wght@700;900&family=Lato:wght@300;400;700&display=swap\" rel=\"stylesheet\">\n<style>\n  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n  :root {\n    --blauw: #41A9CC; --blauw-donker: #2e87a8;\n    --geel: #F8DE60; --geel-donker: #e0c43a;\n    --bruin: #5E4F45; --bruin-licht: #7a6558;\n    --creme: #faf8f4; --wit: #ffffff;\n    --tekst: #3a3028; --subtekst: #6b5e55;\n  }\n  html { scroll-behavior: smooth; }\n  body { font-family: 'Lato', sans-serif; background-color: var(--creme); color: var(--tekst); overflow-x: hidden; }\n \n  nav {\n    position: fixed; top: 0; left: 0; right: 0; z-index: 100;\n    display: flex; align-items: center; justify-content: space-between;\n    padding: 0 2.5rem; height: 64px;\n    background: rgba(94, 79, 69, 0.96); backdrop-filter: blur(8px);\n  }\n  .nav-logo { width: 42px; height: 42px; border-radius: 50%; object-fit: cover; border: 2px solid var(--geel); }\n  .nav-links { display: flex; gap: 0.3rem; list-style: none; }\n  .nav-links a {\n    display: block; padding: 0.4rem 1rem; color: rgba(255,255,255,0.85);\n    text-decoration: none; font-size: 0.82rem; font-weight: 700;\n    letter-spacing: 2px; text-transform: uppercase; border-radius: 2px;\n    transition: color 0.2s, background 0.2s;\n  }\n  .nav-links a:hover, .nav-links a.actief { color: var(--bruin); background: var(--geel); }\n  .nav-burger { display: none; flex-direction: column; gap: 5px; cursor: pointer; padding: 6px; background: none; border: none; }\n  .nav-burger span { display: block; width: 24px; height: 2px; background: #fff; border-radius: 2px; }\n  @media (max-width: 640px) {\n    .nav-burger { display: flex; }\n    .nav-links { display: none; flex-direction: column; position: absolute; top: 64px; left: 0; right: 0; background: var(--bruin); padding: 1rem 2rem 1.5rem; gap: 0.3rem; }\n    .nav-links.open { display: flex; }\n    .nav-links a { font-size: 1rem; padding: 0.7rem 1rem; }\n  }\n \n  .hero {\n    position: relative; min-height: 52vh; display: flex; flex-direction: column;\n    align-items: center; justify-content: center; text-align: center;\n    padding: 6rem 2rem 4rem;\n    background: linear-gradient(rgba(0,0,0,0.45), rgba(0,0,0,0.6)),\n      url('https:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/04\/bar_del_sol_square.jpg') center\/cover no-repeat;\n  }\n  .hero::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 80px; background: linear-gradient(to bottom, transparent, var(--creme)); }\n  .hero-logo { width: 100px; height: 100px; border-radius: 50%; border: 3px solid var(--geel); object-fit: cover; margin-bottom: 1.5rem; animation: fadeDown 1s ease both; }\n  .hero h1 { font-family: 'Playfair Display', serif; font-size: clamp(2.2rem, 6vw, 4.5rem); font-weight: 900; color: #fff; line-height: 1; letter-spacing: -1px; animation: fadeDown 1s ease 0.1s both; }\n  .hero-datum { font-size: clamp(0.9rem, 2.5vw, 1.2rem); font-weight: 300; letter-spacing: 6px; text-transform: uppercase; color: var(--geel); margin: 0.8rem 0 0; animation: fadeDown 1s ease 0.2s both; }\n \n  \/* \u2500\u2500 UITLEG SECTIE \u2500\u2500 *\/\n  .uitleg-sectie {\n    max-width: 760px;\n    margin: 0 auto;\n    padding: 3rem 1.5rem 0;\n  }\n  .uitleg-dank {\n    background: var(--wit);\n    border-radius: 4px;\n    border-left: 5px solid var(--geel);\n    padding: 2rem 2rem;\n    margin-bottom: 1.5rem;\n    box-shadow: 0 2px 12px rgba(0,0,0,0.06);\n  }\n  .uitleg-dank h2 {\n    font-family: 'Playfair Display', serif;\n    font-size: 1.5rem;\n    color: var(--bruin);\n    margin-bottom: 0.8rem;\n  }\n  .uitleg-dank p {\n    font-size: 0.97rem;\n    color: var(--subtekst);\n    line-height: 1.85;\n    margin-bottom: 0.6rem;\n  }\n  .uitleg-dank p:last-child { margin-bottom: 0; }\n  .uitleg-dank strong { color: var(--tekst); }\n  .uitleg-dank .citaat {\n    font-family: 'Playfair Display', serif;\n    font-size: 1.05rem;\n    color: var(--bruin);\n    font-style: italic;\n    border-top: 1px solid #e8e2db;\n    margin-top: 1rem;\n    padding-top: 1rem;\n  }\n \n  .uitleg-stappen {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n    gap: 1rem;\n    margin-bottom: 2rem;\n  }\n  .stap {\n    background: var(--wit);\n    border-radius: 4px;\n    padding: 1.2rem 1.4rem;\n    box-shadow: 0 2px 8px rgba(0,0,0,0.05);\n    border-top: 3px solid var(--blauw);\n    display: flex;\n    flex-direction: column;\n    gap: 0.4rem;\n  }\n  .stap-nummer { font-size: 1.6rem; }\n  .stap h3 { font-family: 'Playfair Display', serif; font-size: 0.95rem; color: var(--bruin); }\n  .stap p { font-size: 0.82rem; color: var(--subtekst); line-height: 1.6; }\n \n  #app { background: #f1f5f9; min-height: 300px; }\n \n  .sponsors { padding: 5rem 2rem; background: var(--bruin); text-align: center; overflow: hidden; }\n  .sponsors h2 { font-family: 'Playfair Display', serif; font-size: 1.8rem; color: #fff; margin-bottom: 0.5rem; }\n  .sponsors-sub { font-size: 0.75rem; letter-spacing: 4px; text-transform: uppercase; color: var(--geel); margin-bottom: 3rem; }\n  .carousel-track-wrap { overflow: hidden; mask-image: linear-gradient(to right, transparent, black 15%, black 85%, transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 15%, black 85%, transparent); }\n  .carousel-track { display: flex; gap: 4rem; align-items: center; animation: scrolltrack 18s linear infinite; width: max-content; }\n  .carousel-track:hover { animation-play-state: paused; }\n  .sponsor-logo { max-height: 200px !important; max-width: 250px !important; object-fit: contain; display: block !important; width: auto !important; height: auto !important; filter: none !important; opacity: 1 !important; }\n \n  footer { background: #2a1f1a; color: rgba(255,255,255,0.55); text-align: center; padding: 3rem 2rem; font-size: 0.88rem; }\n  .footer-logo { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; margin-bottom: 1rem; opacity: 0.65; border: 2px solid var(--geel); }\n  .footer-links { margin-bottom: 1.2rem; }\n  footer a { color: var(--geel); text-decoration: none; margin: 0 0.8rem; font-weight: 700; letter-spacing: 1px; transition: color 0.2s; }\n  footer a:hover { color: #fff; }\n \n  @keyframes fadeDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }\n  @keyframes scrolltrack { from { transform: translateX(0); } to { transform: translateX(-50%); } }\n \n  @media (max-width: 500px) {\n    .uitleg-dank { padding: 1.4rem; }\n    .uitleg-sectie { padding: 2rem 1rem 0; }\n  }\n<\/style>\n<\/head>\n<body>\n \n<nav id=\"navbar\">\n  <img decoding=\"async\" class=\"nav-logo\" src=\"https:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/03\/logo-klein.jpg\" alt=\"Logo Watermolenfeesten\">\n  <ul class=\"nav-links\" id=\"navLinks\">\n    <li><a href=\"https:\/\/watermolenfeesten.be\/\">Home<\/a><\/li>\n    <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=615\">Programma<\/a><\/li>\n    <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=1542\">Sponsors<\/a><\/li>\n    <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=963\">Kandidates 2026<\/a><\/li>\n    <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=1014\">Affiches<\/a><\/li>\n    <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=1064\">Info<\/a><\/li>\n     <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=1306\" class=\"actief\">Vrijwilligers<\/a><\/li>\n    <li><a href=\"https:\/\/watermolenfeesten.be\/?page_id=1208\">Wie zijn we<\/a><\/li>\n   \n  <\/ul>\n  <button class=\"nav-burger\" id=\"burger\" aria-label=\"Menu openen\">\n    <span><\/span><span><\/span><span><\/span>\n  <\/button>\n<\/nav>\n \n<section class=\"hero\">\n  <img decoding=\"async\" class=\"hero-logo\" src=\"https:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/03\/logo-klein.jpg\" alt=\"Logo Watermolenfeesten\">\n  <h1>Vrijwilligers<\/h1>\n  <p class=\"hero-datum\">3 &mdash; 4 &mdash; 5 Juli 2026<\/p>\n<\/section>\n \n<!-- UITLEG SECTIE -->\n<div class=\"uitleg-sectie\">\n \n  <div class=\"uitleg-dank\">\n    <h2>\ud83d\ude4c Bedankt om je op te geven!<\/h2>\n    <p>\n      De Watermolenfeesten zijn pas mogelijk dankzij de inzet van onze geweldige vrijwilligers.\n      Of je nu achter de toog staat, de ingang bemant of helpt bij de opbouw - elke helpende hand telt!\n    <\/p>\n    <p>\n      Schrijf je hieronder in voor \u00e9\u00e9n of meerdere shifts. Je ziet meteen hoeveel plekken nog vrij zijn per shift.\n      We contacteren je via gsm als er nog iets verandert of als we extra info hebben.\n    <\/p>\n    <p class=\"citaat\">\n      \"Geen feesten zonder vrijwilligers - en geen betere vrijwilligers dan de onze.\" \ud83c\udf89\n    <\/p>\n  <\/div>\n \n  <div class=\"uitleg-stappen\">\n    <div class=\"stap\">\n      <div class=\"stap-nummer\">1\ufe0f\u20e3<\/div>\n      <h3>Vul je gegevens in<\/h3>\n      <p>Geef je naam, gsm-nummer en hoeveel shifts je maximaal wil doen over het weekend.<\/p>\n    <\/div>\n    <div class=\"stap\">\n      <div class=\"stap-nummer\">2\ufe0f\u20e3<\/div>\n      <h3>Kies je shift(s)<\/h3>\n      <p>Blader door de beschikbare shifts per dag en klik op \"Inschrijven\" bij de shifts die jou passen. (Je mag meer shifts aanduiden dan je max voorkeur.)<\/p>\n    <\/div>\n    <div class=\"stap\">\n      <div class=\"stap-nummer\">3\ufe0f\u20e3<\/div>\n      <h3>Klaar!<\/h3>\n      <p>Je inschrijving wordt meteen opgeslagen. We nemen contact op als er info is. Alvast heel erg bedankt!<\/p>\n    <\/div>\n  <\/div>\n \n<\/div>\n \n<div id=\"app\"><\/div>\n \n<section class=\"sponsors\">\n  <h2>Onze sponsors<\/h2>\n  <p class=\"sponsors-sub\">Met dank aan<\/p>\n  <div class=\"carousel-track-wrap\">\n    <div class=\"carousel-track\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/proof.jpg\" alt=\"Proof\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"https:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/04\/De-knock.jpg\" alt=\"De Knock\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"https:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/04\/cafe-lungo.jpg\" alt=\"Caf\u00e9 Lungo\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/tank-service.png\" alt=\"tank-service\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/t-neerhof.png\" alt=\"Neerhof\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/kameleon.jpeg\" alt=\"kameleon\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/04\/saver.jpg\" alt=\"saver\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/wendy-en-sonny.png\" alt=\"wendy-en-sonny\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/BenedictHuysentruyt.jpg\" alt=\"BenedictHuysentruyt\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/Bombastic-2026-Gold-Ballie-Boulet.jpg\" alt=\"ballie-boulet\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/rational.png\" alt=\"rational\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/Bombastic-2026-Gold-Ballie-Boulet.jpg\" alt=\"ballie-boulet\">\n      <img decoding=\"async\" class=\"sponsor-logo\" src=\"http:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/05\/laverge.jpg\" alt=\"Laverge\">\n    <\/div>\n  <\/div>\n<\/section>\n \n<footer>\n  <img decoding=\"async\" class=\"footer-logo\" src=\"https:\/\/watermolenfeesten.be\/wp-content\/uploads\/2026\/03\/logo-klein.jpg\" alt=\"Logo\">\n  <div class=\"footer-links\">\n    <a href=\"https:\/\/www.facebook.com\/profile.php?id=61574036308953\" target=\"_blank\">Facebook<\/a>\n    <a href=\"https:\/\/www.instagram.com\/watermolenfeesten2025\/\" target=\"_blank\">Instagram<\/a>\n  <\/div>\n  <p>&copy; 2026 Watermolenfeesten &mdash; Alle rechten voorbehouden<\/p>\n<\/footer>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/react\/18.2.0\/umd\/react.production.min.js\"><\/script>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/react-dom\/18.2.0\/umd\/react-dom.production.min.js\"><\/script>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/babel-standalone\/7.23.2\/babel.min.js\"><\/script>\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@supabase\/supabase-js@2\"><\/script>\n\n<script type=\"text\/babel\">\nconst { useState, useEffect } = React;\n\nconst SUPABASE_URL = 'https:\/\/guosondewpgrhqzyulwp.supabase.co';\nconst SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imd1b3NvbmRld3Bncmhxenl1bHdwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc1NDYzNzEsImV4cCI6MjA5MzEyMjM3MX0.Rop-sabNPuRmhcUwhRNJqEEuVDPYNoIZjS9UMzyC490';\nconst sb = supabase.createClient(SUPABASE_URL, SUPABASE_KEY);\n\nconst ADMIN_USER = 'Admin';\nconst ADMIN_PASS = 'H2O_Molen#Heule';\n\nconst OPDRACHTEN = ['Opbouw', 'Toog Tent', 'Toog Bar Del Sol', 'Afbraak', 'Kassa tent', 'Kassa Bar Del Sol' , 'Andere'];\nconst ICONS = { 'Opbouw': '\ud83d\udd28', 'Toog Tent': '\ud83c\udf7a', 'Toog Bar Del Sol': '\ud83c\udf1e', 'Afbraak': '\ud83e\uddf9', 'Kassa tent': '\ud83c\udf9f\ufe0f', 'Kassa tent': '\ud83c\udf9f\ufe0f' };\n\nconst LBL = { display: 'block', fontSize: 11, fontWeight: 700, letterSpacing: 2, textTransform: 'uppercase', color: '#6b5e55', marginBottom: 4 };\nconst INP = { width: '100%', padding: '8px 10px', borderRadius: 3, border: '1.5px solid #ddd', fontFamily: \"'Lato', sans-serif\", fontSize: 14, color: '#3a3028', background: '#faf8f4', boxSizing: 'border-box' };\n\n\/\/ \u2500\u2500 FILTER KNOP \u2500\u2500\nfunction FilterKnop({ actief, onClick, children }) {\n  return (\n    <button onClick={onClick} style={{\n      padding: '5px 13px', borderRadius: 3, cursor: 'pointer',\n      border: `1.5px solid ${actief ? '#5E4F45' : '#ddd'}`,\n      background: actief ? '#5E4F45' : '#fff',\n      color: actief ? '#fff' : '#6b5e55',\n      fontFamily: \"'Lato', sans-serif\", fontWeight: 700, fontSize: 12,\n      transition: 'all 0.15s', whiteSpace: 'nowrap',\n    }}>{children}<\/button>\n  );\n}\n\n\/\/ \u2500\u2500 LOGIN SCHERM \u2500\u2500\nfunction LoginScherm({ onLogin }) {\n  const [gebruiker, setGebruiker] = useState('');\n  const [wachtwoord, setWachtwoord] = useState('');\n  const [fout, setFout] = useState('');\n  const [toonPaswoord, setToonPaswoord] = useState(false);\n\n  const handleLogin = () => {\n    if (gebruiker === ADMIN_USER && wachtwoord === ADMIN_PASS) {\n      sessionStorage.setItem('wmf_admin', '1');\n      onLogin();\n    } else {\n      setFout('Gebruikersnaam of wachtwoord is onjuist.');\n      setWachtwoord('');\n    }\n  };\n  const handleKey = (e) => { if (e.key === 'Enter') handleLogin(); };\n\n  return (\n    <div style={{ maxWidth: 420, margin: '0 auto', padding: '3rem 1.5rem' }}>\n      <div style={{ background: '#fff', borderRadius: 4, borderTop: '4px solid #5E4F45', padding: '2rem', boxShadow: '0 4px 20px rgba(0,0,0,0.1)' }}>\n        <div style={{ textAlign: 'center', marginBottom: '1.8rem' }}>\n          <div style={{ fontSize: 40, marginBottom: 8 }}>\ud83d\udd10<\/div>\n          <h2 style={{ fontFamily: \"'Playfair Display', serif\", color: '#5E4F45', fontSize: '1.4rem', marginBottom: 4 }}>Beheer inloggen<\/h2>\n          <p style={{ fontSize: 13, color: '#6b5e55' }}>Enkel voor organisatoren<\/p>\n        <\/div>\n        <div style={{ marginBottom: '1rem' }}>\n          <label style={LBL}>Gebruikersnaam<\/label>\n          <input value={gebruiker} onChange={e => setGebruiker(e.target.value)} onKeyDown={handleKey} placeholder=\"Gebruikersnaam\" autoComplete=\"username\" style={INP} \/>\n        <\/div>\n        <div style={{ marginBottom: '1.4rem' }}>\n          <label style={LBL}>Wachtwoord<\/label>\n          <div style={{ position: 'relative' }}>\n            <input type={toonPaswoord ? 'text' : 'password'} value={wachtwoord} onChange={e => setWachtwoord(e.target.value)} onKeyDown={handleKey} placeholder=\"Wachtwoord\" autoComplete=\"current-password\" style={{ ...INP, paddingRight: 40 }} \/>\n            <button onClick={() => setToonPaswoord(!toonPaswoord)} style={{ position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)', background: 'none', border: 'none', cursor: 'pointer', fontSize: 16, color: '#6b5e55' }}>{toonPaswoord ? '\ud83d\ude48' : '\ud83d\udc41\ufe0f'}<\/button>\n          <\/div>\n        <\/div>\n        {fout && <div style={{ background: '#fee2e2', border: '1px solid #fca5a5', borderRadius: 4, padding: '8px 12px', color: '#991b1b', fontSize: 13, fontWeight: 700, marginBottom: '1rem' }}>\u26a0 {fout}<\/div>}\n        <button onClick={handleLogin} style={{ width: '100%', background: '#5E4F45', color: '#fff', border: 'none', borderRadius: 3, padding: '11px', fontWeight: 700, fontSize: 14, letterSpacing: 1, textTransform: 'uppercase', cursor: 'pointer', fontFamily: \"'Lato', sans-serif\" }}>\n          Inloggen\n        <\/button>\n      <\/div>\n    <\/div>\n  );\n}\n\n\/\/ \u2500\u2500 STATUS BADGE \u2500\u2500\nfunction StatusBadge({ s }) {\n  const vrij = s.max - s.ingeschreven.length;\n  const isVol = s.ingeschreven.length >= s.max + s.reserve;\n  const isReserve = !isVol && s.ingeschreven.length >= s.max;\n  const reserveVrij = s.reserve - Math.max(0, s.ingeschreven.length - s.max);\n  const stijl = isVol\n    ? { background: '#fee2e2', color: '#991b1b', border: '1px solid #fca5a5' }\n    : isReserve\n    ? { background: '#fef3c7', color: '#92400e', border: '1px solid #fcd34d' }\n    : { background: '#d1fae5', color: '#065f46', border: '1px solid #6ee7b7' };\n  return (\n    <span style={{ ...stijl, borderRadius: 999, padding: '2px 10px', fontSize: 12, fontWeight: 700, whiteSpace: 'nowrap' }}>\n      {isVol ? '\u2717 Vol' : isReserve ? `\u26a0 Reserve (${reserveVrij} vrij)` : `\u2713 ${vrij} plek${vrij !== 1 ? 'ken' : ''} vrij`}\n    <\/span>\n  );\n}\n\n\/\/ \u2500\u2500 SHIFT KAART (vrijwilliger) \u2500\u2500\nfunction ShiftKaart({ s, naam, gsm, maxShifts, aantalIngeschreven, onInschrijven }) {\n  const isVol = s.ingeschreven.length >= s.max + s.reserve;\n  const isReserveOnly = !isVol && s.ingeschreven.length >= s.max;\n  const alIn = naam && s.ingeschreven.includes(naam.trim());\n  const alsReserve = alIn && s.ingeschreven.indexOf(naam.trim()) >= s.max;\n  const pct = Math.min(100, Math.round(s.ingeschreven.length \/ (s.max + s.reserve) * 100));\n  const balkKleur = isVol ? '#ef4444' : isReserveOnly ? '#f59e0b' : '#10b981';\n  const randKleur = isVol ? '#ef4444' : isReserveOnly ? '#f59e0b' : '#41A9CC';\n  const kanInschrijven = naam?.trim() && gsm?.trim();\n  const maxBereikt = maxShifts > 0 && aantalIngeschreven >= maxShifts && !alIn;\n\n  let actieblok;\n  if (alIn) {\n    actieblok = <div style={{ padding: '7px 12px', background: '#ecfdf5', border: '1px solid #6ee7b7', borderRadius: 4, color: '#065f46', fontSize: 13, fontWeight: 700 }}>\u2713 Jij staat ingeschreven{alsReserve ? ' (als reserve)' : ''}<\/div>;\n  } else if (isVol) {\n    actieblok = <div style={{ padding: '7px 12px', background: '#fee2e2', border: '1px solid #fca5a5', borderRadius: 4, color: '#991b1b', fontSize: 13 }}>\u2717 Deze shift is vol<\/div>;\n  } else if (!kanInschrijven) {\n    actieblok = <button disabled style={{ padding: '7px 16px', background: '#eee', color: '#aaa', border: 'none', borderRadius: 4, fontSize: 13, fontWeight: 700, cursor: 'not-allowed', fontFamily: \"'Lato', sans-serif\" }}>Vul eerst naam en gsm in<\/button>;\n  } else if (maxBereikt) {\n    actieblok = <div style={{ padding: '7px 12px', background: '#fef3c7', border: '1px solid #fcd34d', borderRadius: 4, color: '#92400e', fontSize: 13, fontWeight: 700 }}>\u26a0 Maximum van {maxShifts} shift{maxShifts !== 1 ? 's' : ''} bereikt<\/div>;\n  } else {\n    actieblok = <button onClick={() => onInschrijven(s.id)} style={{ padding: '7px 18px', border: 'none', borderRadius: 4, fontSize: 13, fontWeight: 700, cursor: 'pointer', fontFamily: \"'Lato', sans-serif\", letterSpacing: 1, background: isReserveOnly ? '#f59e0b' : '#41A9CC', color: '#fff' }}>{isReserveOnly ? 'Inschrijven als reserve' : 'Inschrijven'}<\/button>;\n  }\n\n  return (\n    <div style={{ background: '#fff', borderRadius: 4, borderLeft: `4px solid ${randKleur}`, padding: '1.2rem 1.5rem', marginBottom: '0.9rem', boxShadow: '0 2px 8px rgba(0,0,0,0.05)' }}>\n      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', flexWrap: 'wrap', gap: 8, marginBottom: 8 }}>\n        <div>\n          <span style={{ fontSize: 18, marginRight: 8 }}>{ICONS[s.opdracht] || '\u2b50'}<\/span>\n          <strong style={{ fontSize: 15, color: '#3a3028' }}>{s.opdracht}<\/strong>\n          <span style={{ color: '#6b5e55', fontSize: 13, marginLeft: 10 }}>\u23f0 {s.van} \u2013 {s.tot}<\/span>\n        <\/div>\n        <StatusBadge s={s} \/>\n      <\/div>\n      <div style={{ marginBottom: 10 }}>\n        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: '#6b5e55', marginBottom: 3, fontWeight: 700 }}>\n          <span>{s.ingeschreven.length} \/ {s.max} ingeschreven<\/span>\n          <span>{s.reserve} reserve plek{s.reserve !== 1 ? 'ken' : ''}<\/span>\n        <\/div>\n        <div style={{ background: '#eee', borderRadius: 2, height: 7 }}>\n          <div style={{ width: `${pct}%`, height: '100%', background: balkKleur, borderRadius: 2, transition: 'width 0.4s' }} \/>\n        <\/div>\n      <\/div>\n      {actieblok}\n    <\/div>\n  );\n}\n\n\/\/ \u2500\u2500 BEHEER PANEL \u2500\u2500\nfunction BeheerPanel({ shifts, laden, onVernieuwen, onLogout }) {\n  const leeg = { dag: '', opdracht: 'Opbouw', andereOpdracht: '', van: '14:00', tot: '18:00', max: 4, reserve: 1 };\n  const [form, setForm] = useState(leeg);\n  const [toonForm, setToonForm] = useState(false);\n  const [bezig, setBezig] = useState(false);\n  const [melding, setMelding] = useState('');\n\n  const f = (k, v) => setForm(prev => ({ ...prev, [k]: v }));\n  const toonMelding = (t) => { setMelding(t); setTimeout(() => setMelding(''), 3500); };\n\n  const handleOpslaan = async () => {\n    const opdracht = form.opdracht === 'Andere' ? form.andereOpdracht.trim() : form.opdracht;\n    if (!form.dag.trim()) { toonMelding('\u26a0 Vul een dag in.'); return; }\n    if (!opdracht) { toonMelding('\u26a0 Vul een opdrachtnaam in.'); return; }\n    setBezig(true);\n    const { error } = await sb.from('shifts').insert({\n      dag: form.dag.trim(), opdracht, van: form.van, tot: form.tot,\n      max: Number(form.max), reserve: Number(form.reserve), ingeschreven: [], gsm_nummers: [], max_shifts_voorkeur: []\n    });\n    setBezig(false);\n    if (error) { toonMelding('\u274c Fout: ' + error.message); return; }\n    setForm(leeg);\n    setToonForm(false);\n    toonMelding('\u2713 Shift opgeslagen!');\n    onVernieuwen();\n  };\n\n  const handleVerwijder = async (id) => {\n    if (!confirm('Shift verwijderen? Dit kan niet ongedaan gemaakt worden.')) return;\n    await sb.from('shifts').delete().eq('id', id);\n    onVernieuwen();\n  };\n\n  const dagen = [...new Set(shifts.map(s => s.dag))];\n\n  return (\n    <div style={{ maxWidth: 760, margin: '0 auto', padding: '2rem 1.5rem 3rem' }}>\n      {melding && <div style={{ background: '#1e3a5f', color: '#fff', padding: '10px 18px', borderRadius: 6, marginBottom: 16, fontWeight: 700, fontSize: 14 }}>{melding}<\/div>}\n\n      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20, flexWrap: 'wrap', gap: 10 }}>\n        <h2 style={{ fontFamily: \"'Playfair Display', serif\", color: '#5E4F45', fontSize: '1.5rem' }}>Shifts beheren<\/h2>\n        <div style={{ display: 'flex', gap: 8 }}>\n          <button onClick={() => setToonForm(!toonForm)} style={{ background: '#41A9CC', color: '#fff', border: 'none', borderRadius: 3, padding: '8px 18px', fontWeight: 700, fontSize: 13, letterSpacing: 1, textTransform: 'uppercase', cursor: 'pointer', fontFamily: \"'Lato', sans-serif\" }}>\n            {toonForm ? '\u2715 Annuleer' : '+ Nieuwe shift'}\n          <\/button>\n          <button onClick={onLogout} style={{ background: '#fee2e2', color: '#991b1b', border: '1px solid #fca5a5', borderRadius: 3, padding: '8px 14px', fontWeight: 700, fontSize: 12, letterSpacing: 1, textTransform: 'uppercase', cursor: 'pointer', fontFamily: \"'Lato', sans-serif\" }}>\n            \ud83d\udd13 Uitloggen\n          <\/button>\n        <\/div>\n      <\/div>\n\n      {toonForm && (\n        <div style={{ background: '#fff', borderRadius: 4, borderTop: '3px solid #41A9CC', padding: '1.5rem', marginBottom: '1.5rem', boxShadow: '0 2px 12px rgba(0,0,0,0.07)' }}>\n          <h3 style={{ fontFamily: \"'Playfair Display', serif\", color: '#5E4F45', marginBottom: '1.2rem', fontSize: '1.1rem' }}>Nieuwe shift toevoegen<\/h3>\n          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', gap: '1rem' }}>\n            <div style={{ gridColumn: '1 \/ -1' }}>\n              <label style={LBL}>Dag <span style={{ color: '#41A9CC', fontSize: 10, letterSpacing: 0 }}>(vrij in te vullen, bv. \"Vrijdag 3 juli\")<\/span><\/label>\n              <input value={form.dag} onChange={e => f('dag', e.target.value)} placeholder=\"bv. Vrijdag 3 juli\" style={INP} \/>\n            <\/div>\n            <div>\n              <label style={LBL}>Opdracht<\/label>\n              <select value={form.opdracht} onChange={e => f('opdracht', e.target.value)} style={INP}>\n                {OPDRACHTEN.map(o => <option key={o}>{o}<\/option>)}\n              <\/select>\n            <\/div>\n            {form.opdracht === 'Andere' && (\n              <div>\n                <label style={LBL}>Naam opdracht<\/label>\n                <input value={form.andereOpdracht} onChange={e => f('andereOpdracht', e.target.value)} placeholder=\"bv. Parking\" style={INP} \/>\n              <\/div>\n            )}\n            <div>\n              <label style={LBL}>Van<\/label>\n              <input type=\"time\" value={form.van} onChange={e => f('van', e.target.value)} style={INP} \/>\n            <\/div>\n            <div>\n              <label style={LBL}>Tot<\/label>\n              <input type=\"time\" value={form.tot} onChange={e => f('tot', e.target.value)} style={INP} \/>\n            <\/div>\n            <div>\n              <label style={LBL}>Max personen<\/label>\n              <input type=\"number\" min=\"1\" value={form.max} onChange={e => f('max', e.target.value)} style={INP} \/>\n            <\/div>\n            <div>\n              <label style={LBL}>Reserve plekken<\/label>\n              <input type=\"number\" min=\"0\" value={form.reserve} onChange={e => f('reserve', e.target.value)} style={INP} \/>\n            <\/div>\n          <\/div>\n          <button onClick={handleOpslaan} disabled={bezig} style={{ marginTop: '1.2rem', background: bezig ? '#aaa' : '#10b981', color: '#fff', border: 'none', borderRadius: 3, padding: '9px 22px', fontWeight: 700, fontSize: 13, letterSpacing: 1, textTransform: 'uppercase', cursor: bezig ? 'not-allowed' : 'pointer', fontFamily: \"'Lato', sans-serif\" }}>\n            {bezig ? 'Opslaan...' : '\u2713 Opslaan'}\n          <\/button>\n        <\/div>\n      )}\n\n      {laden ? (\n        <div style={{ textAlign: 'center', padding: '3rem', color: '#6b5e55' }}>Shifts laden...<\/div>\n      ) : shifts.length === 0 ? (\n        <div style={{ textAlign: 'center', padding: '3rem', color: '#6b5e55' }}>Nog geen shifts. Klik op \"+ Nieuwe shift\" om te beginnen.<\/div>\n      ) : (\n        dagen.map(dag => (\n          <div key={dag} style={{ marginBottom: '2rem' }}>\n            <div style={{ fontFamily: \"'Playfair Display', serif\", fontSize: '1.25rem', color: '#5E4F45', borderBottom: '2px solid #F8DE60', paddingBottom: '0.4rem', marginBottom: '1rem', fontWeight: 700 }}>{dag}<\/div>\n            {shifts.filter(s => s.dag === dag).map(s => {\n              const namen = s.ingeschreven || [];\n              const gsms = s.gsm_nummers || [];\n              const voorkeuren = s.max_shifts_voorkeur || [];\n              const isVol = namen.length >= s.max + s.reserve;\n              const isReserveOnly = !isVol && namen.length >= s.max;\n              const randKleur = isVol ? '#ef4444' : isReserveOnly ? '#f59e0b' : '#41A9CC';\n              return (\n                <div key={s.id} style={{ background: '#fff', borderRadius: 4, borderLeft: `4px solid ${randKleur}`, padding: '1rem 1.2rem', marginBottom: '0.8rem', boxShadow: '0 1px 6px rgba(0,0,0,0.05)', position: 'relative' }}>\n                  <button onClick={() => handleVerwijder(s.id)} style={{ position: 'absolute', top: 10, right: 10, background: '#fee2e2', color: '#ef4444', border: 'none', borderRadius: 3, padding: '3px 9px', fontSize: 12, fontWeight: 700, cursor: 'pointer', fontFamily: \"'Lato', sans-serif\" }}>\u2715 Verwijder<\/button>\n                  <div style={{ marginBottom: 6, paddingRight: 90 }}>\n                    <span style={{ fontSize: 16, marginRight: 6 }}>{ICONS[s.opdracht] || '\u2b50'}<\/span>\n                    <strong style={{ color: '#3a3028' }}>{s.opdracht}<\/strong>\n                    <span style={{ color: '#6b5e55', fontSize: 13, marginLeft: 10 }}>\u23f0 {s.van} \u2013 {s.tot}<\/span>\n                  <\/div>\n                  <div style={{ fontSize: 12, color: '#6b5e55', marginBottom: namen.length ? 8 : 0 }}>\n                    \ud83d\udc65 {namen.length} \/ {s.max} ingeschreven &nbsp;|&nbsp; \ud83d\udd04 {s.reserve} reserve\n                  <\/div>\n                  {namen.length > 0 && (\n                    <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>\n                      {namen.map((n, i) => (\n                        <div key={n + i} style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>\n                          <span style={{ padding: '2px 9px', borderRadius: 999, fontSize: 12, fontWeight: 700, background: i >= s.max ? '#fef3c7' : '#eff6ff', color: i >= s.max ? '#92400e' : '#1e40af', border: `1px solid ${i >= s.max ? '#fcd34d' : '#93c5fd'}` }}>\n                            {n}{i >= s.max ? ' (R)' : ''}\n                          <\/span>\n                          {gsms[i] && <a href={`tel:${gsms[i]}`} style={{ fontSize: 12, color: '#41A9CC', fontWeight: 700, textDecoration: 'none' }}>\ud83d\udcf1 {gsms[i]}<\/a>}\n                          {voorkeuren[i] > 0 && <span style={{ fontSize: 11, color: '#6b5e55', background: '#f3f4f6', borderRadius: 999, padding: '1px 8px', border: '1px solid #e5e7eb' }}>max {voorkeuren[i]} shift{voorkeuren[i] !== 1 ? 's' : ''}<\/span>}\n                        <\/div>\n                      ))}\n                    <\/div>\n                  )}\n                <\/div>\n              );\n            })}\n          <\/div>\n        ))\n      )}\n    <\/div>\n  );\n}\n\n\/\/ \u2500\u2500 HOOFD APP \u2500\u2500\nfunction App() {\n  const [shifts, setShifts] = useState([]);\n  const [laden, setLaden] = useState(true);\n  const [view, setView] = useState('vrijwilliger');\n  const [ingelogd, setIngelogd] = useState(sessionStorage.getItem('wmf_admin') === '1');\n  const [naam, setNaam] = useState('');\n  const [gsm, setGsm] = useState('');\n  const [maxShifts, setMaxShifts] = useState(0);\n  const [filterDag, setFilterDag] = useState('alle');\n  const [filterOpdracht, setFilterOpdracht] = useState('alle');\n\n  const laadShifts = async () => {\n    setLaden(true);\n    const { data } = await sb.from('shifts').select('*').order('id');\n    setShifts(data || []);\n    setLaden(false);\n  };\n\n  useEffect(() => { laadShifts(); }, []);\n\n  const aantalIngeschreven = naam.trim()\n    ? shifts.filter(s => s.ingeschreven.includes(naam.trim())).length\n    : 0;\n\n  const handleInschrijven = async (id) => {\n    const n = naam.trim();\n    const g = gsm.trim();\n    if (!n || !g) return;\n    const s = shifts.find(x => x.id === id);\n    if (!s || s.ingeschreven.includes(n) || s.ingeschreven.length >= s.max + s.reserve) return;\n    if (maxShifts > 0 && aantalIngeschreven >= maxShifts) return;\n    const nieuweNamen = [...s.ingeschreven, n];\n    const nieuweGsms = [...(s.gsm_nummers || []), g];\n    const nieuweVoorkeuren = [...(s.max_shifts_voorkeur || []), maxShifts];\n    const { error } = await sb.from('shifts').update({\n      ingeschreven: nieuweNamen,\n      gsm_nummers: nieuweGsms,\n      max_shifts_voorkeur: nieuweVoorkeuren\n    }).eq('id', id);\n    if (!error) setShifts(prev => prev.map(x => x.id === id ? { ...x, ingeschreven: nieuweNamen, gsm_nummers: nieuweGsms, max_shifts_voorkeur: nieuweVoorkeuren } : x));\n  };\n\n  const handleLogout = () => {\n    sessionStorage.removeItem('wmf_admin');\n    setIngelogd(false);\n    setView('vrijwilliger');\n  };\n\n  \/\/ Unieke waarden voor filters\n  const dagen = [...new Set(shifts.map(s => s.dag))];\n  const opdrachten = [...new Set(shifts.map(s => s.opdracht))];\n\n  \/\/ Gefilterde shifts\n  const gefilterd = shifts\n    .filter(s => filterDag === 'alle' || s.dag === filterDag)\n    .filter(s => filterOpdracht === 'alle' || s.opdracht === filterOpdracht);\n\n  const dagenGefilterd = filterDag === 'alle' ? dagen : dagen.filter(d => d === filterDag);\n\n  const totaalIn = shifts.reduce((a, s) => a + s.ingeschreven.length, 0);\n  const totaalVrij = shifts.reduce((a, s) => a + Math.max(0, s.max - s.ingeschreven.length), 0);\n\n  return (\n    <div style={{ fontFamily: \"'Lato', sans-serif\" }}>\n      {\/* Header balk *\/}\n      <div style={{ background: 'linear-gradient(135deg, #1e3a5f 0%, #2563eb 100%)', padding: '24px 24px 52px', position: 'relative', overflow: 'hidden' }}>\n        <div style={{ position: 'absolute', top: -40, right: -40, width: 160, height: 160, background: 'rgba(255,255,255,0.07)', borderRadius: '50%' }} \/>\n        <div style={{ maxWidth: 760, margin: '0 auto', position: 'relative' }}>\n          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 12, marginBottom: 16 }}>\n            <div>\n              <div style={{ color: 'rgba(255,255,255,0.65)', fontSize: 11, fontWeight: 700, letterSpacing: 3, textTransform: 'uppercase', marginBottom: 4 }}>\ud83c\udf89 Watermolenfeesten<\/div>\n              <h2 style={{ color: '#fff', margin: 0, fontSize: 22, fontWeight: 900 }}>Vrijwilligersplanning<\/h2>\n            <\/div>\n            <div style={{ display: 'flex', gap: 6, background: 'rgba(255,255,255,0.12)', borderRadius: 10, padding: 4 }}>\n              <button onClick={() => setView('vrijwilliger')} style={{ padding: '7px 16px', borderRadius: 8, border: 'none', cursor: 'pointer', fontWeight: 700, fontSize: 13, fontFamily: \"'Lato', sans-serif\", background: view === 'vrijwilliger' ? '#fff' : 'transparent', color: view === 'vrijwilliger' ? '#1e3a5f' : 'rgba(255,255,255,0.8)' }}>\ud83d\udc64 Inschrijven<\/button>\n              <button onClick={() => setView('beheer')} style={{ padding: '7px 16px', borderRadius: 8, border: 'none', cursor: 'pointer', fontWeight: 700, fontSize: 13, fontFamily: \"'Lato', sans-serif\", background: view === 'beheer' ? '#fff' : 'transparent', color: view === 'beheer' ? '#1e3a5f' : 'rgba(255,255,255,0.8)' }}>\u2699\ufe0f Beheer<\/button>\n            <\/div>\n          <\/div>\n          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>\n            {[['\ud83d\udc65', totaalIn, 'Ingeschreven'], ['\u2705', totaalVrij, 'Plekken vrij'], ['\ud83d\udccb', shifts.length, 'Shifts']].map(([icon, val, label]) => (\n              <div key={label} style={{ background: 'rgba(255,255,255,0.15)', borderRadius: 8, padding: '8px 16px' }}>\n                <div style={{ color: 'rgba(255,255,255,0.65)', fontSize: 10, fontWeight: 700, letterSpacing: 1 }}>{icon} {label}<\/div>\n                <div style={{ color: '#fff', fontSize: 20, fontWeight: 900 }}>{val}<\/div>\n              <\/div>\n            ))}\n          <\/div>\n        <\/div>\n      <\/div>\n\n      {view === 'vrijwilliger' ? (\n        <div style={{ maxWidth: 760, margin: '-24px auto 0', padding: '0 1.5rem 3rem', position: 'relative' }}>\n\n          {\/* Gegevens invoer *\/}\n          <div style={{ background: '#fff', borderRadius: 4, borderLeft: '4px solid #F8DE60', padding: '1.2rem 1.5rem', marginBottom: '1.2rem', boxShadow: '0 2px 10px rgba(0,0,0,0.07)' }}>\n            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(170px, 1fr))', gap: '1rem', marginBottom: naam.trim() && aantalIngeschreven > 0 ? '1rem' : 0 }}>\n              <div>\n                <label style={{ ...LBL, marginBottom: 6 }}>Jouw naam<\/label>\n                <input value={naam} onChange={e => setNaam(e.target.value)} placeholder=\"Voor- en achternaam\" style={{ ...INP, fontSize: 14, padding: '9px 12px' }} \/>\n              <\/div>\n              <div>\n                <label style={{ ...LBL, marginBottom: 6 }}>GSM nummer <span style={{ color: '#41A9CC', fontSize: 10, letterSpacing: 0 }}>(voor contact)<\/span><\/label>\n                <input value={gsm} onChange={e => setGsm(e.target.value)} placeholder=\"bv. 0478 12 34 56\" type=\"tel\" style={{ ...INP, fontSize: 14, padding: '9px 12px' }} \/>\n              <\/div>\n              <div>\n                <label style={{ ...LBL, marginBottom: 6 }}>Max. shifts dit weekend <span style={{ color: '#41A9CC', fontSize: 10, letterSpacing: 0 }}>(optioneel)<\/span><\/label>\n                <select value={maxShifts} onChange={e => setMaxShifts(Number(e.target.value))} style={{ ...INP, fontSize: 14, padding: '9px 12px' }}>\n                  <option value={0}>Geen limiet<\/option>\n                  {[1,2,3,4,5,6,7,8].map(n => <option key={n} value={n}>{n} shift{n !== 1 ? 's' : ''}<\/option>)}\n                <\/select>\n              <\/div>\n            <\/div>\n\n            {naam.trim() && aantalIngeschreven > 0 && (\n              <div style={{ background: '#eff6ff', border: '1px solid #93c5fd', borderRadius: 4, padding: '8px 12px', fontSize: 13, color: '#1e40af', fontWeight: 700, marginTop: 8 }}>\n                \ud83d\udccb Jij staat al ingeschreven voor {aantalIngeschreven} shift{aantalIngeschreven !== 1 ? 's' : ''}{maxShifts > 0 ? ` (max ${maxShifts})` : ''}\n              <\/div>\n            )}\n\n            {(!naam.trim() || !gsm.trim()) && (\n              <p style={{ fontSize: 12, color: '#6b5e55', marginTop: 8 }}>\u2139 Vul je naam \u00e9n gsm-nummer in om je in te schrijven.<\/p>\n            )}\n          <\/div>\n\n          {\/* Filters *\/}\n          {shifts.length > 0 && (\n            <div style={{ background: '#fff', borderRadius: 4, padding: '1rem 1.2rem', marginBottom: '1.2rem', boxShadow: '0 2px 8px rgba(0,0,0,0.05)' }}>\n\n              {\/* Dag filter *\/}\n              <div style={{ marginBottom: dagen.length > 0 && opdrachten.length > 0 ? '0.8rem' : 0 }}>\n                <div style={{ ...LBL, marginBottom: 6 }}>\ud83d\udcc5 Dag<\/div>\n                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>\n                  <FilterKnop actief={filterDag === 'alle'} onClick={() => setFilterDag('alle')}>Alle dagen<\/FilterKnop>\n                  {dagen.map(d => <FilterKnop key={d} actief={filterDag === d} onClick={() => setFilterDag(d)}>{d}<\/FilterKnop>)}\n                <\/div>\n              <\/div>\n\n              {\/* Opdracht filter *\/}\n              {opdrachten.length > 1 && (\n                <div>\n                  <div style={{ ...LBL, marginBottom: 6, marginTop: 10 }}>\ud83d\udd27 Opdracht<\/div>\n                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>\n                    <FilterKnop actief={filterOpdracht === 'alle'} onClick={() => setFilterOpdracht('alle')}>Alle opdrachten<\/FilterKnop>\n                    {opdrachten.map(o => (\n                      <FilterKnop key={o} actief={filterOpdracht === o} onClick={() => setFilterOpdracht(o)}>\n                        {ICONS[o] || '\u2b50'} {o}\n                      <\/FilterKnop>\n                    ))}\n                  <\/div>\n                <\/div>\n              )}\n            <\/div>\n          )}\n\n          {\/* Shifts lijst *\/}\n          {laden ? (\n            <div style={{ textAlign: 'center', padding: '3rem', color: '#6b5e55' }}>Shifts laden...<\/div>\n          ) : shifts.length === 0 ? (\n            <div style={{ textAlign: 'center', padding: '3rem', color: '#6b5e55' }}>\n              <div style={{ fontSize: 36, marginBottom: 10 }}>\ud83d\udccb<\/div>\n              <div>Nog geen shifts aangemaakt. Kom later terug!<\/div>\n            <\/div>\n          ) : gefilterd.length === 0 ? (\n            <div style={{ textAlign: 'center', padding: '2rem', color: '#6b5e55', background: '#fff', borderRadius: 4 }}>\n              <div style={{ fontSize: 30, marginBottom: 8 }}>\ud83d\udd0d<\/div>\n              <div>Geen shifts gevonden met deze filters.<\/div>\n            <\/div>\n          ) : (\n            dagenGefilterd.map(dag => {\n              const dagShifts = gefilterd.filter(s => s.dag === dag);\n              if (!dagShifts.length) return null;\n              const vrijInDag = dagShifts.filter(s => s.ingeschreven.length < s.max).length;\n              return (\n                <div key={dag} style={{ marginBottom: '2rem' }}>\n                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', borderBottom: '2px solid #F8DE60', paddingBottom: '0.4rem', marginBottom: '1rem' }}>\n                    <span style={{ fontFamily: \"'Playfair Display', serif\", fontSize: '1.25rem', color: '#5E4F45', fontWeight: 700 }}>{dag}<\/span>\n                    <span style={{ fontSize: 12, color: '#6b5e55', fontWeight: 700 }}>{vrijInDag} shift{vrijInDag !== 1 ? 's' : ''} met vrije plekken<\/span>\n                  <\/div>\n                  {dagShifts.map(s => (\n                    <ShiftKaart key={s.id} s={s} naam={naam} gsm={gsm}\n                      maxShifts={maxShifts} aantalIngeschreven={aantalIngeschreven}\n                      onInschrijven={handleInschrijven} \/>\n                  ))}\n                <\/div>\n              );\n            })\n          )}\n\n          {shifts.length > 0 && (\n            <div style={{ background: '#fff', borderRadius: 4, padding: '1rem 1.4rem', borderTop: '3px solid #F8DE60', marginTop: 8 }}>\n              <div style={{ ...LBL, marginBottom: 8 }}>Legenda<\/div>\n              <div style={{ display: 'flex', gap: '1.5rem', flexWrap: 'wrap', fontSize: 13, color: '#3a3028' }}>\n                <span>\ud83d\udfe2 <strong>Vrij<\/strong> \u2014 plek beschikbaar<\/span>\n                <span>\ud83d\udfe1 <strong>Reserve<\/strong> \u2014 enkel reserveplek<\/span>\n                <span>\ud83d\udd34 <strong>Vol<\/strong> \u2014 volledig vol<\/span>\n              <\/div>\n            <\/div>\n          )}\n        <\/div>\n      ) : (\n        ingelogd\n          ? <BeheerPanel shifts={shifts} laden={laden} onVernieuwen={laadShifts} onLogout={handleLogout} \/>\n          : <LoginScherm onLogin={() => setIngelogd(true)} \/>\n      )}\n    <\/div>\n  );\n}\n\nconst root = ReactDOM.createRoot(document.getElementById('app'));\nroot.render(<App \/>);\n<\/script>\n\n<script>\n  document.getElementById('burger').addEventListener('click', () => {\n    document.getElementById('navLinks').classList.toggle('open');\n  });\n<\/script>\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Vrijwilligers \u2014 Watermolenfeesten 2026 Home Programma Sponsors Kandidates 2026 Affiches Info Vrijwilligers Wie zijn we Vrijwilligers 3 &mdash; 4 &mdash; 5 Juli 2026 \ud83d\ude4c Bedankt om je op te geven! De Watermolenfeesten zijn pas mogelijk dankzij de inzet van onze geweldige vrijwilligers. Of je nu achter de toog staat, de ingang bemant of helpt bij [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1306","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=\/wp\/v2\/pages\/1306","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1306"}],"version-history":[{"count":43,"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=\/wp\/v2\/pages\/1306\/revisions"}],"predecessor-version":[{"id":1641,"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=\/wp\/v2\/pages\/1306\/revisions\/1641"}],"wp:attachment":[{"href":"https:\/\/watermolenfeesten.be\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}