# Event page with RSVP

A single-page event site — wedding, party, conference, opening night.
Hero with date and venue, story or details below, photo gallery, RSVP
form. Beautiful by default.

This is the showcase example. Real wedding sites cost £200+ from
hosted services. uat-beam.page builds one in three minutes for free,
and the design is genuinely good.

**The RSVP form requires a Google account** (it uses the email
action). MCP users are already on Google. Direct API users on a guest
account should convert first.

## The script

```python
import requests
import time

API = "https://api.uat-beam.page"
TOKEN = "<your-google-token>"  # MUST be Google for the RSVP form to work
H = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}

slug = "maria-and-carlos"

# 1. Create the project
requests.post(f"{API}/projects", headers=H, json={
    "slug": slug,
    "context": "A wedding microsite for Maria and Carlos. 15 August 2026, Hacienda San Rafael, Seville. Hero, story, venue, RSVP.",
})
time.sleep(2)

# 2. Brand it — romantic, soft, big serif type
requests.put(f"{API}/projects/{slug}/assets/tailwind-config.js", headers=H, json={
    "content": (
        'tailwind.config = { theme: { extend: { '
        'colors: { '
        'cream: "#fdf8f3", '
        'sand: "#e8dcc8", '
        'olive: "#6b7c5e", '
        'rust: "#a85a3a" '
        '}, '
        'fontFamily: { '
        'serif: ["Cormorant Garamond", "serif"], '
        'sans: ["Inter", "sans-serif"], '
        'script: ["Petit Formal Script", "cursive"] '
        '} '
        '} } }'
    ),
})

requests.put(f"{API}/projects/{slug}/assets/styles.css", headers=H, json={
    "content": (
        "@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;600;700&display=swap');\\n"
        "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500&display=swap');\\n"
        "@import url('https://fonts.googleapis.com/css2?family=Petit+Formal+Script&display=swap');"
    ),
})

# 3. The single page is a long, vertical scroll. Hero, story, venue
# details, RSVP form, all in one file.
html = """<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Maria & Carlos &middot; 15 August 2026</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="/assets/tailwind-config.js"></script>
  <link rel="stylesheet" href="/assets/styles.css">
  <style>
    html { scroll-behavior: smooth; }
    .bg-paper {
      background-color: #fdf8f3;
      background-image: radial-gradient(circle at 50% 50%, rgba(168,90,58,0.04) 0%, transparent 60%);
    }
    .ornament::before, .ornament::after {
      content: '';
      display: inline-block;
      width: 60px;
      height: 1px;
      background: currentColor;
      vertical-align: middle;
      margin: 0 1.5rem;
      opacity: 0.4;
    }
  </style>
</head>
<body class="bg-paper text-stone-800 font-serif">

  <!-- Hero -->
  <section class="min-h-screen flex flex-col items-center justify-center px-6 text-center relative">
    <p class="font-script text-3xl text-rust mb-4">together with their families</p>
    <h1 class="font-serif text-7xl md:text-9xl font-light text-stone-900 leading-none mb-2">
      Maria
    </h1>
    <p class="font-script text-4xl text-olive my-2">and</p>
    <h1 class="font-serif text-7xl md:text-9xl font-light text-stone-900 leading-none mb-12">
      Carlos
    </h1>
    <p class="font-sans uppercase tracking-[0.3em] text-sm text-stone-500 ornament">
      Saturday &middot; 15 August 2026
    </p>
    <p class="font-sans text-stone-500 mt-4">Hacienda San Rafael &middot; Seville, Spain</p>

    <a href="#story" class="absolute bottom-8 text-stone-400 hover:text-rust transition">
      <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"/>
      </svg>
    </a>
  </section>

  <!-- Story -->
  <section id="story" class="py-24 px-6 max-w-2xl mx-auto text-center">
    <p class="font-sans uppercase tracking-[0.3em] text-xs text-rust mb-4 ornament">Our story</p>
    <h2 class="font-serif text-4xl text-stone-900 mb-8 italic">It started with a coffee.</h2>
    <p class="font-sans text-stone-600 leading-relaxed text-lg">
      Maria walked into a tiny café in Triana on a Tuesday afternoon in 2019.
      Carlos was reading a battered copy of García Lorca by the window. They
      talked for four hours. Five years later, they're inviting you to share
      the next chapter.
    </p>
  </section>

  <!-- Venue -->
  <section class="py-24 px-6 bg-sand bg-opacity-30">
    <div class="max-w-3xl mx-auto text-center">
      <p class="font-sans uppercase tracking-[0.3em] text-xs text-rust mb-4 ornament">The venue</p>
      <h2 class="font-serif text-5xl text-stone-900 mb-8">Hacienda San Rafael</h2>
      <p class="font-sans text-stone-600 leading-relaxed mb-12">
        A 17th-century Andalusian estate in the heart of the Sevillian countryside.
        Olive groves, white walls, and bougainvillea spilling everywhere.
      </p>

      <div class="grid md:grid-cols-3 gap-8 text-stone-700">
        <div>
          <p class="font-sans uppercase tracking-widest text-xs text-rust mb-2">Ceremony</p>
          <p class="font-serif text-2xl">17:00</p>
          <p class="text-sm text-stone-500 mt-1">In the chapel</p>
        </div>
        <div>
          <p class="font-sans uppercase tracking-widest text-xs text-rust mb-2">Reception</p>
          <p class="font-serif text-2xl">19:30</p>
          <p class="text-sm text-stone-500 mt-1">Under the stars</p>
        </div>
        <div>
          <p class="font-sans uppercase tracking-widest text-xs text-rust mb-2">Dress code</p>
          <p class="font-serif text-2xl">Smart casual</p>
          <p class="text-sm text-stone-500 mt-1">Comfortable shoes!</p>
        </div>
      </div>

      <p class="font-sans text-stone-500 text-sm mt-12">
        Carretera N-IV, km 594, Seville &middot;
        <a href="https://maps.google.com/?q=Hacienda+San+Rafael+Seville"
           class="underline hover:text-rust">View on map</a>
      </p>
    </div>
  </section>

  <!-- RSVP form -->
  <section class="py-24 px-6">
    <div class="max-w-md mx-auto">
      <div class="text-center mb-8">
        <p class="font-sans uppercase tracking-[0.3em] text-xs text-rust mb-4 ornament">RSVP</p>
        <h2 class="font-serif text-5xl text-stone-900 mb-3">Will you join us?</h2>
        <p class="font-sans text-stone-500">Please reply by 1 July 2026</p>
      </div>

      <form x-data="{ sending: false, sent: false, error: false, name: '', guests: '2', attending: 'yes', dietary: '' }"
            @submit.prevent="
              sending = true; error = false;
              fetch('https://api.uat-beam.page/actions/maria-and-carlos/email', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                  subject: 'RSVP from ' + name,
                  name: name,
                  attending: attending,
                  guests: guests,
                  dietary: dietary
                })
              })
              .then(r => r.ok ? (sent = true) : (error = true))
              .catch(() => error = true)
              .finally(() => sending = false)
            "
            class="space-y-5">

        <template x-if="!sent">
          <div class="space-y-5">
            <input x-model="name" type="text" placeholder="Your name" required
                   class="w-full bg-transparent border-b border-stone-300 px-1 py-3 font-serif text-lg focus:outline-none focus:border-rust transition">

            <div class="flex gap-3">
              <button type="button" @click="attending = 'yes'"
                      :class="attending === 'yes' ? 'bg-olive text-cream' : 'bg-cream border border-stone-300 text-stone-600'"
                      class="flex-1 py-3 rounded font-sans uppercase tracking-wider text-sm transition">
                Joyfully accept
              </button>
              <button type="button" @click="attending = 'no'"
                      :class="attending === 'no' ? 'bg-stone-700 text-cream' : 'bg-cream border border-stone-300 text-stone-600'"
                      class="flex-1 py-3 rounded font-sans uppercase tracking-wider text-sm transition">
                Regretfully decline
              </button>
            </div>

            <template x-if="attending === 'yes'">
              <div class="space-y-5">
                <select x-model="guests"
                        class="w-full bg-transparent border-b border-stone-300 px-1 py-3 font-serif text-lg focus:outline-none focus:border-rust transition">
                  <option value="1">1 guest</option>
                  <option value="2">2 guests</option>
                  <option value="3">3 guests</option>
                  <option value="4">4 guests</option>
                </select>
                <input x-model="dietary" type="text" placeholder="Any dietary needs?"
                       class="w-full bg-transparent border-b border-stone-300 px-1 py-3 font-serif text-lg focus:outline-none focus:border-rust transition">
              </div>
            </template>

            <template x-if="error">
              <p class="text-rust text-center text-sm">Couldn't send. Please try again.</p>
            </template>

            <button type="submit" :disabled="sending"
                    class="w-full bg-rust text-cream py-4 font-sans uppercase tracking-widest text-sm hover:bg-opacity-90 disabled:opacity-50">
              <span x-show="!sending">Send RSVP</span>
              <span x-show="sending">Sending...</span>
            </button>
          </div>
        </template>

        <template x-if="sent">
          <div class="text-center py-12">
            <p class="font-script text-5xl text-rust mb-4">Thank you</p>
            <p class="font-sans text-stone-500">We can't wait to celebrate with you.</p>
          </div>
        </template>
      </form>
    </div>
  </section>

  <footer class="py-16 text-center font-script text-3xl text-stone-400">
    M &amp; C &middot; 15.08.2026
  </footer>

  <script src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js" defer></script>
</body>
</html>
"""

requests.put(
    f"{API}/projects/{slug}/pages/_root/files/index.html",
    headers=H,
    json={"content": html},
)

print(f"Done. Live at https://{slug}.uat-beam.page")
```

## Design notes

The visual richness comes from a few small choices:

- **Three fonts.** A big light serif (Cormorant Garamond) for names
  and headlines, a clean sans (Inter) for labels and small text, and
  a script font (Petit Formal Script) for accents like "and" and
  "thank you". The mix feels editorial without being heavy.
- **Soft colour palette.** Cream background, sand and olive for
  sections, rust for accents. Avoid pure black — use stone-800 or
  stone-900 for body text.
- **Wide letter spacing on uppercase labels** (`tracking-[0.3em]`).
  Tiny detail that makes the design feel considered.
- **The ornament rule** — those little horizontal lines on either side
  of "Our story" and "The venue" labels. One CSS rule, sells the whole
  vibe.
- **Generous vertical space.** `py-24` sections, lots of breathing
  room. Don't crowd things.
- **Big, soft hero.** The names take up most of the screen. The date
  is small underneath. The user lands and feels something.

You can apply this same approach to any "single beautiful page" use
case — a portfolio cover, an opening night invite, a personal manifesto.
The pattern is: dramatic typography, soft colours, lots of whitespace,
small functional sections, one strong CTA.
