<!doctype html>

<html lang="de">

<head>

  <meta charset="utf-8" />

  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <title>30 Jahre Glanz – Julias Geburtstag</title>

  <meta name="description" content="RSVP für Julias 30. Geburtstag – 60s Glam, Breakfast at Tiffany’s Vibes. Zusage + Essenswünsche + Begleitpersonen." />


  <!-- Optional: Social Preview -->

  <meta property="og:title" content="30 Jahre Glanz – Julias Geburtstag" />

  <meta property="og:description" content="Bitte sag kurz Bescheid, ob du kommst – inkl. Begleitpersonen & Essenswunsch (Fleisch/Vegetarisch/Vegan)." />

  <!-- <meta property="og:image" content="https://30jahreglanz.fun/assets/einladung.jpg" /> -->


  <style>

    /* ====== Tiffany-Glam Styling (60s) ====== */

    :root{

      --tiffany: #7fd6da;

      --tiffany-dark: #38b8bf;

      --ink: #0e1216;

      --paper: #f7fbff;

      --gold: #c8a858;

      --line: rgba(14,18,22,.12);

      --shadow: 0 14px 40px rgba(14,18,22,.14);

      --radius: 22px;

      --radius-sm: 14px;

      --max: 1060px;

    }


    *{ box-sizing: border-box; }

    html,body{ height:100%; }

    body{

      margin:0;

      font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji","Segoe UI Emoji";

      color: var(--ink);

      background:

        radial-gradient(1200px 800px at 20% 10%, rgba(127,214,218,.40), transparent 55%),

        radial-gradient(900px 700px at 80% 20%, rgba(200,168,88,.18), transparent 55%),

        radial-gradient(1200px 900px at 50% 110%, rgba(127,214,218,.25), transparent 60%),

        linear-gradient(180deg, #ffffff, var(--paper));

      overflow-x:hidden;

    }


    /* Fancy subtle sparkle noise via CSS-only */

    .grain{

      position: fixed;

      inset: 0;

      pointer-events:none;

      opacity:.06;

      background-image:

        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");

      mix-blend-mode: multiply;

    }


    a{ color: inherit; }

    .wrap{ max-width: var(--max); margin: 0 auto; padding: 22px 18px 70px; }


    header{

      position: relative;

      border-radius: var(--radius);

      padding: 28px 24px 22px;

      overflow:hidden;

      background:

        linear-gradient(135deg, rgba(127,214,218,.38), rgba(255,255,255,.65) 55%, rgba(200,168,88,.14)),

        radial-gradient(700px 400px at 12% 0%, rgba(56,184,191,.28), transparent 55%);

      border: 1px solid rgba(14,18,22,.10);

      box-shadow: var(--shadow);

    }


    .topbar{

      display:flex;

      align-items:center;

      justify-content:space-between;

      gap:12px;

      flex-wrap:wrap;

      margin-bottom: 14px;

    }


    .badge{

      display:inline-flex;

      align-items:center;

      gap:10px;

      padding: 10px 14px;

      border-radius: 999px;

      background: rgba(255,255,255,.75);

      border: 1px solid rgba(14,18,22,.10);

      backdrop-filter: blur(8px);

      font-weight: 650;

      letter-spacing: .2px;

    }

    .dot{

      width:10px; height:10px;

      border-radius: 999px;

      background: var(--tiffany-dark);

      box-shadow: 0 0 0 3px rgba(127,214,218,.35);

    }


    .cta-row{

      display:flex;

      gap:12px;

      flex-wrap:wrap;

      justify-content:flex-end;

      align-items:center;

    }


    .btn{

      appearance:none;

      border:0;

      cursor:pointer;

      border-radius: 999px;

      padding: 12px 16px;

      font-weight: 700;

      letter-spacing: .2px;

      display:inline-flex;

      align-items:center;

      gap:10px;

      transition: transform .08s ease, box-shadow .18s ease, background .18s ease, border-color .18s ease;

      text-decoration:none;

      user-select:none;

      white-space: nowrap;

    }

    .btn:active{ transform: translateY(1px) scale(.99); }

    .btn-primary{

      background: linear-gradient(180deg, var(--tiffany), var(--tiffany-dark));

      color: #042a2d;

      box-shadow: 0 10px 22px rgba(56,184,191,.28);

    }

    .btn-ghost{

      background: rgba(255,255,255,.72);

      border: 1px solid rgba(14,18,22,.12);

    }

    .btn:hover{ box-shadow: 0 14px 30px rgba(14,18,22,.10); }


    .hero{

      display:grid;

      grid-template-columns: 1.2fr .8fr;

      gap: 18px;

      align-items:center;

      margin-top: 8px;

    }

    @media (max-width: 900px){

      .hero{ grid-template-columns: 1fr; }

    }


    .h-eyebrow{

      font-weight: 800;

      letter-spacing: .18em;

      text-transform: uppercase;

      color: rgba(14,18,22,.72);

      font-size: 12px;

    }


    h1{

      margin: 10px 0 10px;

      font-size: clamp(30px, 4.6vw, 56px);

      line-height: 1.03;

      letter-spacing: -0.02em;

    }


    .sub{

      margin: 0 0 16px;

      font-size: 16px;

      line-height: 1.55;

      color: rgba(14,18,22,.80);

      max-width: 62ch;

    }


    .quote{

      margin-top: 14px;

      padding: 14px 16px;

      border-radius: var(--radius-sm);

      border: 1px solid rgba(14,18,22,.10);

      background: rgba(255,255,255,.70);

    }

    .quote b{ letter-spacing: .02em; }

    .quote p{ margin: 0; }


    .poster{

      border-radius: var(--radius);

      border: 1px solid rgba(14,18,22,.10);

      background:

        radial-gradient(500px 260px at 50% 20%, rgba(200,168,88,.22), transparent 60%),

        linear-gradient(180deg, rgba(255,255,255,.70), rgba(127,214,218,.10));

      overflow:hidden;

      box-shadow: 0 18px 44px rgba(14,18,22,.14);

      min-height: 320px;

      position: relative;

    }

    .poster::after{

      content:"";

      position:absolute;

      inset:-60px;

      background:

        radial-gradient(circle at 20% 30%, rgba(255,255,255,.8), transparent 25%),

        radial-gradient(circle at 60% 20%, rgba(255,255,255,.65), transparent 20%),

        radial-gradient(circle at 75% 55%, rgba(255,255,255,.55), transparent 22%),

        radial-gradient(circle at 35% 75%, rgba(255,255,255,.45), transparent 22%);

      opacity:.45;

      transform: rotate(12deg);

      pointer-events:none;

    }

    .poster-inner{

      position:absolute;

      inset:0;

      display:flex;

      flex-direction:column;

      justify-content:space-between;

      padding: 18px;

    }

    .poster-top{

      display:flex;

      justify-content:space-between;

      gap:10px;

      align-items:flex-start;

    }

    .diamond{

      width: 36px; height: 36px;

      border-radius: 12px;

      background: rgba(255,255,255,.75);

      border: 1px solid rgba(14,18,22,.10);

      display:grid;

      place-items:center;

      font-size: 18px;

    }

    .poster-title{

      font-weight: 850;

      letter-spacing: .06em;

      text-transform: uppercase;

      font-size: 12px;

      color: rgba(14,18,22,.78);

    }

    .poster-big{

      font-size: 40px;

      font-weight: 900;

      letter-spacing: -0.02em;

      margin-top: 6px;

    }


    .img-slot{

      position:absolute;

      inset:0;

      z-index:-1;

      opacity:.9;

      background:

        linear-gradient(180deg, rgba(255,255,255,.65), rgba(255,255,255,.18)),

        radial-gradient(900px 420px at 50% -10%, rgba(127,214,218,.35), transparent 60%);

    }

    /* Wenn du ein echtes Bild nutzen willst:

       - lege es als assets/einladung.jpg ab

       - und ersetze unten background-image entsprechend. */

    /* .img-slot{ background-image: url("assets/einladung.jpg"); background-size: cover; background-position: center; } */


    main{ margin-top: 22px; display:grid; gap: 18px; }


    .grid{

      display:grid;

      grid-template-columns: 1fr 1fr;

      gap: 18px;

    }

    @media (max-width: 900px){

      .grid{ grid-template-columns: 1fr; }

    }


    .card{

      background: rgba(255,255,255,.78);

      border: 1px solid rgba(14,18,22,.10);

      border-radius: var(--radius);

      box-shadow: 0 12px 34px rgba(14,18,22,.08);

      padding: 18px;

      backdrop-filter: blur(10px);

    }


    .card h2{

      margin: 0 0 12px;

      font-size: 20px;

      letter-spacing: -0.01em;

    }


    .facts{

      display:grid;

      gap: 10px;

    }

    .fact{

      display:flex;

      gap: 10px;

      align-items:flex-start;

      padding: 12px 12px;

      border-radius: var(--radius-sm);

      border: 1px solid rgba(14,18,22,.09);

      background: rgba(255,255,255,.68);

    }

    .icon{

      width: 36px; height: 36px;

      border-radius: 12px;

      display:grid;

      place-items:center;

      background: rgba(127,214,218,.22);

      border: 1px solid rgba(56,184,191,.18);

      font-size: 18px;

      flex: 0 0 auto;

    }

    .fact b{ display:block; }

    .muted{ color: rgba(14,18,22,.70); }


    .pill{

      display:inline-flex;

      align-items:center;

      gap:8px;

      padding: 8px 12px;

      border-radius: 999px;

      background: rgba(127,214,218,.18);

      border: 1px solid rgba(56,184,191,.22);

      font-weight: 750;

      margin-top: 10px;

    }


    /* ===== Form ===== */

    form{ display:grid; gap: 14px; }


    .row{

      display:grid;

      grid-template-columns: 1fr 1fr;

      gap: 12px;

    }

    @media (max-width: 720px){

      .row{ grid-template-columns: 1fr; }

    }


    label{

      display:grid;

      gap: 7px;

      font-weight: 700;

      font-size: 13px;

      letter-spacing: .02em;

    }

    input, select, textarea{

      width:100%;

      border-radius: 14px;

      border: 1px solid rgba(14,18,22,.14);

      background: rgba(255,255,255,.78);

      padding: 12px 12px;

      font: inherit;

      outline: none;

      transition: box-shadow .18s ease, border-color .18s ease;

    }

    textarea{ min-height: 96px; resize: vertical; }

    input:focus, select:focus, textarea:focus{

      border-color: rgba(56,184,191,.65);

      box-shadow: 0 0 0 4px rgba(127,214,218,.25);

    }


    .segmented{

      display:flex;

      gap:10px;

      flex-wrap:wrap;

      padding: 10px;

      border-radius: 18px;

      background: rgba(255,255,255,.65);

      border: 1px solid rgba(14,18,22,.10);

    }

    .segmented input{ display:none; }

    .segmented label{

      margin:0;

      cursor:pointer;

      user-select:none;

      display:inline-flex;

      align-items:center;

      gap:8px;

      padding: 10px 12px;

      border-radius: 999px;

      border: 1px solid rgba(14,18,22,.12);

      background: rgba(255,255,255,.70);

      font-weight: 850;

      font-size: 13px;

      transition: transform .08s ease, background .18s ease, border-color .18s ease;

    }

    .segmented label:active{ transform: translateY(1px); }

    .segmented input:checked + label{

      background: linear-gradient(180deg, rgba(127,214,218,.45), rgba(56,184,191,.25));

      border-color: rgba(56,184,191,.55);

    }


    .guests{

      display:grid;

      gap: 12px;

    }

    .guest{

      border-radius: var(--radius);

      border: 1px solid rgba(14,18,22,.10);

      background: rgba(255,255,255,.65);

      padding: 12px;

      display:grid;

      gap: 10px;

    }

    .guest-head{

      display:flex;

      justify-content:space-between;

      align-items:center;

      gap: 12px;

    }

    .guest-title{

      font-weight: 900;

      letter-spacing: -0.01em;

    }

    .btn-small{

      padding: 10px 12px;

      border-radius: 999px;

      font-weight: 850;

      border: 1px solid rgba(14,18,22,.12);

      background: rgba(255,255,255,.75);

    }


    .divider{

      height:1px;

      background: rgba(14,18,22,.10);

      margin: 8px 0;

    }


    .notice{

      padding: 12px 14px;

      border-radius: var(--radius);

      background: rgba(127,214,218,.18);

      border: 1px solid rgba(56,184,191,.26);

      color: rgba(14,18,22,.85);

    }


    .fine{

      font-size: 12px;

      color: rgba(14,18,22,.65);

      line-height: 1.45;

    }


    .footer{

      text-align:center;

      margin-top: 20px;

      color: rgba(14,18,22,.62);

      font-size: 12px;

    }


    /* ===== Modal ===== */

    dialog{

      width: min(680px, calc(100% - 28px));

      border: 1px solid rgba(14,18,22,.14);

      border-radius: 22px;

      padding: 0;

      box-shadow: 0 24px 70px rgba(14,18,22,.30);

      background: rgba(255,255,255,.94);

      overflow:hidden;

    }

    dialog::backdrop{

      background: rgba(14,18,22,.45);

      backdrop-filter: blur(6px);

    }

    .modal{

      padding: 18px;

    }

    .modal h3{ margin: 0 0 10px; font-size: 18px; }

    .summary{

      border-radius: 18px;

      border: 1px solid rgba(14,18,22,.12);

      background: rgba(255,255,255,.70);

      padding: 12px;

      line-height: 1.55;

      white-space: pre-wrap;

      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;

      font-size: 12px;

    }

    .modal-actions{

      display:flex;

      gap: 10px;

      justify-content:flex-end;

      flex-wrap:wrap;

      padding: 14px 18px 18px;

      border-top: 1px solid rgba(14,18,22,.10);

      background: rgba(127,214,218,.10);

    }


    /* ===== Sparkle animation on success ===== */

    .sparkles{

      position: fixed;

      inset: 0;

      pointer-events:none;

      overflow:hidden;

      display:none;

      z-index: 9999;

    }

    .sparkles.show{ display:block; }

    .sparkle{

      position:absolute;

      width: 10px; height: 10px;

      border-radius: 999px;

      background: radial-gradient(circle at 30% 30%, #fff, rgba(255,255,255,.1) 55%, transparent 70%),

                  radial-gradient(circle at 70% 70%, rgba(200,168,88,.9), transparent 60%);

      opacity: .9;

      animation: floatUp 1.1s ease-out forwards;

    }

    @keyframes floatUp{

      from{ transform: translateY(0) scale(.9); opacity:.95; }

      to{ transform: translateY(-180px) scale(1.25); opacity:0; }

    }

  </style>

</head>

<body>

  <div class="grain" aria-hidden="true"></div>

  <div class="sparkles" id="sparkles" aria-hidden="true"></div>


  <div class="wrap">

    <header>

      <div class="topbar">

        <div class="badge"><span class="dot"></span> 30 Jahre Glanz · 60s Glam</div>

        <div class="cta-row">

          <a class="btn btn-ghost" href="#details">Infos</a>

          <a class="btn btn-primary" href="#rsvp">Jetzt zusagen 💎</a>

        </div>

      </div>


      <div class="hero">

        <div>

          <div class="h-eyebrow">Welcome, Darling!</div>

          <h1>Julia wird 30 –<br/>und das feiern wir mit Glanz.</h1>

          <p class="sub">

            Im Stil von „Breakfast at Tiffany’s“: stilvolle Sounds, glamouröse Gespräche und funkelnde Momente.

            Werft euch gern in eure schönsten <b>60er-Jahre Outfits</b> und stoßt mit Julia auf drei Jahrzehnte Leben,

            Liebe und Stil an. 🥂✨

          </p>


          <div class="quote">

            <p><b>Wunschzettel:</b> Musik machen! Dein Geschenk fließt in neues Equipment oder Instrumente – damit aus Moon-River-Momenten neue Musik entsteht.</p>

          </div>


          <div class="pill">Bitte Rückmeldung bis <b>01.04.2026</b> ✍️</div>

        </div>


        <div class="poster" role="img" aria-label="Glamour Poster Bereich">

          <div class="img-slot" aria-hidden="true"></div>

          <div class="poster-inner">

            <div class="poster-top">

              <div>

                <div class="poster-title">Save the Date</div>

                <div class="poster-big">09.05.2026</div>

                <div class="muted" style="font-weight:750;">ab 18:00 Uhr</div>

              </div>

              <div class="diamond">💎</div>

            </div>

            <div class="muted" style="font-weight:750;">

              „Holly Golightly lässt grüßen!“

            </div>

          </div>

        </div>

      </div>

    </header>


    <main>

      <section id="details" class="grid">

        <div class="card">

          <h2>Details</h2>

          <div class="facts">

            <div class="fact">

              <div class="icon">📅</div>

              <div><b>Datum</b><div class="muted">09.05.2026</div></div>

            </div>

            <div class="fact">

              <div class="icon">🕕</div>

              <div><b>Uhrzeit</b><div class="muted">18:00 Uhr</div></div>

            </div>

            <div class="fact">

              <div class="icon">🪩</div>

              <div><b>Dresscode</b><div class="muted">60er Jahre</div></div>

            </div>

            <div class="fact">

              <div class="icon">📍</div>

              <div>

                <b>Location</b>

                <div class="muted">FC Laufach · Am Eisenhammer 18 · 63846 Laufach</div>

                <div class="fine" style="margin-top:6px;">

                  Tipp: Du kannst dir die Adresse direkt in Maps öffnen (Button unten).

                </div>

              </div>

            </div>

          </div>


          <div class="divider"></div>


          <div class="cta-row" style="justify-content:flex-start;">

            <a class="btn btn-ghost" target="_blank" rel="noopener"

               href="https://www.google.com/maps/search/?api=1&query=FC+Laufach%2C+Am+Eisenhammer+18%2C+63846+Laufach">

              Route öffnen 🗺️

            </a>

            <a class="btn btn-primary" href="#rsvp">Zur Rückmeldung →</a>

          </div>

        </div>


        <div class="card">

          <h2>Kurzer Hinweis</h2>

          <div class="notice">

            Kinder sind herzlich willkommen. 💛<br/>

            Für die Planung: Bitte gib pro Person den Essenswunsch an (Fleisch / Vegetarisch / Vegan) und ggf. Allergien.

          </div>

          <p class="fine" style="margin-top:12px;">

            <b>Datenschutz:</b> Diese Seite ist für die Partyplanung gedacht. Deine Angaben werden nur dafür genutzt.

            (Aktuell speichert dieser Prototyp im Browser; später können wir das zentral speichern.)

          </p>


          <div class="divider"></div>


          <div class="facts">

            <div class="fact">

              <div class="icon">🎁</div>

              <div><b>Geschenk-Idee</b><div class="muted">Musik machen – Equipment/Instrumente</div></div>

            </div>

            <div class="fact">

              <div class="icon">✨</div>

              <div><b>Vibe</b><div class="muted">Glamour · 60s · Tiffany-Vibes</div></div>

            </div>

          </div>

        </div>

      </section>


      <section id="rsvp" class="card">

        <h2>Rückmeldung</h2>


        <form id="rsvpForm" novalidate>

          <div class="row">

            <label>

              Dein Name (Vor- & Nachname) *

              <input type="text" name="hostName" id="hostName" placeholder="z. B. Max Mustermann" required />

            </label>


            <label>

              Kontakt (WhatsApp oder E-Mail) <span class="muted" style="font-weight:650;">(optional)</span>

              <input type="text" name="contact" id="contact" placeholder="z. B. 0176… oder name@mail.de" />

            </label>

          </div>


          <div>

            <div class="fine" style="margin-bottom:8px;"><b>Kommst du?</b> *</div>

            <div class="segmented" role="radiogroup" aria-label="Zusage">

              <input type="radio" id="attendYes" name="attendance" value="yes" required />

              <label for="attendYes">✅ Ja, ich komme</label>


              <input type="radio" id="attendNo" name="attendance" value="no" />

              <label for="attendNo">❌ Leider nein</label>

            </div>

          </div>


          <div id="ifNo" style="display:none;">

            <label>

              Nachricht an Julia <span class="muted" style="font-weight:650;">(optional)</span>

              <textarea name="messageNo" id="messageNo" placeholder="z. B. Ich denke an euch und feiere aus der Ferne…"></textarea>

            </label>

          </div>


          <div id="ifYes" style="display:none;">

            <div class="divider"></div>


            <div class="row">

              <label>

                Kinder dabei? (Anzahl)

                <input type="number" name="kidsCount" id="kidsCount" min="0" value="0" />

              </label>


              <label>

                Trinkst du Alkohol?

                <select name="alcohol" id="alcohol">

                  <option value="egal">Egal / weiß ich noch nicht</option>

                  <option value="yes">Ja</option>

                  <option value="no">Nein</option>

                </select>

              </label>

            </div>


            <div>

              <div style="display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;">

                <div>

                  <div style="font-weight:900;">Personen & Essenswünsche *</div>

                  <div class="fine">Füge alle Personen hinzu, die du mitbringst – inkl. Essenswunsch & Allergien.</div>

                </div>

                <button type="button" class="btn btn-ghost" id="addGuestBtn">+ Begleitperson hinzufügen</button>

              </div>


              <div class="guests" id="guests"></div>

            </div>


            <label>

              Nachricht an Julia <span class="muted" style="font-weight:650;">(optional)</span>

              <textarea name="messageYes" id="messageYes" placeholder="z. B. Wir kommen etwas später / bringen Kuchen mit / …"></textarea>

            </label>

          </div>


          <label style="display:flex; gap:10px; align-items:flex-start; font-weight:750;">

            <input type="checkbox" id="consent" required style="width:auto; margin-top:2px;" />

            <span>

              Ich bin einverstanden, dass meine Angaben zur Eventplanung gespeichert werden. *

              <div class="fine">Nur für die Organisation dieser Feier.</div>

            </span>

          </label>


          <div style="display:flex; gap:12px; flex-wrap:wrap; align-items:center;">

            <button class="btn btn-primary" type="submit">Glanz-Antwort abschicken 💎</button>

            <button class="btn btn-ghost" type="button" id="viewLocalBtn">Gespeicherte Rückmeldungen (dieser Browser)</button>

          </div>


          <div class="fine">

            * Pflichtfelder. Rückmeldefrist: <b>01.04.2026</b>.

          </div>

        </form>

      </section>


      <div class="footer">

        Made with ✨ for Julias 30. · 30jahreglanz.fun

      </div>

    </main>

  </div>


  <dialog id="modal">

    <div class="modal">

      <h3>Deine Rückmeldung</h3>

      <div class="summary" id="summaryBox"></div>

      <p class="fine" style="margin:10px 0 0;">

        (Prototyp) Diese Rückmeldung wurde lokal gespeichert. Später können wir das zentral an Julia schicken.

      </p>

    </div>

    <div class="modal-actions">

      <button class="btn btn-ghost" id="closeModalBtn" type="button">Schließen</button>

      <button class="btn btn-primary" id="copyBtn" type="button">Zusammenfassung kopieren</button>

    </div>

  </dialog>


  <dialog id="localModal">

    <div class="modal">

      <h3>Gespeicherte Rückmeldungen (dieser Browser)</h3>

      <div class="summary" id="localBox"></div>

      <p class="fine" style="margin:10px 0 0;">

        Hinweis: Das ist nur lokal auf diesem Gerät/Browser sichtbar.

      </p>

    </div>

    <div class="modal-actions">

      <button class="btn btn-ghost" id="closeLocalBtn" type="button">Schließen</button>

      <button class="btn btn-primary" id="clearLocalBtn" type="button">LocalStorage leeren</button>

    </div>

  </dialog>


  <script>

    // ===== Helpers =====

    const $ = (sel, el=document) => el.querySelector(sel);

    const $$ = (sel, el=document) => [...el.querySelectorAll(sel)];


    const form = $("#rsvpForm");

    const guestsEl = $("#guests");

    const ifYes = $("#ifYes");

    const ifNo = $("#ifNo");


    const modal = $("#modal");

    const summaryBox = $("#summaryBox");


    const localModal = $("#localModal");

    const localBox = $("#localBox");


    const sparkles = $("#sparkles");


    function uid(){

      return Math.random().toString(16).slice(2) + "-" + Date.now().toString(16);

    }


    function escapeHtml(str){

      return String(str ?? "")

        .replaceAll("&","&amp;")

        .replaceAll("<","&lt;")

        .replaceAll(">","&gt;")

        .replaceAll('"',"&quot;")

        .replaceAll("'","&#039;");

    }


    function showSparkles(){

      sparkles.innerHTML = "";

      sparkles.classList.add("show");

      const n = 18;

      for(let i=0;i<n;i++){

        const s = document.createElement("div");

        s.className = "sparkle";

        s.style.left = (Math.random()*100) + "vw";

        s.style.top = (70 + Math.random()*20) + "vh";

        s.style.animationDelay = (Math.random()*0.12) + "s";

        s.style.transform = `translateY(0) scale(${0.8 + Math.random()*0.8})`;

        sparkles.appendChild(s);

      }

      setTimeout(()=> sparkles.classList.remove("show"), 1200);

    }


    // ===== Attendance toggle =====

    function updateAttendanceUI(){

      const attendance = (new FormData(form)).get("attendance");

      if(attendance === "yes"){

        ifYes.style.display = "block";

        ifNo.style.display = "none";

      } else if(attendance === "no"){

        ifYes.style.display = "none";

        ifNo.style.display = "block";

      } else {

        ifYes.style.display = "none";

        ifNo.style.display = "none";

      }

    }

    $$("input[name='attendance']").forEach(r => r.addEventListener("change", updateAttendanceUI));


    // ===== Guests repeater =====

    function guestTemplate({id, name="", meal="vegetarisch", allergies=""}, index, isSelf=false){

      const title = isSelf ? "Person 1 (du)" : `Begleitperson ${index+1}`;

      return `

        <div class="guest" data-guest-id="${id}">

          <div class="guest-head">

            <div class="guest-title">${escapeHtml(title)}</div>

            ${isSelf ? "" : `<button type="button" class="btn-small" data-action="remove">Entfernen</button>`}

          </div>

          <div class="row">

            <label>

              Name *

              <input type="text" data-field="name" value="${escapeHtml(name)}" placeholder="Vor- & Nachname" required />

            </label>

            <label>

              Essen *

              <select data-field="meal" required>

                <option value="fleisch" ${meal==="fleisch"?"selected":""}>Fleisch</option>

                <option value="vegetarisch" ${meal==="vegetarisch"?"selected":""}>Vegetarisch</option>

                <option value="vegan" ${meal==="vegan"?"selected":""}>Vegan</option>

              </select>

            </label>

          </div>

          <label>

            Allergien/Unverträglichkeiten <span class="muted" style="font-weight:650;">(optional)</span>

            <input type="text" data-field="allergies" value="${escapeHtml(allergies)}" placeholder="z. B. Nüsse, Laktose, Gluten …" />

          </label>

        </div>

      `;

    }


    function getGuestsFromUI(){

      return $$(".guest", guestsEl).map((g) => {

        const id = g.getAttribute("data-guest-id");

        const name = $("input[data-field='name']", g)?.value?.trim() || "";

        const meal = $("select[data-field='meal']", g)?.value || "";

        const allergies = $("input[data-field='allergies']", g)?.value?.trim() || "";

        return { id, name, meal, allergies };

      });

    }


    function setGuestsToUI(guests){

      guestsEl.innerHTML = guests.map((guest, idx) => {

        const isSelf = idx === 0;

        return guestTemplate(guest, idx, isSelf);

      }).join("");


      // Bind remove handlers

      $$(".guest [data-action='remove']", guestsEl).forEach(btn => {

        btn.addEventListener("click", () => {

          const box = btn.closest(".guest");

          if(box) box.remove();

          // re-render titles (so "Begleitperson 2" etc stimmt)

          const current = getGuestsFromUI();

          setGuestsToUI(current);

        });

      });

    }


    function ensureSelfGuest(){

      const hostName = $("#hostName").value.trim();

      const current = getGuestsFromUI();

      if(current.length === 0){

        setGuestsToUI([{ id: uid(), name: hostName, meal:"vegetarisch", allergies:"" }]);

      } else {

        // keep guest[0] synced with host name if empty or identical

        if(!current[0].name || current[0].name === "" || current[0].name === $("#hostName").dataset.lastValue){

          current[0].name = hostName;

        }

        setGuestsToUI(current);

      }

      $("#hostName").dataset.lastValue = hostName;

    }


    $("#hostName").addEventListener("input", () => {

      if($("#attendYes").checked) ensureSelfGuest();

    });


    $("#addGuestBtn").addEventListener("click", () => {

      const current = getGuestsFromUI();

      current.push({ id: uid(), name:"", meal:"vegetarisch", allergies:"" });

      setGuestsToUI(current);

    });


    // initialize with one self guest (hidden until yes is selected)

    setGuestsToUI([{ id: uid(), name:"", meal:"vegetarisch", allergies:"" }]);


    // ===== Storage =====

    const STORAGE_KEY = "rsvp_30jahreglanz_v1";


    function readAll(){

      try{

        return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");

      } catch {

        return [];

      }

    }

    function writeAll(items){

      localStorage.setItem(STORAGE_KEY, JSON.stringify(items, null, 2));

    }


    function buildPayload(){

      const fd = new FormData(form);

      const attendance = fd.get("attendance");

      const hostName = (fd.get("hostName") || "").toString().trim();

      const contact = (fd.get("contact") || "").toString().trim();

      const consent = $("#consent").checked;


      const base = {

        id: uid(),

        createdAt: new Date().toISOString(),

        hostName,

        contact,

        attendance,

        consent

      };


      if(attendance === "no"){

        return {

          ...base,

          message: (fd.get("messageNo") || "").toString().trim()

        };

      }


      const kidsCount = Number(fd.get("kidsCount") || 0);

      const alcohol = (fd.get("alcohol") || "egal").toString();

      const guests = getGuestsFromUI().map(g => ({

        name: g.name.trim(),

        meal: g.meal,

        allergies: g.allergies.trim()

      }));


      const message = (fd.get("messageYes") || "").toString().trim();


      return {

        ...base,

        kidsCount: isFinite(kidsCount) ? Math.max(0, kidsCount) : 0,

        alcohol,

        guests,

        message

      };

    }


    function validatePayload(payload){

      const errors = [];

      if(!payload.hostName) errors.push("Bitte deinen Namen angeben.");

      if(payload.attendance !== "yes" && payload.attendance !== "no") errors.push("Bitte auswählen, ob du kommst.");


      if(payload.attendance === "yes"){

        if(!Array.isArray(payload.guests) || payload.guests.length < 1){

          errors.push("Bitte mindestens eine Person angeben (du).");

        } else {

          payload.guests.forEach((g, i) => {

            if(!g.name) errors.push(`Bitte Name für Person ${i+1} angeben.`);

            if(!g.meal) errors.push(`Bitte Essenswunsch für Person ${i+1} wählen.`);

          });

        }

      }

      if(!payload.consent) errors.push("Bitte Datenschutz/Einverständnis bestätigen.");

      return errors;

    }


    function payloadToHumanSummary(payload){

      if(payload.attendance === "no"){

        return [

          "RÜCKMELDUNG",

          "—".repeat(36),

          `Name: ${payload.hostName}`,

          `Kontakt: ${payload.contact || "—"}`,

          `Status: ABSAGE`,

          payload.message ? `Nachricht: ${payload.message}` : "Nachricht: —",

          "",

          "Danke fürs Bescheid sagen. 💛"

        ].join("\n");

      }


      const counts = payload.guests.reduce((acc,g)=>{

        acc[g.meal] = (acc[g.meal]||0)+1; return acc;

      }, {});

      const mealLine = `Essen: Fleisch ${counts.fleisch||0} · Vegetarisch ${counts.vegetarisch||0} · Vegan ${counts.vegan||0}`;


      const guestLines = payload.guests.map((g,i)=> {

        const a = g.allergies ? ` (Allergien: ${g.allergies})` : "";

        return `  ${i+1}. ${g.name} – ${g.meal}${a}`;

      });


      return [

        "RÜCKMELDUNG",

        "—".repeat(36),

        `Name: ${payload.hostName}`,

        `Kontakt: ${payload.contact || "—"}`,

        `Status: ZUSAGE`,

        `Anzahl Personen: ${payload.guests.length} (+ Kinder: ${payload.kidsCount || 0})`,

        mealLine,

        `Alkohol: ${payload.alcohol || "egal"}`,

        "",

        "Personen:",

        ...guestLines,

        "",

        payload.message ? `Nachricht: ${payload.message}` : "Nachricht: —",

        "",

        "Danke, Darling! ✨🥂"

      ].join("\n");

    }


    // ===== Submit =====

    form.addEventListener("submit", async (e) => {

      e.preventDefault();


      updateAttendanceUI();

      if($("#attendYes").checked) ensureSelfGuest();


      const payload = buildPayload();

      const errors = validatePayload(payload);


      if(errors.length){

        alert("Bitte noch kurz prüfen:\n\n• " + errors.join("\n• "));

        return;

      }


      // Store locally (prototype)

      const all = readAll();

      all.push(payload);

      writeAll(all);


      // OPTIONAL: Later send to server endpoint

      // await fetch("/api/rsvp", { method:"POST", headers:{ "Content-Type":"application/json" }, body: JSON.stringify(payload) });


      const summary = payloadToHumanSummary(payload);

      summaryBox.textContent = summary;


      showSparkles();

      modal.showModal();


      // Reset form (but keep a bit of UX friendliness)

      form.reset();

      ifYes.style.display = "none";

      ifNo.style.display = "none";

      setGuestsToUI([{ id: uid(), name:"", meal:"vegetarisch", allergies:"" }]);

      $("#kidsCount").value = 0;

      $("#alcohol").value = "egal";

    });


    // ===== Modals =====

    $("#closeModalBtn").addEventListener("click", () => modal.close());

    $("#copyBtn").addEventListener("click", async () => {

      try{

        await navigator.clipboard.writeText(summaryBox.textContent || "");

        $("#copyBtn").textContent = "Kopiert ✓";

        setTimeout(()=> $("#copyBtn").textContent = "Zusammenfassung kopieren", 1200);

      } catch {

        alert("Kopieren hat nicht geklappt – bitte manuell markieren & kopieren.");

      }

    });


    $("#viewLocalBtn").addEventListener("click", () => {

      const all = readAll();

      if(!all.length){

        localBox.textContent = "Keine Rückmeldungen gespeichert.";

      } else {

        const lines = all.map((p, idx) => {

          const when = new Date(p.createdAt).toLocaleString("de-DE");

          if(p.attendance === "no"){

            return `#${idx+1} · ${when}\nABSAGE · ${p.hostName}\nKontakt: ${p.contact || "—"}\nNachricht: ${p.message || "—"}\n`;

          }

          const counts = (p.guests||[]).reduce((acc,g)=>{ acc[g.meal]=(acc[g.meal]||0)+1; return acc; },{});

          return `#${idx+1} · ${when}\nZUSAGE · ${p.hostName}\nPersonen: ${(p.guests||[]).length} (+ Kinder ${p.kidsCount||0})\nEssen: Fleisch ${counts.fleisch||0} · Vegetarisch ${counts.vegetarisch||0} · Vegan ${counts.vegan||0}\nKontakt: ${p.contact || "—"}\n`;

        }).join("\n" + "—".repeat(36) + "\n\n");

        localBox.textContent = lines.trim();

      }

      localModal.showModal();

    });


    $("#closeLocalBtn").addEventListener("click", () => localModal.close());

    $("#clearLocalBtn").addEventListener("click", () => {

      if(confirm("Wirklich alle lokal gespeicherten Rückmeldungen löschen?")){

        localStorage.removeItem(STORAGE_KEY);

        localBox.textContent = "Gelöscht.";

      }

    });


    // Keep UI consistent on load

    updateAttendanceUI();

  </script>

</body>

</html>