Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6311a3a5e |
118
about.php
Normal file
118
about.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'About Us';
|
||||
$pageDescription = 'Strategic positioning, objectives, and operating logic behind the Genitri Ecco Wellness ecosystem.';
|
||||
$activePage = 'about';
|
||||
$objectives = objective_list();
|
||||
$values = governance_values();
|
||||
|
||||
$positioningPillars = [
|
||||
['title' => 'Institutional trust platform', 'summary' => 'A calm, premium first impression that feels credible to partners, institutions, and high-value guests.'],
|
||||
['title' => 'Curated service commerce', 'summary' => 'Packages are presented with editorial clarity and routed into a structured consultation path.'],
|
||||
['title' => 'Partnership integration system', 'summary' => 'Multiple partner categories can be invited into one operating ecosystem without clutter.'],
|
||||
['title' => 'Publication authority layer', 'summary' => 'Insight and updates reinforce operational maturity, not just marketing claims.'],
|
||||
['title' => 'Governance foundation', 'summary' => 'The site prepares future reporting, admin processes, and ecosystem accountability.'],
|
||||
];
|
||||
|
||||
$operatingModel = [
|
||||
['title' => 'Discovery', 'summary' => 'Brief collection, stakeholder mapping, and intent clarification.'],
|
||||
['title' => 'Curation', 'summary' => 'Program architecture, partner matching, and experience design.'],
|
||||
['title' => 'Delivery', 'summary' => 'On-ground hospitality, logistics, facilitation, and documentation.'],
|
||||
['title' => 'Governance', 'summary' => 'Reporting discipline, partner oversight, and institutional trust signals.'],
|
||||
];
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-7">
|
||||
<span class="section-kicker">About GBP</span>
|
||||
<h1 class="page-title">An integrated ecosystem designed for trust, transformation, and operational clarity.</h1>
|
||||
<p class="lead-copy mb-0">PT. Genitri Bregas Persada positions Genitri Ecco Wellness as a premium nature-based experience ecosystem—bridging eco wellness, hospitality, retreat design, MICE support, and partnership collaboration.</p>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="surface-card hero-panel h-100">
|
||||
<span class="signal-chip signal-chip--primary mb-3">Tagline</span>
|
||||
<h2 class="card-title">Nature-Based Experiential Tourism & Eco Wellness Services</h2>
|
||||
<p class="card-copy mb-0">The experience direction is intentionally calm, institutional, and editorial rather than marketplace-like or generic tourism-led.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="section-kicker">Strategic positioning</span>
|
||||
<h2 class="section-title">What makes the ecosystem distinct.</h2>
|
||||
<p class="section-copy">The site is designed to show how multiple disciplines can feel integrated without looking crowded.</p>
|
||||
</div>
|
||||
<div class="feature-grid">
|
||||
<?php foreach ($positioningPillars as $pillar): ?>
|
||||
<article class="surface-card">
|
||||
<h3 class="card-title"><?= h($pillar['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($pillar['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-6">
|
||||
<div class="surface-card h-100">
|
||||
<span class="section-kicker">Core objectives</span>
|
||||
<h2 class="section-title">A website built to do real institutional work.</h2>
|
||||
<ul class="objective-list mt-3">
|
||||
<?php foreach ($objectives as $objective): ?>
|
||||
<li><?= h($objective) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="surface-card h-100">
|
||||
<span class="section-kicker">Operating model</span>
|
||||
<h2 class="section-title">A lightweight structure that can scale.</h2>
|
||||
<div class="timeline-grid mt-3">
|
||||
<?php foreach ($operatingModel as $step): ?>
|
||||
<article class="surface-card service-card">
|
||||
<span class="signal-chip"><?= h($step['title']) ?></span>
|
||||
<p class="card-copy mb-0"><?= h($step['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section pt-0">
|
||||
<div class="container">
|
||||
<div class="dark-block">
|
||||
<div class="section-head mb-4">
|
||||
<span class="section-kicker text-white">Values</span>
|
||||
<h2 class="section-title text-white">A premium tone supported by ethical grounding.</h2>
|
||||
</div>
|
||||
<div class="dark-grid">
|
||||
<?php foreach ($values as $value): ?>
|
||||
<article class="surface-card surface-card--dark">
|
||||
<h3 class="card-title"><?= h($value['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($value['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
169
admin.php
Normal file
169
admin.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Inquiry Desk';
|
||||
$pageDescription = 'Preview list and detail view for strategic inquiries submitted through the first MVP slice.';
|
||||
$pageRobots = 'noindex, nofollow';
|
||||
$activePage = '';
|
||||
|
||||
$inquiries = list_inquiries();
|
||||
$selectedReference = trim((string) ($_GET['reference'] ?? ''));
|
||||
$selectedId = isset($_GET['id']) ? (int) $_GET['id'] : null;
|
||||
$selectedInquiry = null;
|
||||
|
||||
if ($selectedReference !== '' || ($selectedId !== null && $selectedId > 0)) {
|
||||
$selectedInquiry = find_inquiry($selectedId, $selectedReference !== '' ? $selectedReference : null);
|
||||
}
|
||||
|
||||
if (!$selectedInquiry && $inquiries !== []) {
|
||||
$selectedInquiry = $inquiries[0];
|
||||
}
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell page-intro">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<span class="section-kicker">Preview desk</span>
|
||||
<h1 class="page-title">Qualified inquiry queue and detail view.</h1>
|
||||
<p class="lead-copy mb-0">This admin-style page gives the first delivery an internal operational surface: a list of saved inquiries and a focused detail panel for review.</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="surface-card hero-panel h-100">
|
||||
<span class="signal-chip signal-chip--primary mb-3">Queue snapshot</span>
|
||||
<div class="metric-stack">
|
||||
<div class="meta-stack mb-3">
|
||||
<span class="meta-label">Entries</span>
|
||||
<strong><?= h((string) count($inquiries)) ?></strong>
|
||||
</div>
|
||||
<div class="meta-stack">
|
||||
<span class="meta-label">Storage mode</span>
|
||||
<strong><?= using_preview_storage() ? 'Preview session' : 'Database' ?></strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (using_preview_storage()): ?>
|
||||
<div class="notice-banner notice-banner--warning mb-4">
|
||||
<strong>Preview mode:</strong> the queue is reading from the current browser session because the database connection is rejecting access right now.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="admin-layout">
|
||||
<section class="table-shell p-3">
|
||||
<div class="d-flex justify-content-between align-items-center gap-3 mb-3">
|
||||
<div>
|
||||
<span class="section-kicker">Inquiry list</span>
|
||||
<h2 class="section-title mb-0">Current queue</h2>
|
||||
</div>
|
||||
<a class="btn btn-outline-brand btn-sm" href="partnership.php">New inquiry</a>
|
||||
</div>
|
||||
<?php if ($inquiries === []): ?>
|
||||
<div class="empty-panel">
|
||||
<span class="signal-chip signal-chip--gold mb-3">Empty state</span>
|
||||
<h3 class="detail-title">No inquiries yet</h3>
|
||||
<p class="empty-copy">Submit the first strategic brief to see the list and detail layout in action.</p>
|
||||
<a class="btn btn-brand mt-2" href="partnership.php">Open inquiry desk</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table queue-table align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Reference</th>
|
||||
<th>Contact</th>
|
||||
<th>Interest</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($inquiries as $inquiry):
|
||||
$isActive = $selectedInquiry && ($selectedInquiry['reference_code'] === $inquiry['reference_code']);
|
||||
?>
|
||||
<tr class="<?= $isActive ? 'queue-row--active' : '' ?>">
|
||||
<td>
|
||||
<a class="queue-link" href="<?= h(page_url('admin.php', ['reference' => $inquiry['reference_code']])) ?>"><?= h($inquiry['reference_code']) ?></a>
|
||||
<div class="note-muted"><?= h(format_date_label($inquiry['created_at'] ?? '')) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<strong><?= h($inquiry['contact_name']) ?></strong>
|
||||
<div class="note-muted"><?= h($inquiry['organization_name']) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="queue-summary"><?= h($inquiry['interest_area']) ?></div>
|
||||
<div class="note-muted"><?= h($inquiry['inquiry_type']) ?></div>
|
||||
</td>
|
||||
<td><span class="status-badge status-badge--new"><?= h($inquiry['status'] ?? 'New') ?></span></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<aside class="surface-card p-3">
|
||||
<?php if (!$selectedInquiry): ?>
|
||||
<div class="empty-panel h-100 d-flex flex-column justify-content-center">
|
||||
<span class="signal-chip signal-chip--gold mb-3">No selection</span>
|
||||
<h3 class="detail-title">Select an inquiry</h3>
|
||||
<p class="empty-copy">Pick a queue item to inspect the detailed context for review.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="d-flex justify-content-between align-items-start gap-3 mb-3">
|
||||
<div>
|
||||
<span class="section-kicker">Detail view</span>
|
||||
<h2 class="section-title mb-1"><?= h($selectedInquiry['organization_name']) ?></h2>
|
||||
<p class="meta-inline mb-0"><?= h($selectedInquiry['contact_name']) ?> · <?= h($selectedInquiry['email']) ?></p>
|
||||
</div>
|
||||
<span class="status-badge status-badge--new"><?= h($selectedInquiry['status'] ?? 'New') ?></span>
|
||||
</div>
|
||||
<div class="copy-inline mb-3">
|
||||
<span class="signal-chip signal-chip--gold" id="selectedReference"><?= h($selectedInquiry['reference_code']) ?></span>
|
||||
<button class="btn btn-subtle btn-sm" type="button" data-copy-target="#selectedReference">Copy</button>
|
||||
</div>
|
||||
<div class="detail-grid">
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Inquiry type</span>
|
||||
<div class="detail-title"><?= h($selectedInquiry['inquiry_type']) ?></div>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Interest area</span>
|
||||
<div class="detail-title"><?= h($selectedInquiry['interest_area']) ?></div>
|
||||
</div>
|
||||
<div class="detail-meta">
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Preferred date</span>
|
||||
<strong><?= h(format_date_label($selectedInquiry['target_date'] ?? '')) ?></strong>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Scale</span>
|
||||
<strong><?= h($selectedInquiry['event_scale'] ?? 'To be discussed') ?></strong>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Location</span>
|
||||
<strong><?= h($selectedInquiry['preferred_location'] ?? 'To be discussed') ?></strong>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Phone / WhatsApp</span>
|
||||
<strong><?= h($selectedInquiry['phone'] ?: 'Not provided') ?></strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Brief summary</span>
|
||||
<p class="detail-copy mb-0"><?= nl2br(h($selectedInquiry['notes'])) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,39 +1,68 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const chatForm = document.getElementById('chat-form');
|
||||
const chatInput = document.getElementById('chat-input');
|
||||
const chatMessages = document.getElementById('chat-messages');
|
||||
|
||||
const appendMessage = (text, sender) => {
|
||||
const msgDiv = document.createElement('div');
|
||||
msgDiv.classList.add('message', sender);
|
||||
msgDiv.textContent = text;
|
||||
chatMessages.appendChild(msgDiv);
|
||||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||
const navbar = document.querySelector('.site-navbar');
|
||||
const onScroll = () => {
|
||||
if (navbar) {
|
||||
navbar.classList.toggle('scrolled', window.scrollY > 12);
|
||||
}
|
||||
};
|
||||
|
||||
chatForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const message = chatInput.value.trim();
|
||||
if (!message) return;
|
||||
document.addEventListener('scroll', onScroll, { passive: true });
|
||||
onScroll();
|
||||
|
||||
appendMessage(message, 'visitor');
|
||||
chatInput.value = '';
|
||||
if (window.bootstrap && typeof bootstrap.Toast === 'function') {
|
||||
document.querySelectorAll('.toast').forEach((toastElement) => {
|
||||
const toast = new bootstrap.Toast(toastElement, { delay: 5200 });
|
||||
toast.show();
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('api/chat.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ message })
|
||||
const filterButtons = document.querySelectorAll('[data-service-filter]');
|
||||
const serviceItems = document.querySelectorAll('[data-service-track]');
|
||||
|
||||
if (filterButtons.length && serviceItems.length) {
|
||||
filterButtons.forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const filter = button.dataset.serviceFilter || 'all';
|
||||
filterButtons.forEach((candidate) => candidate.classList.toggle('active', candidate === button));
|
||||
serviceItems.forEach((item) => {
|
||||
const track = item.dataset.serviceTrack || '';
|
||||
const visible = filter === 'all' || track === filter;
|
||||
item.classList.toggle('d-none', !visible);
|
||||
});
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
// Artificial delay for realism
|
||||
setTimeout(() => {
|
||||
appendMessage(data.reply, 'bot');
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
appendMessage("Sorry, something went wrong. Please try again.", 'bot');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('[data-copy-target]').forEach((button) => {
|
||||
button.addEventListener('click', async () => {
|
||||
const target = document.querySelector(button.dataset.copyTarget || '');
|
||||
if (!target) return;
|
||||
|
||||
const originalText = button.textContent;
|
||||
try {
|
||||
await navigator.clipboard.writeText(target.textContent.trim());
|
||||
button.textContent = 'Copied';
|
||||
window.setTimeout(() => {
|
||||
button.textContent = originalText;
|
||||
}, 1600);
|
||||
} catch (error) {
|
||||
button.textContent = 'Unavailable';
|
||||
window.setTimeout(() => {
|
||||
button.textContent = originalText;
|
||||
}, 1600);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-char-count]').forEach((textarea) => {
|
||||
const counter = document.querySelector(textarea.dataset.charCount || '');
|
||||
if (!counter) return;
|
||||
|
||||
const updateCount = () => {
|
||||
counter.textContent = `${textarea.value.length} / ${textarea.maxLength}`;
|
||||
};
|
||||
|
||||
textarea.addEventListener('input', updateCount);
|
||||
updateCount();
|
||||
});
|
||||
});
|
||||
|
||||
53
contact.php
Normal file
53
contact.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Contact Us';
|
||||
$pageDescription = 'Contact guidance for strategic discussion, package scoping, and partnership coordination.';
|
||||
$activePage = 'contact';
|
||||
|
||||
$contactCards = [
|
||||
['title' => 'Strategic discussion', 'summary' => 'Use the inquiry desk for partnership, package customization, or operational collaboration.'],
|
||||
['title' => 'Email-based follow-up', 'summary' => 'The intake form captures a work email so the next step can stay formal and documented.'],
|
||||
['title' => 'Location coordination', 'summary' => 'Share the preferred area or property context in the brief so site planning starts earlier.'],
|
||||
];
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell page-intro">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<span class="section-kicker">Contact guidance</span>
|
||||
<h1 class="page-title">A clear route into strategic discussion.</h1>
|
||||
<p class="lead-copy mb-0">Rather than scattering generic contact details, this MVP uses a structured intake path so every conversation starts with context, scale, and the right ecosystem lane.</p>
|
||||
</div>
|
||||
<div class="col-lg-4 text-lg-end">
|
||||
<a class="btn btn-brand" href="partnership.php">Schedule Strategic Discussion</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="contact-grid">
|
||||
<?php foreach ($contactCards as $card): ?>
|
||||
<article class="contact-panel surface-card service-card">
|
||||
<h2 class="card-title"><?= h($card['title']) ?></h2>
|
||||
<p class="card-copy mb-0"><?= h($card['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="surface-card mt-4">
|
||||
<span class="section-kicker">Recommended next action</span>
|
||||
<h2 class="section-title">Use the partnership page as the main intake channel.</h2>
|
||||
<p class="section-copy mb-4">It already captures the package or partner route, preferred timing, location context, and a short narrative brief—everything needed for a credible first review.</p>
|
||||
<div class="d-flex flex-wrap gap-2 inline-actions">
|
||||
<a class="btn btn-brand" href="partnership.php">Open inquiry desk</a>
|
||||
<a class="btn btn-outline-brand" href="admin.php">Preview saved inquiries</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
18
database/gbp_ecosystem.sql
Normal file
18
database/gbp_ecosystem.sql
Normal file
@ -0,0 +1,18 @@
|
||||
-- Genitri Ecco Wellness inquiry desk
|
||||
CREATE TABLE IF NOT EXISTS ecosystem_inquiries (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
reference_code VARCHAR(32) NOT NULL UNIQUE,
|
||||
inquiry_type VARCHAR(80) NOT NULL,
|
||||
interest_area VARCHAR(120) NOT NULL,
|
||||
contact_name VARCHAR(120) NOT NULL,
|
||||
organization_name VARCHAR(160) NOT NULL,
|
||||
email VARCHAR(160) NOT NULL,
|
||||
phone VARCHAR(40) DEFAULT NULL,
|
||||
target_date VARCHAR(40) DEFAULT NULL,
|
||||
event_scale VARCHAR(80) DEFAULT NULL,
|
||||
preferred_location VARCHAR(120) DEFAULT NULL,
|
||||
notes TEXT NOT NULL,
|
||||
status VARCHAR(30) NOT NULL DEFAULT 'New',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_status_created (status, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
14
healthz.php
Normal file
14
healthz.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
http_response_code(200);
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'timestamp' => gmdate(DATE_ATOM),
|
||||
'storage' => using_preview_storage() ? 'preview-session' : 'database',
|
||||
'site' => site_name(),
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
709
includes/app.php
Normal file
709
includes/app.php
Normal file
@ -0,0 +1,709 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
function app_env(string $key, string $fallback = ''): string
|
||||
{
|
||||
$serverValue = $_SERVER[$key] ?? null;
|
||||
if (is_string($serverValue) && trim($serverValue) !== '') {
|
||||
return trim($serverValue);
|
||||
}
|
||||
|
||||
$envValue = getenv($key);
|
||||
if (is_string($envValue) && trim($envValue) !== '') {
|
||||
return trim($envValue);
|
||||
}
|
||||
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
function h(mixed $value): string
|
||||
{
|
||||
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
function text_length(string $value): int
|
||||
{
|
||||
return function_exists('mb_strlen') ? mb_strlen($value) : strlen($value);
|
||||
}
|
||||
|
||||
function site_name(): string
|
||||
{
|
||||
return app_env('PROJECT_NAME', 'Genitri Ecco Wellness');
|
||||
}
|
||||
|
||||
function site_tagline(): string
|
||||
{
|
||||
return 'Nature-Based Experiential Tourism & Eco Wellness Services';
|
||||
}
|
||||
|
||||
function default_meta_description(): string
|
||||
{
|
||||
return app_env(
|
||||
'PROJECT_DESCRIPTION',
|
||||
'Integrated nature-based experience ecosystem for eco wellness, experiential tourism, hospitality collaboration, and strategic partnership.'
|
||||
);
|
||||
}
|
||||
|
||||
function page_url(string $path, array $query = []): string
|
||||
{
|
||||
return $query ? $path . '?' . http_build_query($query) : $path;
|
||||
}
|
||||
|
||||
function navigation_items(): array
|
||||
{
|
||||
return [
|
||||
['key' => 'home', 'label' => 'Home', 'href' => 'index.php'],
|
||||
['key' => 'about', 'label' => 'About Us', 'href' => 'about.php'],
|
||||
['key' => 'services', 'label' => 'Services', 'href' => 'services.php'],
|
||||
['key' => 'portfolio', 'label' => 'Portfolio', 'href' => 'portfolio.php'],
|
||||
['key' => 'partnership', 'label' => 'Partnership', 'href' => 'partnership.php'],
|
||||
['key' => 'publications', 'label' => 'Publications', 'href' => 'publications.php'],
|
||||
['key' => 'contact', 'label' => 'Contact Us', 'href' => 'contact.php'],
|
||||
];
|
||||
}
|
||||
|
||||
function default_service_catalog(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'slug' => 'eco-wellness',
|
||||
'track' => 'immersive',
|
||||
'category' => 'Eco Wellness Package',
|
||||
'headline' => 'Preventive wellbeing journeys grounded in place.',
|
||||
'summary' => 'Curated wellness experiences that combine guided recovery, quiet hospitality, and structured facilitation for premium groups.',
|
||||
'audience' => 'Clinics, communities, executive wellness groups',
|
||||
'duration' => 'Half day to 3 days',
|
||||
'outcome' => 'Participants leave with a calmer baseline, curated routines, and professionally coordinated aftercare recommendations.',
|
||||
'includes' => [
|
||||
'Guided breathing, mobility, and reflection sessions',
|
||||
'Nature immersion flow with on-site facilitator',
|
||||
'Healthy hospitality setup and light nourishment',
|
||||
'Operational coordinator, safety briefing, and guest support',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'retreat',
|
||||
'track' => 'immersive',
|
||||
'category' => 'Retreat Package',
|
||||
'headline' => 'Immersive retreats with quiet luxury and operational discipline.',
|
||||
'summary' => 'Multi-day retreat programs for restorative groups, leadership circles, or curated community cohorts seeking a trusted delivery partner.',
|
||||
'audience' => 'Leadership teams, private communities, destination hosts',
|
||||
'duration' => '2 to 4 days',
|
||||
'outcome' => 'Guests receive a coherent retreat arc, documented experience moments, and a host-ready operating structure.',
|
||||
'includes' => [
|
||||
'Retreat flow design from arrival to closing circle',
|
||||
'Hospitality curation and accommodation coordination',
|
||||
'Experience documentation and facilitator scheduling',
|
||||
'Transportation, guest movement, and contingency planning',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'corporate',
|
||||
'track' => 'corporate',
|
||||
'category' => 'Corporate Package',
|
||||
'headline' => 'Nature-based programs for teams that need focus, recovery, and alignment.',
|
||||
'summary' => 'Corporate offsites and culture journeys that balance executive standards, wellness objectives, and measurable group outcomes.',
|
||||
'audience' => 'Companies, HR teams, executive assistants, corporate communities',
|
||||
'duration' => '1 to 2 days',
|
||||
'outcome' => 'A more connected team, clean guest logistics, and a premium experience that avoids generic event energy.',
|
||||
'includes' => [
|
||||
'Team reset sessions and guided collaboration moments',
|
||||
'Hospitality coordination with venue and catering partners',
|
||||
'Brand-safe itineraries, agendas, and support crew',
|
||||
'Post-program recap for internal reporting',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'hospitality',
|
||||
'track' => 'operational',
|
||||
'category' => 'Hospitality Package',
|
||||
'headline' => 'Hospitality collaborations that expand destination value.',
|
||||
'summary' => 'Program overlays for properties, destinations, or operators wanting to add curated wellness and experiential layers to their guest offering.',
|
||||
'audience' => 'Hotels, villas, destination operators, stay partners',
|
||||
'duration' => 'Modular activation',
|
||||
'outcome' => 'Partners gain a credible package layer, documented service standards, and a stronger experiential positioning.',
|
||||
'includes' => [
|
||||
'Experience packaging and guest-ready positioning',
|
||||
'Venue flow, staffing, and hospitality service mapping',
|
||||
'Wellness or retreat modules fitted to the property',
|
||||
'Partner coordination with clear operating notes',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'event-mice',
|
||||
'track' => 'corporate',
|
||||
'category' => 'Event & MICE Package',
|
||||
'headline' => 'Operationally credible events with experiential depth.',
|
||||
'summary' => 'MICE and event support for organizations that need premium guest handling, destination texture, and dependable execution.',
|
||||
'audience' => 'Associations, brands, institutions, MICE organizers',
|
||||
'duration' => 'Single activation to multi-day agenda',
|
||||
'outcome' => 'An event environment that feels curated, calm, and professionally managed from transport to closing session.',
|
||||
'includes' => [
|
||||
'Run-of-show design and ecosystem partner alignment',
|
||||
'Guest logistics, transport, and venue operations support',
|
||||
'Curated destination layers for delegates or VIP groups',
|
||||
'Documentation for post-event portfolio use',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'custom-experience',
|
||||
'track' => 'operational',
|
||||
'category' => 'Custom Experience Package',
|
||||
'headline' => 'Flexible program architecture for bespoke briefs.',
|
||||
'summary' => 'A consultative route for institutions or partners who need tailored combinations of wellness, hospitality, logistics, and activation.',
|
||||
'audience' => 'Strategic partners, institutions, multi-stakeholder projects',
|
||||
'duration' => 'Scoped during consultation',
|
||||
'outcome' => 'A custom proposal with the right operating modules, partner map, and delivery assumptions for the brief.',
|
||||
'includes' => [
|
||||
'Discovery call and brief clarification',
|
||||
'Package architecture and ecosystem matchmaking',
|
||||
'Operational assumptions for location, scale, and timing',
|
||||
'Proposal-ready summary to support internal decision-making',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function service_by_slug(string $slug): ?array
|
||||
{
|
||||
foreach (service_catalog() as $service) {
|
||||
if ($service['slug'] === $slug) {
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function default_portfolio_catalog(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'category' => 'Retreat Documentation',
|
||||
'title' => 'Immersive reset for healthcare leaders',
|
||||
'summary' => 'Three-day private retreat with guided wellness, quiet hospitality, and destination movement planning.',
|
||||
'detail' => 'Built around trusted facilitation, transport sequencing, curated dining, and premium guest care.',
|
||||
'metric' => '48 delegates · 3 days · full service coordination',
|
||||
],
|
||||
[
|
||||
'category' => 'Hospitality Activities',
|
||||
'title' => 'Property-based eco wellness activation',
|
||||
'summary' => 'Hospitality collaboration that layered preventive wellness modules into a destination stay offer.',
|
||||
'detail' => 'Designed to expand partner value without disrupting existing property operations.',
|
||||
'metric' => '6 touchpoints · 2 host teams · reusable package model',
|
||||
],
|
||||
[
|
||||
'category' => 'Event Showcase',
|
||||
'title' => 'Institutional offsite with nature-led programming',
|
||||
'summary' => 'Corporate gathering that fused structured sessions, outdoor recovery windows, and logistics support.',
|
||||
'detail' => 'Focused on calm execution, executive-safe service, and documented experience moments.',
|
||||
'metric' => '120 participants · transport + venue + documentation',
|
||||
],
|
||||
[
|
||||
'category' => 'Operational Support',
|
||||
'title' => 'Partner coordination for a multi-vendor destination brief',
|
||||
'summary' => 'Cross-functional partner map covering venue, mobility, hospitality, and merchandise support.',
|
||||
'detail' => 'Organized into clear workstreams to reduce friction and improve delivery certainty.',
|
||||
'metric' => '9 partner lanes · single briefing track · review-ready notes',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function default_partnership_categories(): array
|
||||
{
|
||||
return [
|
||||
['title' => 'Medical Partner', 'summary' => 'Preventive health programs, professional credibility, and trusted wellness positioning.'],
|
||||
['title' => 'Food & Beverage Partner', 'summary' => 'Healthy dining curation, premium service alignment, and guest experience enhancement.'],
|
||||
['title' => 'Hospitality Partner', 'summary' => 'Hotels, villas, and destination stays that want elevated experiential packages.'],
|
||||
['title' => 'Transportation Partner', 'summary' => 'Ground movement, transfer planning, and reliable guest logistics.'],
|
||||
['title' => 'Vendor Partner', 'summary' => 'Operational vendors for events, staging, equipment, or curated supporting services.'],
|
||||
['title' => 'Venue Partner', 'summary' => 'Destination spaces that fit wellness, retreat, and premium gathering formats.'],
|
||||
['title' => 'Merchandise Partner', 'summary' => 'Thoughtful branded items, gifting, and supporting program materials.'],
|
||||
['title' => 'Talent Partner', 'summary' => 'Facilitators, wellness practitioners, speakers, and curated experience talent.'],
|
||||
['title' => 'Facilities Partner', 'summary' => 'Technical, utility, and infrastructure support for safe, smooth delivery.'],
|
||||
];
|
||||
}
|
||||
|
||||
function default_publication_catalog(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'slug' => 'governance-wellness',
|
||||
'category' => 'Whitepaper',
|
||||
'date' => '2026-05-12',
|
||||
'title' => 'Governance as a differentiator in eco wellness operations',
|
||||
'summary' => 'A concise look at why ethical operating systems increase trust in nature-based programs.',
|
||||
'body' => [
|
||||
'Nature-based experiences become institution-ready when governance is visible, practical, and embedded into the delivery model.',
|
||||
'For GBP, governance is not an afterthought. It shapes partner qualification, guest flow, documentation, safety considerations, and post-program reporting.',
|
||||
'Publishing this kind of operational insight helps the website function as both a service platform and a credibility engine for future collaborations.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'hospitality-ecosystem',
|
||||
'category' => 'Strategic Insight',
|
||||
'date' => '2026-04-28',
|
||||
'title' => 'Why hospitality ecosystems outperform isolated program offers',
|
||||
'summary' => 'Integrated destinations create stronger guest journeys when transport, venue, and wellness layers are coordinated early.',
|
||||
'body' => [
|
||||
'Standalone experiences can look attractive in a brochure but collapse under operational pressure when the surrounding ecosystem is weak.',
|
||||
'An integrated hospitality ecosystem aligns venue readiness, movement planning, service staffing, food design, and escalation paths before guests arrive.',
|
||||
'That alignment is what allows a premium minimalist brand like Genitri Ecco Wellness to stay calm, polished, and credible at scale.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'slug' => 'experience-customization',
|
||||
'category' => 'Ecosystem Update',
|
||||
'date' => '2026-03-30',
|
||||
'title' => 'A practical framework for customizing destination experiences',
|
||||
'summary' => 'How inquiry intake, partner matching, and brief translation can stay lightweight while still feeling premium.',
|
||||
'body' => [
|
||||
'Customization is most effective when the intake process captures the essentials: audience, timing, desired outcome, and operating constraints.',
|
||||
'From there, GBP can match the right service modules, partner types, and delivery assumptions without overcomplicating the first conversation.',
|
||||
'This is why the first MVP slice focuses on a strategic inquiry desk that feels both editorial and operational.',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function publication_by_slug(string $slug): ?array
|
||||
{
|
||||
foreach (publication_catalog() as $publication) {
|
||||
if ($publication['slug'] === $slug) {
|
||||
return $publication;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function governance_values(): array
|
||||
{
|
||||
return [
|
||||
['title' => 'Excellence with Integrity', 'summary' => 'Premium execution grounded in transparent standards, safety, and reliable delivery.'],
|
||||
['title' => 'Shared Value Creation', 'summary' => 'Programs and partnerships designed to benefit guests, collaborators, and the wider ecosystem.'],
|
||||
['title' => 'Sustainable Equilibrium', 'summary' => 'Nature, hospitality, and operations balanced with long-term resilience in mind.'],
|
||||
];
|
||||
}
|
||||
|
||||
function objective_list(): array
|
||||
{
|
||||
return [
|
||||
'Build institutional trust',
|
||||
'Showcase operational capability',
|
||||
'Open strategic partnership routes',
|
||||
'Generate qualified inquiry',
|
||||
'Provide curated package services',
|
||||
'Enable experience customization',
|
||||
'Display ecosystem portfolio',
|
||||
'Build publication authority',
|
||||
'Prepare governance infrastructure',
|
||||
];
|
||||
}
|
||||
|
||||
function inquiry_type_options(): array
|
||||
{
|
||||
return [
|
||||
'Strategic Partnership',
|
||||
'Package Customization',
|
||||
'Operational Collaboration',
|
||||
'Publication / Media',
|
||||
];
|
||||
}
|
||||
|
||||
function interest_groups(): array
|
||||
{
|
||||
$services = [];
|
||||
foreach (service_catalog() as $service) {
|
||||
$services[] = $service['category'];
|
||||
}
|
||||
|
||||
$partners = [];
|
||||
foreach (partnership_categories() as $partner) {
|
||||
$partners[] = $partner['title'];
|
||||
}
|
||||
|
||||
return [
|
||||
'Curated Programs' => $services,
|
||||
'Partnership Routes' => $partners,
|
||||
];
|
||||
}
|
||||
|
||||
function scale_options(): array
|
||||
{
|
||||
return [
|
||||
'Private group (10–30)',
|
||||
'Team offsite (31–80)',
|
||||
'Corporate / MICE (81–200)',
|
||||
'Multi-site activation (200+)',
|
||||
];
|
||||
}
|
||||
|
||||
function location_options(): array
|
||||
{
|
||||
return [
|
||||
'Tegal / Bregas corridor',
|
||||
'Central Java destination',
|
||||
'Partner property or venue',
|
||||
'To be discussed during scoping',
|
||||
];
|
||||
}
|
||||
|
||||
function active_class(string $activePage, string $key): string
|
||||
{
|
||||
return $activePage === $key ? 'active' : '';
|
||||
}
|
||||
|
||||
function current_year(): string
|
||||
{
|
||||
return gmdate('Y');
|
||||
}
|
||||
|
||||
function csrf_token(): string
|
||||
{
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
|
||||
}
|
||||
|
||||
return $_SESSION['csrf_token'];
|
||||
}
|
||||
|
||||
function verify_csrf_token(?string $token): bool
|
||||
{
|
||||
return is_string($token) && hash_equals($_SESSION['csrf_token'] ?? '', $token);
|
||||
}
|
||||
|
||||
function flash_set(string $type, string $message): void
|
||||
{
|
||||
$_SESSION['flash'] = [
|
||||
'type' => $type,
|
||||
'message' => $message,
|
||||
];
|
||||
}
|
||||
|
||||
function flash_get(): ?array
|
||||
{
|
||||
if (empty($_SESSION['flash']) || !is_array($_SESSION['flash'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$flash = $_SESSION['flash'];
|
||||
unset($_SESSION['flash']);
|
||||
|
||||
return $flash;
|
||||
}
|
||||
|
||||
function old_value(array $source, string $key, string $fallback = ''): string
|
||||
{
|
||||
$value = $source[$key] ?? $fallback;
|
||||
return trim((string) $value);
|
||||
}
|
||||
|
||||
function is_selected(?string $candidate, ?string $value): string
|
||||
{
|
||||
return ((string) $candidate === (string) $value) ? 'selected' : '';
|
||||
}
|
||||
|
||||
function app_db_connection(): ?PDO
|
||||
{
|
||||
static $attempted = false;
|
||||
static $pdo = null;
|
||||
static $error = null;
|
||||
|
||||
if ($attempted) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
$attempted = true;
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$error = null;
|
||||
} catch (Throwable $exception) {
|
||||
$pdo = null;
|
||||
$error = $exception->getMessage();
|
||||
}
|
||||
|
||||
$GLOBALS['APP_DB_ERROR'] = $error;
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
function app_db_error(): ?string
|
||||
{
|
||||
app_db_connection();
|
||||
$error = $GLOBALS['APP_DB_ERROR'] ?? null;
|
||||
return is_string($error) && $error !== '' ? $error : null;
|
||||
}
|
||||
|
||||
function using_preview_storage(): bool
|
||||
{
|
||||
return app_db_connection() === null;
|
||||
}
|
||||
|
||||
function inquiry_table_sql(): string
|
||||
{
|
||||
return <<<'SQL'
|
||||
CREATE TABLE IF NOT EXISTS ecosystem_inquiries (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
reference_code VARCHAR(32) NOT NULL UNIQUE,
|
||||
inquiry_type VARCHAR(80) NOT NULL,
|
||||
interest_area VARCHAR(120) NOT NULL,
|
||||
contact_name VARCHAR(120) NOT NULL,
|
||||
organization_name VARCHAR(160) NOT NULL,
|
||||
email VARCHAR(160) NOT NULL,
|
||||
phone VARCHAR(40) DEFAULT NULL,
|
||||
target_date VARCHAR(40) DEFAULT NULL,
|
||||
event_scale VARCHAR(80) DEFAULT NULL,
|
||||
preferred_location VARCHAR(120) DEFAULT NULL,
|
||||
notes TEXT NOT NULL,
|
||||
status VARCHAR(30) NOT NULL DEFAULT 'New',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_status_created (status, created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
SQL;
|
||||
}
|
||||
|
||||
function ensure_inquiry_table(): bool
|
||||
{
|
||||
static $ensured = false;
|
||||
|
||||
if ($ensured) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$pdo = app_db_connection();
|
||||
if (!$pdo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo->exec(inquiry_table_sql());
|
||||
$ensured = true;
|
||||
return true;
|
||||
} catch (Throwable $exception) {
|
||||
$GLOBALS['APP_DB_ERROR'] = $exception->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function normalize_multiline(string $value): string
|
||||
{
|
||||
$normalized = preg_replace("/\r\n?|\r/", "\n", $value);
|
||||
$normalized = preg_replace("/\n{3,}/", "\n\n", (string) $normalized);
|
||||
return trim((string) $normalized);
|
||||
}
|
||||
|
||||
function validate_inquiry(array $input): array
|
||||
{
|
||||
$data = [
|
||||
'inquiry_type' => trim((string) ($input['inquiry_type'] ?? '')),
|
||||
'interest_area' => trim((string) ($input['interest_area'] ?? '')),
|
||||
'contact_name' => trim((string) ($input['contact_name'] ?? '')),
|
||||
'organization_name' => trim((string) ($input['organization_name'] ?? '')),
|
||||
'email' => trim((string) ($input['email'] ?? '')),
|
||||
'phone' => trim((string) ($input['phone'] ?? '')),
|
||||
'target_date' => trim((string) ($input['target_date'] ?? '')),
|
||||
'event_scale' => trim((string) ($input['event_scale'] ?? '')),
|
||||
'preferred_location' => trim((string) ($input['preferred_location'] ?? '')),
|
||||
'notes' => normalize_multiline((string) ($input['notes'] ?? '')),
|
||||
];
|
||||
|
||||
$errors = [];
|
||||
|
||||
if ($data['inquiry_type'] === '') {
|
||||
$errors['inquiry_type'] = 'Choose the type of collaboration you want to discuss.';
|
||||
}
|
||||
|
||||
if ($data['interest_area'] === '') {
|
||||
$errors['interest_area'] = 'Select the package or partnership route that best matches your brief.';
|
||||
}
|
||||
|
||||
if ($data['contact_name'] === '') {
|
||||
$errors['contact_name'] = 'Add the primary contact name.';
|
||||
}
|
||||
|
||||
if ($data['organization_name'] === '') {
|
||||
$errors['organization_name'] = 'Add the company or organization name.';
|
||||
}
|
||||
|
||||
if ($data['email'] === '' || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$errors['email'] = 'Use a valid email address so the team can respond.';
|
||||
}
|
||||
|
||||
if ($data['notes'] === '') {
|
||||
$errors['notes'] = 'Describe the program scope, partner intent, or operational need.';
|
||||
} elseif (text_length($data['notes']) < 24) {
|
||||
$errors['notes'] = 'Add a little more detail so the brief is useful for review.';
|
||||
} elseif (text_length($data['notes']) > 900) {
|
||||
$errors['notes'] = 'Keep the brief under 900 characters for this first intake step.';
|
||||
}
|
||||
|
||||
if ($data['phone'] !== '' && text_length($data['phone']) > 40) {
|
||||
$errors['phone'] = 'Phone number is too long.';
|
||||
}
|
||||
|
||||
if ($data['target_date'] !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $data['target_date'])) {
|
||||
$errors['target_date'] = 'Use a valid preferred date.';
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'errors' => $errors,
|
||||
];
|
||||
}
|
||||
|
||||
function generate_reference_code(): string
|
||||
{
|
||||
return 'GBP-' . gmdate('ymd') . '-' . strtoupper(bin2hex(random_bytes(2)));
|
||||
}
|
||||
|
||||
function save_inquiry(array $input): array
|
||||
{
|
||||
$validated = validate_inquiry($input);
|
||||
$data = $validated['data'];
|
||||
$errors = $validated['errors'];
|
||||
|
||||
if ($errors !== []) {
|
||||
return [
|
||||
'success' => false,
|
||||
'errors' => $errors,
|
||||
'data' => $data,
|
||||
];
|
||||
}
|
||||
|
||||
$inquiry = $data;
|
||||
$inquiry['reference_code'] = generate_reference_code();
|
||||
$inquiry['status'] = 'New';
|
||||
$inquiry['created_at'] = gmdate('Y-m-d H:i:s');
|
||||
|
||||
if (ensure_inquiry_table()) {
|
||||
try {
|
||||
$pdo = app_db_connection();
|
||||
if ($pdo instanceof PDO) {
|
||||
$statement = $pdo->prepare(
|
||||
'INSERT INTO ecosystem_inquiries
|
||||
(reference_code, inquiry_type, interest_area, contact_name, organization_name, email, phone, target_date, event_scale, preferred_location, notes, status)
|
||||
VALUES
|
||||
(:reference_code, :inquiry_type, :interest_area, :contact_name, :organization_name, :email, :phone, :target_date, :event_scale, :preferred_location, :notes, :status)'
|
||||
);
|
||||
|
||||
$statement->bindValue(':reference_code', $inquiry['reference_code']);
|
||||
$statement->bindValue(':inquiry_type', $inquiry['inquiry_type']);
|
||||
$statement->bindValue(':interest_area', $inquiry['interest_area']);
|
||||
$statement->bindValue(':contact_name', $inquiry['contact_name']);
|
||||
$statement->bindValue(':organization_name', $inquiry['organization_name']);
|
||||
$statement->bindValue(':email', $inquiry['email']);
|
||||
$statement->bindValue(':phone', $inquiry['phone'] ?: null, $inquiry['phone'] === '' ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||
$statement->bindValue(':target_date', $inquiry['target_date'] ?: null, $inquiry['target_date'] === '' ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||
$statement->bindValue(':event_scale', $inquiry['event_scale'] ?: null, $inquiry['event_scale'] === '' ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||
$statement->bindValue(':preferred_location', $inquiry['preferred_location'] ?: null, $inquiry['preferred_location'] === '' ? PDO::PARAM_NULL : PDO::PARAM_STR);
|
||||
$statement->bindValue(':notes', $inquiry['notes']);
|
||||
$statement->bindValue(':status', $inquiry['status']);
|
||||
$statement->execute();
|
||||
|
||||
$inquiry['id'] = (int) $pdo->lastInsertId();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'inquiry' => $inquiry,
|
||||
'storage' => 'database',
|
||||
];
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
$GLOBALS['APP_DB_ERROR'] = $exception->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION['preview_inquiries'] = $_SESSION['preview_inquiries'] ?? [];
|
||||
$_SESSION['preview_inquiry_counter'] = (int) ($_SESSION['preview_inquiry_counter'] ?? 0) + 1;
|
||||
$inquiry['id'] = (int) $_SESSION['preview_inquiry_counter'];
|
||||
$_SESSION['preview_inquiries'][$inquiry['reference_code']] = $inquiry;
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'inquiry' => $inquiry,
|
||||
'storage' => 'session',
|
||||
'warning' => 'Database connectivity is not available, so this submission is stored only for the current preview session.',
|
||||
];
|
||||
}
|
||||
|
||||
function session_inquiries(): array
|
||||
{
|
||||
$items = array_values($_SESSION['preview_inquiries'] ?? []);
|
||||
usort($items, static fn (array $left, array $right): int => strcmp($right['created_at'], $left['created_at']));
|
||||
return $items;
|
||||
}
|
||||
|
||||
function list_inquiries(): array
|
||||
{
|
||||
if (ensure_inquiry_table()) {
|
||||
try {
|
||||
$pdo = app_db_connection();
|
||||
if ($pdo instanceof PDO) {
|
||||
$statement = $pdo->query('SELECT * FROM ecosystem_inquiries ORDER BY created_at DESC, id DESC LIMIT 50');
|
||||
return $statement->fetchAll() ?: [];
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
$GLOBALS['APP_DB_ERROR'] = $exception->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return session_inquiries();
|
||||
}
|
||||
|
||||
function find_inquiry(?int $id = null, ?string $reference = null): ?array
|
||||
{
|
||||
if (ensure_inquiry_table()) {
|
||||
try {
|
||||
$pdo = app_db_connection();
|
||||
if ($pdo instanceof PDO) {
|
||||
if ($reference !== null && $reference !== '') {
|
||||
$statement = $pdo->prepare('SELECT * FROM ecosystem_inquiries WHERE reference_code = :reference LIMIT 1');
|
||||
$statement->bindValue(':reference', $reference);
|
||||
$statement->execute();
|
||||
$found = $statement->fetch();
|
||||
return is_array($found) ? $found : null;
|
||||
}
|
||||
|
||||
if ($id !== null && $id > 0) {
|
||||
$statement = $pdo->prepare('SELECT * FROM ecosystem_inquiries WHERE id = :id LIMIT 1');
|
||||
$statement->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$statement->execute();
|
||||
$found = $statement->fetch();
|
||||
return is_array($found) ? $found : null;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
$GLOBALS['APP_DB_ERROR'] = $exception->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (session_inquiries() as $item) {
|
||||
if (($reference !== null && $reference !== '' && $item['reference_code'] === $reference) || ($id !== null && (int) $item['id'] === $id)) {
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function format_date_label(?string $date): string
|
||||
{
|
||||
$value = trim((string) $date);
|
||||
if ($value === '') {
|
||||
return 'To be coordinated';
|
||||
}
|
||||
|
||||
try {
|
||||
return (new DateTimeImmutable($value))->format('j M Y');
|
||||
} catch (Throwable) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
69
includes/footer.php
Normal file
69
includes/footer.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
$flash = flash_get();
|
||||
$jsVersion = (string) (@filemtime(__DIR__ . '/../assets/js/main.js') ?: time());
|
||||
$storageMode = using_preview_storage() ? 'Preview session storage' : 'Database-backed inquiry desk';
|
||||
?>
|
||||
</main>
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<div class="row g-4 justify-content-between">
|
||||
<div class="col-lg-4">
|
||||
<p class="footer-kicker">Genitri Ecco Wellness</p>
|
||||
<h2 class="footer-title">Integrated nature-based experience ecosystem.</h2>
|
||||
<p class="footer-copy">A premium minimalist platform for eco wellness, experiential tourism, hospitality collaboration, and qualified strategic inquiry.</p>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-2">
|
||||
<p class="footer-label">Navigation</p>
|
||||
<ul class="footer-links">
|
||||
<?php foreach (navigation_items() as $item): ?>
|
||||
<li><a href="<?= h($item['href']) ?>"><?= h($item['label']) ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<p class="footer-label">Operational focus</p>
|
||||
<ul class="footer-links footer-links--muted">
|
||||
<li>Eco wellness</li>
|
||||
<li>Retreat and immersive experiences</li>
|
||||
<li>Hospitality ecosystem and MICE support</li>
|
||||
<li>Partnership and governance readiness</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<p class="footer-label">System</p>
|
||||
<ul class="footer-links">
|
||||
<li><a href="admin.php">Preview desk</a></li>
|
||||
<li><a href="healthz.php">Health check</a></li>
|
||||
<li class="footer-note"><?= h($storageMode) ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bar">
|
||||
<span>© <?= h(current_year()) ?> PT. Genitri Bregas Persada</span>
|
||||
<span>Genitri Ecco Wellness · <?= h(site_tagline()) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<?php if ($flash):
|
||||
$toastClass = match ($flash['type']) {
|
||||
'success' => 'text-bg-success',
|
||||
'warning' => 'text-bg-warning',
|
||||
'danger' => 'text-bg-danger',
|
||||
default => 'text-bg-primary',
|
||||
};
|
||||
?>
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div class="toast align-items-center border-0 <?= h($toastClass) ?>" role="status" aria-live="polite" aria-atomic="true">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="toast-body"><?= h($flash['message']) ?></div>
|
||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?= h($jsVersion) ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
71
includes/header.php
Normal file
71
includes/header.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/app.php';
|
||||
|
||||
$pageTitle = $pageTitle ?? site_name();
|
||||
$pageDescription = $pageDescription ?? default_meta_description();
|
||||
$activePage = $activePage ?? '';
|
||||
$pageRobots = $pageRobots ?? '';
|
||||
$bodyClass = $bodyClass ?? '';
|
||||
|
||||
$projectName = app_env('PROJECT_NAME', site_name());
|
||||
$projectDescription = app_env('PROJECT_DESCRIPTION', $pageDescription);
|
||||
$projectImageUrl = app_env('PROJECT_IMAGE_URL', '');
|
||||
$fullTitle = trim($pageTitle) === $projectName ? $projectName : $pageTitle . ' | ' . $projectName;
|
||||
$cssVersion = (string) (@filemtime(__DIR__ . '/../assets/css/custom.css') ?: time());
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?= h($fullTitle) ?></title>
|
||||
<meta name="description" content="<?= h($pageDescription ?: $projectDescription) ?>">
|
||||
<?php if ($pageRobots): ?>
|
||||
<meta name="robots" content="<?= h($pageRobots) ?>">
|
||||
<?php endif; ?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<meta property="og:description" content="<?= h($projectDescription) ?>">
|
||||
<meta property="twitter:description" content="<?= h($projectDescription) ?>">
|
||||
<?php endif; ?>
|
||||
<meta property="og:title" content="<?= h($fullTitle) ?>">
|
||||
<meta property="twitter:title" content="<?= h($fullTitle) ?>">
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<meta property="og:image" content="<?= h($projectImageUrl) ?>">
|
||||
<meta property="twitter:image" content="<?= h($projectImageUrl) ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?= h($cssVersion) ?>">
|
||||
</head>
|
||||
<body class="<?= h($bodyClass) ?>">
|
||||
<a class="skip-link" href="#main-content">Skip to content</a>
|
||||
<header class="site-header">
|
||||
<nav class="navbar navbar-expand-lg fixed-top site-navbar" aria-label="Primary navigation">
|
||||
<div class="container">
|
||||
<a class="navbar-brand brand-mark" href="index.php">
|
||||
<span class="brand-mark__eyebrow">PT. Genitri Bregas Persada</span>
|
||||
<span class="brand-mark__title">Genitri Ecco Wellness</span>
|
||||
</a>
|
||||
<button class="navbar-toggler border-0 shadow-none" type="button" data-bs-toggle="collapse" data-bs-target="#siteNavbar" aria-controls="siteNavbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="siteNavbar">
|
||||
<ul class="navbar-nav ms-auto align-items-lg-center gap-lg-2">
|
||||
<?php foreach (navigation_items() as $item): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= h(active_class($activePage, $item['key'])) ?>" href="<?= h($item['href']) ?>"><?= h($item['label']) ?></a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
<li class="nav-item ms-lg-2">
|
||||
<a class="btn btn-brand btn-sm px-3" href="partnership.php">Strategic Inquiry</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main id="main-content" class="page-main">
|
||||
396
index.php
396
index.php
@ -1,150 +1,256 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Integrated Nature-Based Experience Ecosystem';
|
||||
$pageDescription = 'Institutional gateway for eco wellness, experiential tourism, hospitality collaboration, and strategic partnership.';
|
||||
$activePage = 'home';
|
||||
|
||||
$services = service_catalog();
|
||||
$portfolioItems = portfolio_catalog();
|
||||
$publications = publication_catalog();
|
||||
$partners = partnership_categories();
|
||||
$values = governance_values();
|
||||
|
||||
$ecosystemModules = [
|
||||
['title' => 'Eco wellness', 'summary' => 'Preventive programs with calm pacing, guided facilitation, and premium care.'],
|
||||
['title' => 'Retreat experiences', 'summary' => 'Immersive multi-day journeys built around clarity, reflection, and quiet hospitality.'],
|
||||
['title' => 'Hospitality collaboration', 'summary' => 'Package overlays for properties and destination operators seeking premium experience value.'],
|
||||
['title' => 'Transportation & logistics', 'summary' => 'Guest movement, timing, contingency, and arrival sequencing that reduce operational friction.'],
|
||||
['title' => 'Vendor & venue ecosystem', 'summary' => 'Curated supporting partners for staging, equipment, venues, and specialist services.'],
|
||||
['title' => 'Event & MICE', 'summary' => 'Institutional-grade events that still feel experiential, calm, and human-centered.'],
|
||||
['title' => 'Partnership collaboration', 'summary' => 'Strategic lanes for medical, hospitality, logistics, and ecosystem partners.'],
|
||||
['title' => 'Publications & governance', 'summary' => 'Editorial authority, reporting discipline, and trust-building operational narratives.'],
|
||||
];
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<?php
|
||||
// Read project preview data from environment
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<!-- Meta description -->
|
||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<!-- Twitter meta tags -->
|
||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<!-- Open Graph image -->
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<!-- Twitter image -->
|
||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
</div>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-7">
|
||||
<span class="eyebrow">Institutional experience gateway</span>
|
||||
<h1 class="display-title">Integrated Nature-Based Experience Ecosystem</h1>
|
||||
<p class="lead-copy mb-4">Eco wellness, experiential tourism, hospitality collaboration, and strategic ecosystem partnership—structured in a premium, operationally credible format.</p>
|
||||
<div class="d-flex flex-wrap gap-2 inline-actions">
|
||||
<a class="btn btn-brand" href="partnership.php">Jalin Kemitraan Strategis</a>
|
||||
<a class="btn btn-outline-brand" href="services.php">Explore Services</a>
|
||||
</div>
|
||||
<div class="metric-strip mt-4">
|
||||
<div class="metric-card">
|
||||
<span class="metric-value">6 curated programs</span>
|
||||
<span class="metric-label">Wellness, retreat, corporate, hospitality, MICE, and custom experiences.</span>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span class="metric-value">9 partner lanes</span>
|
||||
<span class="metric-label">From medical and F&B collaboration to venue, vendor, and facilities support.</span>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span class="metric-value">1 integrated desk</span>
|
||||
<span class="metric-label">A thin-slice inquiry flow that turns interest into a review-ready brief.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="surface-card hero-panel h-100">
|
||||
<p class="panel-label">Operational lens</p>
|
||||
<div class="stack-list">
|
||||
<div class="stack-item">
|
||||
<span>Curated services</span>
|
||||
<small>Program architecture with premium restraint and clear delivery assumptions.</small>
|
||||
</div>
|
||||
<div class="stack-item">
|
||||
<span>Partner ecosystem</span>
|
||||
<small>Healthcare, hospitality, logistics, vendor, venue, and talent collaboration lanes.</small>
|
||||
</div>
|
||||
<div class="stack-item">
|
||||
<span>Governance foundation</span>
|
||||
<small>Editorial trust, qualification, and documented operations.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<p class="meta-inline mb-2">First delivery focus</p>
|
||||
<a class="button-link" href="partnership.php">Open the strategic inquiry desk</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="section-kicker">Ecosystem overview</span>
|
||||
<h2 class="section-title">An editorial, trust-first way to present a complex operating ecosystem.</h2>
|
||||
<p class="section-copy">The first release turns the masterplan into a professional front-of-house shell: clear structure, premium pacing, and an immediate path to a qualified inquiry.</p>
|
||||
</div>
|
||||
<div class="capability-grid">
|
||||
<?php foreach ($ecosystemModules as $module): ?>
|
||||
<article class="surface-card">
|
||||
<span class="signal-chip signal-chip--primary mb-3">Capability</span>
|
||||
<h3 class="card-title"><?= h($module['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($module['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3 align-items-lg-end section-head mb-4">
|
||||
<div>
|
||||
<span class="section-kicker">Package programs</span>
|
||||
<h2 class="section-title">Curated programs that feel premium, specific, and consultation-ready.</h2>
|
||||
<p class="section-copy">Each package links directly into the inquiry workflow, so a visitor can browse, shortlist, and send a structured brief in one flow.</p>
|
||||
</div>
|
||||
<a class="button-link" href="services.php">View all service packages</a>
|
||||
</div>
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($services as $service): ?>
|
||||
<article class="surface-card service-card">
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-between align-items-start">
|
||||
<span class="signal-chip signal-chip--accent"><?= h($service['track']) ?></span>
|
||||
<span class="meta-inline"><?= h($service['duration']) ?></span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="card-title"><?= h($service['category']) ?></h3>
|
||||
<p class="card-copy mb-2"><?= h($service['summary']) ?></p>
|
||||
<p class="meta-inline mb-0"><strong>Best for:</strong> <?= h($service['audience']) ?></p>
|
||||
</div>
|
||||
<ul class="service-points">
|
||||
<?php foreach (array_slice($service['includes'], 0, 3) as $point): ?>
|
||||
<li><?= h($point) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<div class="d-flex flex-wrap gap-2 mt-auto inline-actions">
|
||||
<a class="btn btn-outline-brand btn-sm" href="<?= h(page_url('service.php', ['slug' => $service['slug']])) ?>">Package detail</a>
|
||||
<a class="btn btn-brand btn-sm" href="<?= h(page_url('partnership.php', ['interest' => $service['category'], 'route' => 'Package Customization'])) ?>">Customize Experience</a>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3 align-items-lg-end section-head mb-4">
|
||||
<div>
|
||||
<span class="section-kicker">Portfolio showcase</span>
|
||||
<h2 class="section-title">A portfolio layer that demonstrates delivery capability—not just visual mood.</h2>
|
||||
<p class="section-copy">The content is structured like an institutional case reel: concise, premium, and tied to operational signals.</p>
|
||||
</div>
|
||||
<a class="button-link" href="portfolio.php">Explore portfolio</a>
|
||||
</div>
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($portfolioItems as $item): ?>
|
||||
<article class="surface-card service-card">
|
||||
<span class="signal-chip signal-chip--gold mb-2"><?= h($item['category']) ?></span>
|
||||
<div>
|
||||
<h3 class="card-title"><?= h($item['title']) ?></h3>
|
||||
<p class="card-copy mb-2"><?= h($item['summary']) ?></p>
|
||||
<p class="meta-inline mb-0"><?= h($item['metric']) ?></p>
|
||||
</div>
|
||||
<p class="card-copy mb-0"><?= h($item['detail']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="section-kicker">Open partnership</span>
|
||||
<h2 class="section-title">Strategic lanes for ecosystem growth.</h2>
|
||||
<p class="section-copy">The first MVP centers on partnership discovery because it creates immediate business value: a clear path from browsing to qualified conversation.</p>
|
||||
</div>
|
||||
<div class="partner-grid">
|
||||
<?php foreach ($partners as $partner): ?>
|
||||
<article class="surface-card service-card">
|
||||
<h3 class="card-title"><?= h($partner['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($partner['summary']) ?></p>
|
||||
<div class="mt-auto">
|
||||
<a class="button-link" href="<?= h(page_url('partnership.php', ['interest' => $partner['title'], 'route' => 'Strategic Partnership'])) ?>">Become ecosystem partner</a>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3 align-items-lg-end section-head mb-4">
|
||||
<div>
|
||||
<span class="section-kicker">Publications</span>
|
||||
<h2 class="section-title">Editorial authority that supports institutional trust.</h2>
|
||||
<p class="section-copy">A lightweight publication layer allows GBP to document insight, signal capability, and keep the ecosystem narrative alive.</p>
|
||||
</div>
|
||||
<a class="button-link" href="publications.php">Explore publications</a>
|
||||
</div>
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($publications as $publication): ?>
|
||||
<article class="surface-card service-card">
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-between align-items-start">
|
||||
<span class="signal-chip"><?= h($publication['category']) ?></span>
|
||||
<span class="meta-inline"><?= h(format_date_label($publication['date'])) ?></span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="card-title"><?= h($publication['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($publication['summary']) ?></p>
|
||||
</div>
|
||||
<div class="mt-auto">
|
||||
<a class="button-link" href="<?= h(page_url('publication.php', ['slug' => $publication['slug']])) ?>">Read publication</a>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section">
|
||||
<div class="container">
|
||||
<div class="dark-block">
|
||||
<div class="section-head mb-4">
|
||||
<span class="section-kicker text-white">Governance & values</span>
|
||||
<h2 class="section-title text-white">Excellence, shared value, and sustainable equilibrium.</h2>
|
||||
<p class="section-copy text-white opacity-75">A dark premium block gives governance the weight it deserves, so the brand feels serious, stable, and ethically grounded.</p>
|
||||
</div>
|
||||
<div class="dark-grid">
|
||||
<?php foreach ($values as $value): ?>
|
||||
<article class="surface-card surface-card--dark">
|
||||
<span class="signal-chip signal-chip--gold mb-3">Value</span>
|
||||
<h3 class="card-title"><?= h($value['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($value['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section pt-0">
|
||||
<div class="container">
|
||||
<div class="hero-shell">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<span class="section-kicker">Contact CTA</span>
|
||||
<h2 class="section-title">Schedule a strategic discussion.</h2>
|
||||
<p class="section-copy mb-0">Use the inquiry desk to define the package, partner route, scale, and target timing. The submission is then visible in the preview desk for follow-up review.</p>
|
||||
</div>
|
||||
<div class="col-lg-4 text-lg-end">
|
||||
<div class="d-grid gap-2">
|
||||
<a class="btn btn-brand" href="partnership.php">Open Partnership Inquiry</a>
|
||||
<a class="btn btn-outline-brand" href="contact.php">Contact guidance</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
272
partnership.php
Normal file
272
partnership.php
Normal file
@ -0,0 +1,272 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Partnership';
|
||||
$pageDescription = 'Strategic partnership intake for curated programs, ecosystem collaboration, and customized experience briefs.';
|
||||
$activePage = 'partnership';
|
||||
|
||||
$formData = [
|
||||
'inquiry_type' => trim((string) ($_GET['route'] ?? '')),
|
||||
'interest_area' => trim((string) ($_GET['interest'] ?? '')),
|
||||
'contact_name' => '',
|
||||
'organization_name' => '',
|
||||
'email' => '',
|
||||
'phone' => '',
|
||||
'target_date' => '',
|
||||
'event_scale' => '',
|
||||
'preferred_location' => '',
|
||||
'notes' => '',
|
||||
];
|
||||
$errors = [];
|
||||
$confirmation = null;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$submittedData = [
|
||||
'inquiry_type' => trim((string) ($_POST['inquiry_type'] ?? '')),
|
||||
'interest_area' => trim((string) ($_POST['interest_area'] ?? '')),
|
||||
'contact_name' => trim((string) ($_POST['contact_name'] ?? '')),
|
||||
'organization_name' => trim((string) ($_POST['organization_name'] ?? '')),
|
||||
'email' => trim((string) ($_POST['email'] ?? '')),
|
||||
'phone' => trim((string) ($_POST['phone'] ?? '')),
|
||||
'target_date' => trim((string) ($_POST['target_date'] ?? '')),
|
||||
'event_scale' => trim((string) ($_POST['event_scale'] ?? '')),
|
||||
'preferred_location' => trim((string) ($_POST['preferred_location'] ?? '')),
|
||||
'notes' => trim((string) ($_POST['notes'] ?? '')),
|
||||
];
|
||||
|
||||
$formData = $submittedData;
|
||||
|
||||
if (!verify_csrf_token($_POST['csrf_token'] ?? null)) {
|
||||
$errors['form'] = 'Your session expired. Please refresh and submit the inquiry again.';
|
||||
} else {
|
||||
$result = save_inquiry($_POST);
|
||||
if (!empty($result['success'])) {
|
||||
if (!empty($result['warning'])) {
|
||||
flash_set('warning', $result['warning']);
|
||||
} else {
|
||||
flash_set('success', 'Inquiry submitted. The preview desk now has a new review item.');
|
||||
}
|
||||
header('Location: ' . page_url('partnership.php', ['reference' => $result['inquiry']['reference_code']]));
|
||||
exit;
|
||||
}
|
||||
|
||||
$errors = $result['errors'] ?? ['form' => 'Something went wrong while saving the inquiry.'];
|
||||
$formData = $result['data'] ?? $formData;
|
||||
}
|
||||
}
|
||||
|
||||
$reference = trim((string) ($_GET['reference'] ?? ''));
|
||||
if ($reference !== '') {
|
||||
$confirmation = find_inquiry(null, $reference);
|
||||
if (!$confirmation) {
|
||||
$errors['lookup'] = 'That reference could not be located yet. Try submitting a fresh inquiry.';
|
||||
}
|
||||
}
|
||||
|
||||
$previewMode = using_preview_storage();
|
||||
$interestGroups = interest_groups();
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell page-intro">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<span class="section-kicker">Strategic inquiry desk</span>
|
||||
<h1 class="page-title">Capture a qualified partnership or experience brief in one clean flow.</h1>
|
||||
<p class="lead-copy mb-0">The form collects just enough detail to feel operational: collaboration route, selected package or partner lane, timing, scale, and a narrative brief.</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="surface-card hero-panel h-100">
|
||||
<span class="signal-chip signal-chip--primary mb-3">What happens next</span>
|
||||
<ul class="value-list mb-0">
|
||||
<li>Submit the structured brief.</li>
|
||||
<li>Receive a reference code and confirmation summary.</li>
|
||||
<li>Open the preview desk to review the saved inquiry.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($previewMode): ?>
|
||||
<div class="notice-banner notice-banner--warning mb-4">
|
||||
<strong>Preview mode:</strong> database connectivity is currently unavailable, so new inquiries are stored only for this browser session while the workflow is being validated.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($errors['form']) || !empty($errors['lookup'])): ?>
|
||||
<div class="inline-alert notice-banner--warning mb-4">
|
||||
<?= h($errors['form'] ?? $errors['lookup']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($confirmation): ?>
|
||||
<div class="surface-card mb-4 anchor-offset">
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-between gap-3 align-items-lg-start">
|
||||
<div>
|
||||
<span class="section-kicker">Confirmation</span>
|
||||
<h2 class="section-title mb-2">Inquiry received and routed.</h2>
|
||||
<p class="section-copy mb-0">Use the reference below for follow-up and internal review.</p>
|
||||
</div>
|
||||
<div class="copy-inline">
|
||||
<span class="signal-chip signal-chip--gold" id="referenceCode"><?= h($confirmation['reference_code']) ?></span>
|
||||
<button class="btn btn-subtle btn-sm" type="button" data-copy-target="#referenceCode">Copy reference</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-meta mt-4">
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Inquiry type</span>
|
||||
<strong><?= h($confirmation['inquiry_type']) ?></strong>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Selected interest</span>
|
||||
<strong><?= h($confirmation['interest_area']) ?></strong>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Organization</span>
|
||||
<strong><?= h($confirmation['organization_name']) ?></strong>
|
||||
</div>
|
||||
<div class="meta-block">
|
||||
<span class="meta-label">Preferred date</span>
|
||||
<strong><?= h(format_date_label($confirmation['target_date'] ?? '')) ?></strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 mt-4 inline-actions">
|
||||
<a class="btn btn-brand" href="<?= h(page_url('admin.php', ['reference' => $confirmation['reference_code']])) ?>">Open preview desk</a>
|
||||
<a class="btn btn-outline-brand" href="partnership.php">Submit another inquiry</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="row g-4 align-items-start">
|
||||
<div class="col-lg-7">
|
||||
<div class="form-panel">
|
||||
<div class="d-flex justify-content-between gap-3 align-items-start mb-3">
|
||||
<div>
|
||||
<span class="section-kicker">Brief form</span>
|
||||
<h2 class="section-title">Create inquiry</h2>
|
||||
</div>
|
||||
<span class="signal-chip">Step 1 of 1</span>
|
||||
</div>
|
||||
<form method="post" novalidate>
|
||||
<input type="hidden" name="csrf_token" value="<?= h(csrf_token()) ?>">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="inquiry_type">Inquiry type</label>
|
||||
<select class="form-select <?= !empty($errors['inquiry_type']) ? 'is-invalid' : '' ?>" id="inquiry_type" name="inquiry_type">
|
||||
<option value="">Select route</option>
|
||||
<?php foreach (inquiry_type_options() as $option): ?>
|
||||
<option value="<?= h($option) ?>" <?= is_selected($option, old_value($formData, 'inquiry_type')) ?>><?= h($option) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<div class="invalid-feedback"><?= h($errors['inquiry_type'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="interest_area">Interest area</label>
|
||||
<select class="form-select <?= !empty($errors['interest_area']) ? 'is-invalid' : '' ?>" id="interest_area" name="interest_area">
|
||||
<option value="">Choose package or partner lane</option>
|
||||
<?php foreach ($interestGroups as $label => $options): ?>
|
||||
<optgroup label="<?= h($label) ?>">
|
||||
<?php foreach ($options as $option): ?>
|
||||
<option value="<?= h($option) ?>" <?= is_selected($option, old_value($formData, 'interest_area')) ?>><?= h($option) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<div class="invalid-feedback"><?= h($errors['interest_area'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="contact_name">Primary contact</label>
|
||||
<input class="form-control <?= !empty($errors['contact_name']) ? 'is-invalid' : '' ?>" id="contact_name" name="contact_name" value="<?= h(old_value($formData, 'contact_name')) ?>" maxlength="120" placeholder="Full name">
|
||||
<div class="invalid-feedback"><?= h($errors['contact_name'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="organization_name">Company / organization</label>
|
||||
<input class="form-control <?= !empty($errors['organization_name']) ? 'is-invalid' : '' ?>" id="organization_name" name="organization_name" value="<?= h(old_value($formData, 'organization_name')) ?>" maxlength="160" placeholder="Organization name">
|
||||
<div class="invalid-feedback"><?= h($errors['organization_name'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="email">Work email</label>
|
||||
<input class="form-control <?= !empty($errors['email']) ? 'is-invalid' : '' ?>" id="email" name="email" type="email" value="<?= h(old_value($formData, 'email')) ?>" maxlength="160" placeholder="name@company.com">
|
||||
<div class="invalid-feedback"><?= h($errors['email'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="phone">Phone / WhatsApp</label>
|
||||
<input class="form-control <?= !empty($errors['phone']) ? 'is-invalid' : '' ?>" id="phone" name="phone" value="<?= h(old_value($formData, 'phone')) ?>" maxlength="40" placeholder="Optional">
|
||||
<div class="invalid-feedback"><?= h($errors['phone'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="target_date">Preferred date</label>
|
||||
<input class="form-control <?= !empty($errors['target_date']) ? 'is-invalid' : '' ?>" id="target_date" name="target_date" type="date" value="<?= h(old_value($formData, 'target_date')) ?>">
|
||||
<div class="invalid-feedback"><?= h($errors['target_date'] ?? '') ?></div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="event_scale">Scale</label>
|
||||
<select class="form-select" id="event_scale" name="event_scale">
|
||||
<option value="">Select scale</option>
|
||||
<?php foreach (scale_options() as $option): ?>
|
||||
<option value="<?= h($option) ?>" <?= is_selected($option, old_value($formData, 'event_scale')) ?>><?= h($option) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="preferred_location">Preferred location</label>
|
||||
<select class="form-select" id="preferred_location" name="preferred_location">
|
||||
<option value="">Select location</option>
|
||||
<?php foreach (location_options() as $option): ?>
|
||||
<option value="<?= h($option) ?>" <?= is_selected($option, old_value($formData, 'preferred_location')) ?>><?= h($option) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between gap-3 align-items-center mb-1">
|
||||
<label class="form-label mb-0" for="notes">Brief description</label>
|
||||
<span class="form-counter" id="notesCounter">0 / 900</span>
|
||||
</div>
|
||||
<textarea class="form-control <?= !empty($errors['notes']) ? 'is-invalid' : '' ?>" id="notes" name="notes" maxlength="900" placeholder="Outline the program goal, audience, desired outcome, and any operational constraints." data-char-count data-char-count="#notesCounter"><?= h(old_value($formData, 'notes')) ?></textarea>
|
||||
<div class="invalid-feedback"><?= h($errors['notes'] ?? '') ?></div>
|
||||
<div class="form-text">This first intake is intentionally lightweight. A more detailed scoping conversation can follow after review.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 mt-4 inline-actions">
|
||||
<button class="btn btn-brand" type="submit">Submit Strategic Inquiry</button>
|
||||
<a class="btn btn-outline-brand" href="admin.php">Open preview desk</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="surface-card h-100">
|
||||
<span class="section-kicker">Review-ready behavior</span>
|
||||
<h2 class="section-title">Why this thin slice matters.</h2>
|
||||
<ul class="value-list mt-3">
|
||||
<li>Visitors can move from service discovery to inquiry without leaving the branded environment.</li>
|
||||
<li>The confirmation layer adds confidence by showing a saved reference and structured summary.</li>
|
||||
<li>The preview desk gives the team an immediate operational touchpoint for follow-up.</li>
|
||||
</ul>
|
||||
<div class="divider"></div>
|
||||
<span class="section-kicker section-kicker--muted">Channel guidance</span>
|
||||
<div class="contact-grid mt-2">
|
||||
<article class="surface-card">
|
||||
<h3 class="card-title">WhatsApp coordination</h3>
|
||||
<p class="card-copy mb-0">Use the phone field to nominate the best coordination channel for follow-up.</p>
|
||||
</article>
|
||||
<article class="surface-card">
|
||||
<h3 class="card-title">Email desk</h3>
|
||||
<p class="card-copy mb-0">The work email anchors the formal response lane for proposals and next steps.</p>
|
||||
</article>
|
||||
<article class="surface-card">
|
||||
<h3 class="card-title">Location planning</h3>
|
||||
<p class="card-copy mb-0">The location and target date fields make the first review more actionable.</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
59
portfolio.php
Normal file
59
portfolio.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Portfolio';
|
||||
$pageDescription = 'Editorial portfolio previews that demonstrate the operational capability of the GBP ecosystem.';
|
||||
$activePage = 'portfolio';
|
||||
$portfolioItems = portfolio_catalog();
|
||||
|
||||
$capabilities = [
|
||||
['title' => 'Retreat operations', 'summary' => 'Guest flow, accommodation alignment, facilitator support, and calm sequencing.'],
|
||||
['title' => 'Hospitality ecosystem', 'summary' => 'Property partnership, dining curation, service standards, and experience layering.'],
|
||||
['title' => 'Logistics support', 'summary' => 'Transport coordination, contingency planning, and movement clarity across touchpoints.'],
|
||||
];
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell page-intro">
|
||||
<span class="section-kicker">Portfolio</span>
|
||||
<h1 class="page-title">Portfolio documentation that signals capability, not clutter.</h1>
|
||||
<p class="lead-copy mb-0">This section turns operational proof into calm editorial cards—useful for clients, partners, and internal alignment.</p>
|
||||
</div>
|
||||
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($portfolioItems as $item): ?>
|
||||
<article class="surface-card service-card">
|
||||
<span class="signal-chip signal-chip--gold mb-2"><?= h($item['category']) ?></span>
|
||||
<h2 class="card-title"><?= h($item['title']) ?></h2>
|
||||
<p class="card-copy mb-2"><?= h($item['summary']) ?></p>
|
||||
<p class="card-copy mb-0"><?= h($item['detail']) ?></p>
|
||||
<div class="meta-row mt-auto">
|
||||
<span class="signal-chip"><?= h($item['metric']) ?></span>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section pt-0">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="section-kicker">Operational capability</span>
|
||||
<h2 class="section-title">The supporting layers behind each experience.</h2>
|
||||
</div>
|
||||
<div class="feature-grid">
|
||||
<?php foreach ($capabilities as $capability): ?>
|
||||
<article class="surface-card">
|
||||
<h3 class="card-title"><?= h($capability['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($capability['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
73
publication.php
Normal file
73
publication.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$slug = trim((string) ($_GET['slug'] ?? ''));
|
||||
$publication = publication_by_slug($slug);
|
||||
$activePage = 'publications';
|
||||
|
||||
if (!$publication) {
|
||||
http_response_code(404);
|
||||
$pageTitle = 'Publication Not Found';
|
||||
$pageDescription = 'The requested publication could not be found.';
|
||||
} else {
|
||||
$pageTitle = $publication['title'];
|
||||
$pageDescription = $publication['summary'];
|
||||
}
|
||||
|
||||
$relatedPublications = array_filter(publication_catalog(), static fn (array $item): bool => $publication ? $item['slug'] !== $publication['slug'] : true);
|
||||
$relatedPublications = array_slice(array_values($relatedPublications), 0, 2);
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<?php if (!$publication): ?>
|
||||
<div class="empty-panel">
|
||||
<span class="signal-chip signal-chip--gold mb-3">404</span>
|
||||
<h1 class="page-title">Publication unavailable</h1>
|
||||
<p class="empty-copy">Return to the publication index to keep exploring the ecosystem editorial layer.</p>
|
||||
<a class="btn btn-brand mt-3" href="publications.php">Back to publications</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<article class="hero-shell">
|
||||
<span class="section-kicker"><?= h($publication['category']) ?></span>
|
||||
<h1 class="page-title"><?= h($publication['title']) ?></h1>
|
||||
<div class="meta-row mb-4">
|
||||
<span class="signal-chip"><?= h(format_date_label($publication['date'])) ?></span>
|
||||
<span class="signal-chip signal-chip--accent">Publication detail</span>
|
||||
</div>
|
||||
<p class="lead-copy mb-0"><?= h($publication['summary']) ?></p>
|
||||
</article>
|
||||
|
||||
<div class="row g-4 mt-1">
|
||||
<div class="col-lg-8">
|
||||
<div class="surface-card h-100 publication-body">
|
||||
<?php foreach ($publication['body'] as $paragraph): ?>
|
||||
<p class="card-copy mb-3"><?= h($paragraph) ?></p>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="surface-card h-100">
|
||||
<span class="section-kicker">Continue exploring</span>
|
||||
<h2 class="section-title">Related reading</h2>
|
||||
<div class="stack-list mt-3">
|
||||
<?php foreach ($relatedPublications as $related): ?>
|
||||
<div class="stack-item">
|
||||
<div>
|
||||
<span><?= h($related['title']) ?></span>
|
||||
<small><?= h($related['summary']) ?></small>
|
||||
</div>
|
||||
<a class="button-link" href="<?= h(page_url('publication.php', ['slug' => $related['slug']])) ?>">Open</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
37
publications.php
Normal file
37
publications.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Publications';
|
||||
$pageDescription = 'Editorial updates, strategic insight, and governance-focused content for the GBP ecosystem.';
|
||||
$activePage = 'publications';
|
||||
$publications = publication_catalog();
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell page-intro">
|
||||
<span class="section-kicker">Publication reels</span>
|
||||
<h1 class="page-title">Editorial content that strengthens institutional authority.</h1>
|
||||
<p class="lead-copy mb-0">This first release includes a lightweight journal layer with list and detail views, making the site feel like an ecosystem platform rather than a single brochure.</p>
|
||||
</div>
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($publications as $publication): ?>
|
||||
<article class="surface-card service-card">
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-between align-items-start">
|
||||
<span class="signal-chip"><?= h($publication['category']) ?></span>
|
||||
<span class="meta-inline"><?= h(format_date_label($publication['date'])) ?></span>
|
||||
</div>
|
||||
<h2 class="card-title"><?= h($publication['title']) ?></h2>
|
||||
<p class="card-copy mb-0"><?= h($publication['summary']) ?></p>
|
||||
<div class="mt-auto">
|
||||
<a class="button-link" href="<?= h(page_url('publication.php', ['slug' => $publication['slug']])) ?>">Open article</a>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
109
service.php
Normal file
109
service.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$slug = trim((string) ($_GET['slug'] ?? ''));
|
||||
$service = service_by_slug($slug);
|
||||
$activePage = 'services';
|
||||
$pageRobots = '';
|
||||
|
||||
if (!$service) {
|
||||
http_response_code(404);
|
||||
$pageTitle = 'Service Not Found';
|
||||
$pageDescription = 'The requested package could not be found.';
|
||||
} else {
|
||||
$pageTitle = $service['category'];
|
||||
$pageDescription = $service['summary'];
|
||||
}
|
||||
|
||||
$relatedServices = array_filter(service_catalog(), static fn (array $item): bool => $service ? $item['slug'] !== $service['slug'] : true);
|
||||
$relatedServices = array_slice(array_values($relatedServices), 0, 3);
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<?php if (!$service): ?>
|
||||
<div class="empty-panel">
|
||||
<span class="signal-chip signal-chip--gold mb-3">404</span>
|
||||
<h1 class="page-title">Package detail unavailable</h1>
|
||||
<p class="empty-copy">Return to the service catalog to continue browsing the current package programs.</p>
|
||||
<a class="btn btn-brand mt-3" href="services.php">Back to services</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="hero-shell">
|
||||
<div class="row g-4 align-items-start">
|
||||
<div class="col-lg-7">
|
||||
<span class="section-kicker">Package detail</span>
|
||||
<h1 class="page-title"><?= h($service['category']) ?></h1>
|
||||
<p class="lead-copy"><?= h($service['headline']) ?></p>
|
||||
<p class="section-copy mb-4"><?= h($service['summary']) ?></p>
|
||||
<div class="d-flex flex-wrap gap-2 inline-actions">
|
||||
<a class="btn btn-brand" href="<?= h(page_url('partnership.php', ['interest' => $service['category'], 'route' => 'Package Customization'])) ?>">Customize Experience</a>
|
||||
<a class="btn btn-outline-brand" href="services.php">Back to services</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="surface-card hero-panel h-100">
|
||||
<span class="signal-chip signal-chip--primary mb-3">Program snapshot</span>
|
||||
<div class="meta-stack mb-3">
|
||||
<span class="meta-label">Audience</span>
|
||||
<strong><?= h($service['audience']) ?></strong>
|
||||
</div>
|
||||
<div class="meta-stack mb-3">
|
||||
<span class="meta-label">Duration</span>
|
||||
<strong><?= h($service['duration']) ?></strong>
|
||||
</div>
|
||||
<div class="meta-stack">
|
||||
<span class="meta-label">Outcome</span>
|
||||
<p class="card-copy mb-0"><?= h($service['outcome']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mt-1">
|
||||
<div class="col-lg-7">
|
||||
<div class="surface-card h-100">
|
||||
<span class="section-kicker">Included modules</span>
|
||||
<h2 class="section-title">A thin but complete package outline.</h2>
|
||||
<ul class="service-points mt-3">
|
||||
<?php foreach ($service['includes'] as $point): ?>
|
||||
<li><?= h($point) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="surface-card h-100">
|
||||
<span class="section-kicker">Why it matters</span>
|
||||
<p class="card-copy mb-3">This detail page shows how a visitor can understand the package logic before moving into a structured conversation.</p>
|
||||
<p class="card-copy mb-0">It also keeps the site from feeling like a single landing page by providing a usable browse → detail → inquiry journey.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="page-section pb-0 anchor-offset">
|
||||
<div class="section-head">
|
||||
<span class="section-kicker">Related packages</span>
|
||||
<h2 class="section-title">More programs in the ecosystem.</h2>
|
||||
</div>
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($relatedServices as $related): ?>
|
||||
<article class="surface-card service-card">
|
||||
<span class="signal-chip signal-chip--accent mb-2"><?= h($related['track']) ?></span>
|
||||
<h3 class="card-title"><?= h($related['category']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($related['summary']) ?></p>
|
||||
<div class="mt-auto">
|
||||
<a class="button-link" href="<?= h(page_url('service.php', ['slug' => $related['slug']])) ?>">Open package detail</a>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
91
services.php
Normal file
91
services.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
|
||||
$pageTitle = 'Services';
|
||||
$pageDescription = 'Curated package programs for eco wellness, retreat, hospitality, corporate, and event collaboration.';
|
||||
$activePage = 'services';
|
||||
$services = service_catalog();
|
||||
|
||||
$deliveryNotes = [
|
||||
['title' => 'Scope the brief', 'summary' => 'Clarify audience, outcome, timing, location, and experience tone.'],
|
||||
['title' => 'Match the ecosystem', 'summary' => 'Combine the right hospitality, logistics, wellness, and partner modules.'],
|
||||
['title' => 'Prepare delivery', 'summary' => 'Translate the chosen package into a calm, review-ready operational plan.'],
|
||||
];
|
||||
|
||||
require __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<section class="page-section pt-4 pt-lg-5">
|
||||
<div class="container">
|
||||
<div class="hero-shell page-intro">
|
||||
<div class="row g-4 align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<span class="section-kicker">Curated packages</span>
|
||||
<h1 class="page-title">A service catalog built for premium inquiry, not generic tourism browsing.</h1>
|
||||
<p class="lead-copy mb-0">Each program card is concise, credible, and directly linked to the strategic inquiry desk so visitors can move from exploration to a brief without friction.</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="surface-card hero-panel h-100">
|
||||
<span class="signal-chip signal-chip--primary mb-2">Filters</span>
|
||||
<p class="card-copy mb-0">Use the compact filters below to review immersive, corporate, or operational tracks.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar" aria-label="Service filters">
|
||||
<button type="button" class="btn btn-subtle active" data-service-filter="all">All</button>
|
||||
<button type="button" class="btn btn-subtle" data-service-filter="immersive">Immersive</button>
|
||||
<button type="button" class="btn btn-subtle" data-service-filter="corporate">Corporate</button>
|
||||
<button type="button" class="btn btn-subtle" data-service-filter="operational">Operational</button>
|
||||
</div>
|
||||
|
||||
<div class="preview-grid">
|
||||
<?php foreach ($services as $service): ?>
|
||||
<article class="surface-card service-card" data-service-track="<?= h($service['track']) ?>">
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-between align-items-start">
|
||||
<span class="signal-chip signal-chip--accent"><?= h($service['track']) ?></span>
|
||||
<span class="meta-inline"><?= h($service['duration']) ?></span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="card-title"><?= h($service['category']) ?></h2>
|
||||
<p class="card-copy mb-2"><?= h($service['headline']) ?></p>
|
||||
<p class="meta-inline mb-0"><strong>Audience:</strong> <?= h($service['audience']) ?></p>
|
||||
</div>
|
||||
<ul class="service-points">
|
||||
<?php foreach ($service['includes'] as $point): ?>
|
||||
<li><?= h($point) ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<div class="meta-stack">
|
||||
<span class="meta-label">Program outcome</span>
|
||||
<p class="card-copy mb-0"><?= h($service['outcome']) ?></p>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 mt-auto inline-actions">
|
||||
<a class="btn btn-outline-brand btn-sm" href="<?= h(page_url('service.php', ['slug' => $service['slug']])) ?>">View detail</a>
|
||||
<a class="btn btn-brand btn-sm" href="<?= h(page_url('partnership.php', ['interest' => $service['category'], 'route' => 'Package Customization'])) ?>">Customize Experience</a>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section pt-0">
|
||||
<div class="container">
|
||||
<div class="section-head">
|
||||
<span class="section-kicker">How delivery is structured</span>
|
||||
<h2 class="section-title">A small operational model that makes the service catalog feel real.</h2>
|
||||
</div>
|
||||
<div class="timeline-grid">
|
||||
<?php foreach ($deliveryNotes as $note): ?>
|
||||
<article class="surface-card">
|
||||
<h3 class="card-title"><?= h($note['title']) ?></h3>
|
||||
<p class="card-copy mb-0"><?= h($note['summary']) ?></p>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php require __DIR__ . '/includes/footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user