feat: restructure application form (10 steps), add sponsorship tiers, consolidate CTAs

- Restructure apply form: landing screen, pricing at step 1, theme picker,
  belief update, review & pay step, localStorage autosave, warm success state
- Add 7 new DB columns (migration-004): selected_weeks, top_themes,
  belief_update, volunteer_interest, coupon_code, food_preference, accessibility_needs
- Update confirmation emails: 1-week review timeline, warmer tone
- Add sponsorship tiers page (Friend/Symbiont/Spore/Mycelium)
- Consolidate all "Apply Now" → "Register Now", remove duplicate CTAs
- Add new fields to admin panel display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-31 09:58:46 -07:00
parent 707bdc3d53
commit 79141b7142
9 changed files with 1516 additions and 398 deletions

View File

@ -791,6 +791,52 @@
</div> </div>
</div> </div>
<div class="detail-section">
<h3>Themes & Beliefs</h3>
<div class="detail-grid">
<div class="detail-item full-width">
<label>Top Themes</label>
<div class="chip-list">
${(app.top_themes || []).map(t => `<span class="chip">${t}</span>`).join('') || '-'}
</div>
</div>
<div class="detail-item full-width">
<label>Belief Update</label>
<div class="long-text">${app.belief_update || '-'}</div>
</div>
<div class="detail-item full-width">
<label>Selected Weeks</label>
<div class="chip-list">
${(app.selected_weeks || []).map(w => `<span class="chip">${w}</span>`).join('') || '-'}
</div>
</div>
</div>
</div>
<div class="detail-section">
<h3>Practical Needs</h3>
<div class="detail-grid">
<div class="detail-item">
<label>Food Preference</label>
<p>${app.food_preference || '-'}</p>
</div>
<div class="detail-item">
<label>Volunteer Interest</label>
<p>${app.volunteer_interest ? '✓ Yes' : 'No'}</p>
</div>
<div class="detail-item full-width">
<label>Accessibility Needs</label>
<div class="long-text">${app.accessibility_needs || '-'}</div>
</div>
${app.coupon_code ? `
<div class="detail-item">
<label>Coupon Code</label>
<p>${app.coupon_code}</p>
</div>
` : ''}
</div>
</div>
<div class="detail-section"> <div class="detail-section">
<h3>Financial & Practical</h3> <h3>Financial & Practical</h3>
<div class="detail-grid"> <div class="detail-grid">

View File

@ -61,14 +61,12 @@ const confirmationEmail = (application) => {
: ''; : '';
return { return {
subject: 'Application Received - Valley of the Commons', subject: 'Welcome to the Process - Valley of the Commons',
html: ` html: `
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;"> <div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
<h1 style="color: #2d5016; margin-bottom: 24px;">Thank You for Applying!</h1> <h1 style="color: #2d5016; margin-bottom: 24px;">We're glad you're here, ${application.first_name}!</h1>
<p>Dear ${application.first_name},</p> <p>Your application to <strong>Valley of the Commons</strong> (August 24 September 20, 2026) has been received. We're excited to read about what you'll bring to the village.</p>
<p>We've received your application to join <strong>Valley of the Commons</strong> (August 24 - September 20, 2026).</p>
<div style="background: #f5f5f0; padding: 20px; border-radius: 8px; margin: 24px 0;"> <div style="background: #f5f5f0; padding: 20px; border-radius: 8px; margin: 24px 0;">
<h3 style="margin-top: 0; color: #2d5016;">Your Booking Summary</h3> <h3 style="margin-top: 0; color: #2d5016;">Your Booking Summary</h3>
@ -99,10 +97,9 @@ const confirmationEmail = (application) => {
<h3 style="margin-top: 0; color: #2d5016;">What happens next?</h3> <h3 style="margin-top: 0; color: #2d5016;">What happens next?</h3>
<ol style="margin-bottom: 0;"> <ol style="margin-bottom: 0;">
<li><a href="${process.env.BASE_URL || 'https://valleyofthecommons.com'}/api/mollie/resume?id=${application.id}" style="color: #2d5016; font-weight: 600;">Complete your registration payment</a> (if you haven't already)</li> <li><a href="${process.env.BASE_URL || 'https://valleyofthecommons.com'}/api/mollie/resume?id=${application.id}" style="color: #2d5016; font-weight: 600;">Complete your registration payment</a> (if you haven't already)</li>
<li>Our team will review your application</li> <li>Our team will review your application within <strong>1 week</strong></li>
<li>We may reach out with follow-up questions</li> <li>We may reach out with follow-up questions</li>
<li>You'll receive a decision within 2-3 weeks</li> ${accomType ? '<li>Your accommodation will be allocated and details sent to you shortly after payment is confirmed</li>' : ''}
${accomType ? '<li>Your bed will be assigned automatically once payment is confirmed</li>' : ''}
</ol> </ol>
</div> </div>
@ -112,7 +109,7 @@ const confirmationEmail = (application) => {
<li><a href="https://valleyofthecommons.com/">Valley of the Commons</a></li> <li><a href="https://valleyofthecommons.com/">Valley of the Commons</a></li>
</ul> </ul>
<p>If you have any questions, reply to this email and we'll get back to you.</p> <p>If you have any questions, just reply to this email we'd love to hear from you.</p>
<p style="margin-top: 32px;"> <p style="margin-top: 32px;">
With warmth,<br> With warmth,<br>
@ -212,7 +209,7 @@ module.exports = async function handler(req, res) {
const data = req.body; const data = req.body;
// Validate required fields // Validate required fields
const required = ['first_name', 'last_name', 'email', 'motivation', 'code_of_conduct_accepted', 'privacy_policy_accepted']; const required = ['first_name', 'last_name', 'email', 'motivation', 'belief_update', 'privacy_policy_accepted'];
for (const field of required) { for (const field of required) {
if (!data[field]) { if (!data[field]) {
return res.status(400).json({ error: `Missing required field: ${field}` }); return res.status(400).json({ error: `Missing required field: ${field}` });
@ -244,6 +241,10 @@ module.exports = async function handler(req, res) {
const governance = Array.isArray(data.governance_interest) ? data.governance_interest : (data.governance_interest ? [data.governance_interest] : null); const governance = Array.isArray(data.governance_interest) ? data.governance_interest : (data.governance_interest ? [data.governance_interest] : null);
const previousEvents = Array.isArray(data.previous_events) ? data.previous_events : (data.previous_events ? [data.previous_events] : null); const previousEvents = Array.isArray(data.previous_events) ? data.previous_events : (data.previous_events ? [data.previous_events] : null);
// Prepare new array fields
const selectedWeeks = Array.isArray(data.weeks) ? data.weeks : (data.weeks ? [data.weeks] : []);
const topThemes = Array.isArray(data.top_themes) ? data.top_themes : (data.top_themes ? [data.top_themes] : null);
// Insert application // Insert application
const result = await pool.query( const result = await pool.query(
`INSERT INTO applications ( `INSERT INTO applications (
@ -255,11 +256,14 @@ module.exports = async function handler(req, res) {
how_heard, referral_name, previous_events, emergency_name, emergency_phone, how_heard, referral_name, previous_events, emergency_name, emergency_phone,
emergency_relationship, code_of_conduct_accepted, privacy_policy_accepted, emergency_relationship, code_of_conduct_accepted, privacy_policy_accepted,
photo_consent, scholarship_needed, scholarship_reason, contribution_amount, photo_consent, scholarship_needed, scholarship_reason, contribution_amount,
ip_address, user_agent, need_accommodation, want_food, accommodation_type ip_address, user_agent, need_accommodation, want_food, accommodation_type,
selected_weeks, top_themes, belief_update, volunteer_interest, coupon_code,
food_preference, accessibility_needs
) VALUES ( ) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17,
$18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32,
$33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44 $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44,
$45, $46, $47, $48, $49, $50, $51
) RETURNING id, submitted_at`, ) RETURNING id, submitted_at`,
[ [
data.first_name?.trim(), data.first_name?.trim(),
@ -305,11 +309,17 @@ module.exports = async function handler(req, res) {
req.headers['user-agent'] || null, req.headers['user-agent'] || null,
data.need_accommodation || false, data.need_accommodation || false,
data.want_food || false, data.want_food || false,
data.accommodation_type || null data.accommodation_type || null,
selectedWeeks.length > 0 ? selectedWeeks : null,
topThemes,
data.belief_update?.trim() || null,
data.volunteer_interest || false,
data.coupon_code?.trim() || null,
data.food_preference?.trim() || null,
data.accessibility_needs?.trim() || null
] ]
); );
const weeksSelected = Array.isArray(data.weeks) ? data.weeks : [];
const application = { const application = {
id: result.rows[0].id, id: result.rows[0].id,
submitted_at: result.rows[0].submitted_at, submitted_at: result.rows[0].submitted_at,
@ -328,7 +338,7 @@ module.exports = async function handler(req, res) {
referral_name: data.referral_name, referral_name: data.referral_name,
arrival_date: data.arrival_date, arrival_date: data.arrival_date,
departure_date: data.departure_date, departure_date: data.departure_date,
weeks: weeksSelected, weeks: selectedWeeks,
need_accommodation: data.need_accommodation || false, need_accommodation: data.need_accommodation || false,
accommodation_preference: data.accommodation_preference || null, accommodation_preference: data.accommodation_preference || null,
accommodation_type: data.accommodation_type || null, accommodation_type: data.accommodation_type || null,
@ -342,7 +352,7 @@ module.exports = async function handler(req, res) {
// Add to Listmonk newsletter // Add to Listmonk newsletter
addToListmonk(application.email, `${application.first_name} ${application.last_name}`, { addToListmonk(application.email, `${application.first_name} ${application.last_name}`, {
source: 'application', source: 'application',
weeks: weeksSelected, weeks: selectedWeeks,
contributionAmount: data.contribution_amount, contributionAmount: data.contribution_amount,
}).catch(err => console.error('[Listmonk] Application sync failed:', err.message)); }).catch(err => console.error('[Listmonk] Application sync failed:', err.message));
@ -382,17 +392,17 @@ module.exports = async function handler(req, res) {
// Create Mollie payment for registration + accommodation fee // Create Mollie payment for registration + accommodation fee
let checkoutUrl = null; let checkoutUrl = null;
if (weeksSelected.length > 0 && process.env.MOLLIE_API_KEY) { if (selectedWeeks.length > 0 && process.env.MOLLIE_API_KEY) {
try { try {
const paymentResult = await createPayment( const paymentResult = await createPayment(
application.id, application.id,
'registration', 'registration',
weeksSelected.length, selectedWeeks.length,
application.email, application.email,
application.first_name, application.first_name,
application.last_name, application.last_name,
application.accommodation_type, application.accommodation_type,
weeksSelected selectedWeeks
); );
checkoutUrl = paymentResult.checkoutUrl; checkoutUrl = paymentResult.checkoutUrl;
console.log(`Mollie payment created: ${paymentResult.paymentId} (€${paymentResult.amount})`); console.log(`Mollie payment created: ${paymentResult.paymentId} (€${paymentResult.amount})`);

View File

@ -226,7 +226,7 @@ const paymentConfirmationEmail = (application, bookingResult) => {
${bookingHtml} ${bookingHtml}
<p>Your application is now complete. Our team will review it and get back to you within 2-3 weeks.</p> <p>Your application is now complete. Our team will review it and get back to you within 1 week.</p>
<p>If you have any questions, reply to this email and we'll get back to you.</p> <p>If you have any questions, reply to this email and we'll get back to you.</p>

1407
apply.html

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
-- Migration 004: Form restructure — add columns for new application flow
-- selected_weeks, top_themes, belief_update, volunteer_interest, coupon_code, food_preference, accessibility_needs
ALTER TABLE applications
ADD COLUMN IF NOT EXISTS selected_weeks TEXT[],
ADD COLUMN IF NOT EXISTS top_themes TEXT[],
ADD COLUMN IF NOT EXISTS belief_update TEXT,
ADD COLUMN IF NOT EXISTS volunteer_interest BOOLEAN DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS coupon_code TEXT,
ADD COLUMN IF NOT EXISTS food_preference TEXT,
ADD COLUMN IF NOT EXISTS accessibility_needs TEXT;

View File

@ -51,9 +51,8 @@
<span class="nav-speakers-short">Collaborators</span> <span class="nav-speakers-short">Collaborators</span>
</a> </a>
<a href="#explore">Explore the Valley</a> <a href="#explore">Explore the Valley</a>
<a href="#register" class="nav-get-involved">Register</a>
<a href="game.html" target="_blank" rel="noopener noreferrer" class="nav-rabbit">🐰</a> <a href="game.html" target="_blank" rel="noopener noreferrer" class="nav-rabbit">🐰</a>
<a href="/apply.html" class="nav-cta-button">APPLY NOW</a> <a href="/apply.html" class="nav-cta-button">REGISTER NOW</a>
</nav> </nav>
</div> </div>
</header> </header>
@ -78,7 +77,7 @@
<h2 class="event-title">Pop-Up Event to Seed the Valley</h2> <h2 class="event-title">Pop-Up Event to Seed the Valley</h2>
<p class="event-dates">24 August 2026 20 September 2026</p> <p class="event-dates">24 August 2026 20 September 2026</p>
</div> </div>
<a href="/apply.html" class="cta-button">APPLY NOW</a> <a href="/apply.html" class="cta-button">REGISTER NOW</a>
</section> </section>
<!-- Main Content --> <!-- Main Content -->
@ -202,9 +201,6 @@
<div id="partners-container" class="partners-container"> <div id="partners-container" class="partners-container">
<!-- Partners will be dynamically loaded here --> <!-- Partners will be dynamically loaded here -->
</div> </div>
<p style="text-align: center; margin-top: var(--spacing-md);">
<a href="#register" class="explore-link">Register →</a>
</p>
</section> </section>
<!-- Explore the Valley Section --> <!-- Explore the Valley Section -->
@ -226,7 +222,6 @@
<span>from €120 / week</span> <span>from €120 / week</span>
</div> </div>
<a href="/apply.html" class="register-button">REGISTER NOW</a> <a href="/apply.html" class="register-button">REGISTER NOW</a>
<p class="cta-note">You'll be added to our mailing list to stay updated.</p>
</div> </div>
</section> </section>
@ -238,6 +233,7 @@
<input type="email" id="newsletter-email" name="email" placeholder="your@email.com" required aria-label="Email address"> <input type="email" id="newsletter-email" name="email" placeholder="your@email.com" required aria-label="Email address">
<button type="submit">Subscribe</button> <button type="submit">Subscribe</button>
</form> </form>
<p class="cta-note">You'll be added to our mailing list to stay updated.</p>
<div id="newsletter-message" class="newsletter-message" role="status" aria-live="polite"></div> <div id="newsletter-message" class="newsletter-message" role="status" aria-live="polite"></div>
</div> </div>
</section> </section>

View File

@ -216,7 +216,7 @@
switch (data.paymentStatus) { switch (data.paymentStatus) {
case 'paid': case 'paid':
showStatus('success', 'Payment Confirmed!', showStatus('success', 'Payment Confirmed!',
'Your payment has been received. We\'ll review your application and get back to you within 2-3 weeks.', true); 'Your payment has been received. We\'ll review your application and get back to you within 1 week.', true);
break; break;
case 'pending': case 'pending':
case 'open': case 'open':

View File

@ -87,6 +87,18 @@ async function runMigrations() {
ADD COLUMN IF NOT EXISTS accommodation_type VARCHAR(50) ADD COLUMN IF NOT EXISTS accommodation_type VARCHAR(50)
`); `);
// Form restructure columns (migration 004)
await pool.query(`
ALTER TABLE applications
ADD COLUMN IF NOT EXISTS selected_weeks TEXT[],
ADD COLUMN IF NOT EXISTS top_themes TEXT[],
ADD COLUMN IF NOT EXISTS belief_update TEXT,
ADD COLUMN IF NOT EXISTS volunteer_interest BOOLEAN DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS coupon_code TEXT,
ADD COLUMN IF NOT EXISTS food_preference TEXT,
ADD COLUMN IF NOT EXISTS accessibility_needs TEXT
`);
// Rename resend_id → message_id in email_log (legacy column name) // Rename resend_id → message_id in email_log (legacy column name)
const colCheck = await pool.query(` const colCheck = await pool.query(`
SELECT column_name FROM information_schema.columns SELECT column_name FROM information_schema.columns

View File

@ -16,6 +16,7 @@
--color-bg: #ffffff; --color-bg: #ffffff;
--color-accent: #000; --color-accent: #000;
--color-link: #000; --color-link: #000;
--color-forest: #2d5016;
--font-sans: 'Urbanist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --font-sans: 'Urbanist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
} }
@ -39,7 +40,7 @@
} }
.header-container { .header-container {
max-width: 900px; max-width: 1100px;
margin: 0 auto; margin: 0 auto;
padding: 0 2rem; padding: 0 2rem;
display: flex; display: flex;
@ -59,15 +60,15 @@
.header a:hover { text-decoration: underline; } .header a:hover { text-decoration: underline; }
.content { .content {
max-width: 900px; max-width: 1100px;
margin: 0 auto; margin: 0 auto;
padding: 4rem 2rem; padding: 3rem 2rem 4rem;
flex: 1; flex: 1;
display: flex; }
flex-direction: column;
align-items: center; .page-header {
justify-content: center;
text-align: center; text-align: center;
margin-bottom: 3rem;
} }
h1 { h1 {
@ -81,21 +82,177 @@
.subtitle { .subtitle {
font-size: 1.2rem; font-size: 1.2rem;
color: var(--color-text-light); color: var(--color-text-light);
margin-bottom: 2rem; margin-bottom: 1rem;
} }
.coming-soon { .intro-text {
font-size: 1.1rem; font-size: 1.05rem;
color: var(--color-text-light); color: var(--color-text-light);
max-width: 500px; max-width: 650px;
margin-bottom: 2rem; margin: 0 auto;
} }
.contact { /* Tier cards */
font-size: 1rem; .tiers {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.25rem;
margin-bottom: 3rem;
} }
.contact a { .tier-card {
border: 1px solid #e5e5e5;
border-radius: 12px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.tier-card.featured {
border-color: var(--color-forest);
box-shadow: 0 4px 16px rgba(45, 80, 22, 0.12);
}
.tier-header {
padding: 1.5rem 1.25rem 1rem;
text-align: center;
border-bottom: 1px solid #e5e5e5;
}
.tier-card.featured .tier-header {
background: var(--color-forest);
border-bottom-color: var(--color-forest);
}
.tier-card.featured .tier-name,
.tier-card.featured .tier-price,
.tier-card.featured .tier-limit {
color: white;
}
.tier-name {
font-size: 0.85rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 0.5rem;
color: var(--color-text);
}
.tier-price {
font-size: 2rem;
font-weight: 700;
color: var(--color-text);
line-height: 1.2;
}
.tier-limit {
font-size: 0.8rem;
color: var(--color-text-light);
margin-top: 0.25rem;
}
.tier-body {
padding: 1.25rem;
flex: 1;
display: flex;
flex-direction: column;
gap: 1rem;
}
.tier-perk {
display: flex;
gap: 0.5rem;
font-size: 0.9rem;
line-height: 1.4;
}
.tier-perk .perk-icon {
flex-shrink: 0;
width: 20px;
text-align: center;
color: var(--color-forest);
font-weight: 600;
}
.tier-perk .perk-label {
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--color-text-light);
display: block;
margin-bottom: 0.1rem;
}
.tier-perk.empty {
color: #ccc;
}
.tier-footer {
padding: 1.25rem;
border-top: 1px solid #f0f0f0;
text-align: center;
}
.tier-cta {
display: inline-block;
padding: 0.6rem 1.5rem;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 0.04em;
border: 1px solid var(--color-text);
color: var(--color-text);
transition: all 0.2s;
}
.tier-cta:hover {
background: var(--color-text);
color: white;
}
.tier-card.featured .tier-cta {
background: var(--color-forest);
color: white;
border-color: var(--color-forest);
}
.tier-card.featured .tier-cta:hover {
background: #3a6b1e;
}
/* Footnote */
.footnote {
text-align: center;
font-size: 0.85rem;
color: var(--color-text-light);
font-style: italic;
margin-bottom: 3rem;
}
/* CTA */
.cta-section {
text-align: center;
padding: 2.5rem;
background: #f9f9f6;
border-radius: 12px;
}
.cta-section h2 {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
.cta-section p {
color: var(--color-text-light);
margin-bottom: 1rem;
}
.cta-section a {
color: var(--color-link); color: var(--color-link);
font-weight: 600; font-weight: 600;
} }
@ -114,25 +271,202 @@
} }
.footer a:hover { text-decoration: underline; } .footer a:hover { text-decoration: underline; }
/* Responsive */
@media (max-width: 900px) {
.tiers {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 550px) {
.tiers {
grid-template-columns: 1fr;
}
.content { padding: 2rem 1rem; }
}
</style> </style>
</head> </head>
<body> <body>
<header class="header"> <header class="header">
<div class="header-container"> <div class="header-container">
<a href="/">Valley of the Commons</a> <a href="/">Valley of the Commons</a>
<a href="/apply.html">Apply Now</a> <a href="/apply.html">Register Now</a>
</div> </div>
</header> </header>
<div class="content"> <div class="content">
<h1>Sponsorships</h1> <div class="page-header">
<p class="subtitle">Aug 24 Sep 20, 2026 · Höllental, Austrian Alps</p> <h1>Sponsorship Tiers</h1>
<p class="coming-soon">Details coming soon. We're finalizing sponsorship packages for Valley of the Commons and will share more here shortly.</p> <p class="subtitle">Aug 24 &ndash; Sep 20, 2026 &middot; H&ouml;llental, Austrian Alps</p>
<p class="contact">Interested? Reach out at <a href="mailto:team@valleyofthecommons.com">team@valleyofthecommons.com</a></p> <p class="intro-text">Support the commons and gain visibility with a community of practitioners, researchers, and builders shaping life beyond extractive systems.</p>
</div>
<div class="tiers">
<!-- Friend of the Commons -->
<div class="tier-card">
<div class="tier-header">
<div class="tier-name">Friend of<br>the Commons</div>
<div class="tier-price">&euro;1,000</div>
<div class="tier-limit">Unlimited spots</div>
</div>
<div class="tier-body">
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Ticket Voucher</span>&euro;250</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Visibility</span>Name on sponsor list</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Public Gratitude</span>Social media recognition</div>
</div>
<div class="tier-perk empty">
<span class="perk-icon">&mdash;</span>
<div>Stage Access</div>
</div>
<div class="tier-perk empty">
<span class="perk-icon">&mdash;</span>
<div>Video Assets</div>
</div>
<div class="tier-perk empty">
<span class="perk-icon">&mdash;</span>
<div>Branded Handouts</div>
</div>
</div>
<div class="tier-footer">
<a href="mailto:team@valleyofthecommons.com?subject=Sponsorship%20—%20Friend%20of%20the%20Commons" class="tier-cta">Get in Touch</a>
</div>
</div>
<!-- Symbiont Supporter -->
<div class="tier-card">
<div class="tier-header">
<div class="tier-name">Symbiont<br>Supporter</div>
<div class="tier-price">&euro;2,500</div>
<div class="tier-limit">10 spots</div>
</div>
<div class="tier-body">
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Ticket Voucher</span>&euro;625</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Visibility</span>Small logo on website</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Public Gratitude</span>Social media recognition</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Stage Access</span>25 min exclusive session (no competing sessions)</div>
</div>
<div class="tier-perk empty">
<span class="perk-icon">&mdash;</span>
<div>Video Assets</div>
</div>
<div class="tier-perk empty">
<span class="perk-icon">&mdash;</span>
<div>Branded Handouts</div>
</div>
</div>
<div class="tier-footer">
<a href="mailto:team@valleyofthecommons.com?subject=Sponsorship%20—%20Symbiont%20Supporter" class="tier-cta">Get in Touch</a>
</div>
</div>
<!-- Spore Partner -->
<div class="tier-card featured">
<div class="tier-header">
<div class="tier-name">Spore<br>Partner</div>
<div class="tier-price">&euro;5,000</div>
<div class="tier-limit">5 spots</div>
</div>
<div class="tier-body">
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Ticket Voucher</span>&euro;1,250</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Visibility</span>Mid-sized logo on website &amp; signage</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Public Gratitude</span>Social media recognition + naming in opening &amp; closing ceremony</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Stage Access</span>45 min exclusive session</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Video Assets</span>Short clip for your socials</div>
</div>
<div class="tier-perk empty">
<span class="perk-icon">&mdash;</span>
<div>Branded Handouts</div>
</div>
</div>
<div class="tier-footer">
<a href="mailto:team@valleyofthecommons.com?subject=Sponsorship%20—%20Spore%20Partner" class="tier-cta">Get in Touch</a>
</div>
</div>
<!-- Mycelium Partner -->
<div class="tier-card">
<div class="tier-header">
<div class="tier-name">Mycelium<br>Partner</div>
<div class="tier-price">&euro;10,000</div>
<div class="tier-limit">3 spots</div>
</div>
<div class="tier-body">
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Ticket Voucher</span>&euro;2,500</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Visibility</span>Central logo on website &amp; signage</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Public Gratitude</span>Social media recognition + naming in opening &amp; closing ceremony</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Stage Access</span>2&times; 45 min exclusive session</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Video Assets</span>Extended feature</div>
</div>
<div class="tier-perk">
<span class="perk-icon">&check;</span>
<div><span class="perk-label">Branded Handouts</span>Cosmo-local gimmicks* produced in our fablab</div>
</div>
</div>
<div class="tier-footer">
<a href="mailto:team@valleyofthecommons.com?subject=Sponsorship%20—%20Mycelium%20Partner" class="tier-cta">Get in Touch</a>
</div>
</div>
</div>
<p class="footnote">* Customized to your specific needs</p>
<div class="cta-section">
<h2>Interested in sponsoring?</h2>
<p>We'd love to discuss how we can work together. Every tier is customizable.</p>
<p><a href="mailto:team@valleyofthecommons.com">team@valleyofthecommons.com</a></p>
</div>
</div> </div>
<footer class="footer"> <footer class="footer">
<p>&copy; 2026 Commons Hub · <a href="mailto:team@valleyofthecommons.com">team@valleyofthecommons.com</a> · <a href="/privacy.html">Privacy Policy</a> · <a href="/">Home</a></p> <p>&copy; 2026 Commons Hub &middot; <a href="mailto:team@valleyofthecommons.com">team@valleyofthecommons.com</a> &middot; <a href="/privacy.html">Privacy Policy</a> &middot; <a href="/">Home</a></p>
</footer> </footer>
</body> </body>
</html> </html>