Compare commits

..

No commits in common. "ai-dev" and "master" have entirely different histories.

4 changed files with 405 additions and 441 deletions

View File

@ -1,73 +0,0 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'error' => 'Invalid method']);
exit;
}
if (!isset($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
echo json_encode(['success' => false, 'error' => 'Upload failed']);
exit;
}
$uploadDir = __DIR__ . '/../uploads/originals/';
$processedDir = __DIR__ . '/../uploads/processed/';
$fileName = time() . '_' . basename($_FILES['photo']['name']);
$targetFile = $uploadDir . $fileName;
if (move_uploaded_file($_FILES['photo']['tmp_name'], $targetFile)) {
// In a real app, we would call an AI API here to remove background and swap.
// For this MVP, we will simulate it by creating a "Luxury Edition"
// which is the original image with a subtle luxury filter/overlay.
$processedFileName = 'luxury_' . $fileName;
$processedPath = $processedDir . $processedFileName;
// Simulate processing: just copy for now
copy($targetFile, $processedPath);
// To make it look "luxury", we could use GD library to add a filter if available
if (extension_loaded('gd')) {
$info = getimagesize($targetFile);
$img = null;
if ($info['mime'] == 'image/jpeg') $img = imagecreatefromjpeg($targetFile);
elseif ($info['mime'] == 'image/png') $img = imagecreatefrompng($targetFile);
elseif ($info['mime'] == 'image/webp') $img = imagecreatefromwebp($targetFile);
if ($img) {
// Apply a slight "luxury" warm/dark filter
imagefilter($img, IMG_FILTER_CONTRAST, -5);
imagefilter($img, IMG_FILTER_BRIGHTNESS, -10);
imagefilter($img, IMG_FILTER_COLORIZE, 20, 10, -10, 20); // Warm gold tint
if ($info['mime'] == 'image/jpeg') imagejpeg($img, $processedPath, 90);
elseif ($info['mime'] == 'image/png') imagepng($img, $processedPath);
elseif ($info['mime'] == 'image/webp') imagewebp($img, $processedPath);
imagedestroy($img);
}
}
// Persist to DB
try {
$db = db();
$stmt = $db->prepare("INSERT INTO transformations (original_path, processed_path, style_id, status) VALUES (?, ?, ?, 'completed')");
$stmt->execute([
'uploads/originals/' . $fileName,
'uploads/processed/' . $processedFileName,
$_POST['style'] ?? 'default'
]);
} catch (Exception $e) {
// Silently continue if DB fails, but log it
error_log($e->getMessage());
}
echo json_encode([
'success' => true,
'original_url' => 'uploads/originals/' . $fileName,
'processed_url' => 'uploads/processed/' . $processedFileName
]);
} else {
echo json_encode(['success' => false, 'error' => 'Could not save file']);
}

View File

@ -1,249 +1,302 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&display=swap');
:root {
--bg-color: #0a0a0a;
--surface-color: #121212;
--accent-color: #d4af37;
--text-primary: #ffffff;
--text-secondary: #a0a0a0;
--border-color: rgba(255, 255, 255, 0.1);
--glass-bg: rgba(255, 255, 255, 0.03);
}
body { body {
background-color: var(--bg-color); background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
color: var(--text-primary); background-size: 400% 400%;
font-family: 'Inter', sans-serif; animation: gradient 15s ease infinite;
color: #212529;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-size: 14px;
margin: 0; margin: 0;
padding: 0; min-height: 100vh;
-webkit-font-smoothing: antialiased;
} }
.luxury-bg { .main-wrapper {
position: fixed; display: flex;
top: 0; align-items: center;
left: 0; justify-content: center;
min-height: 100vh;
width: 100%; width: 100%;
height: 100%; padding: 20px;
background: radial-gradient(circle at 50% 50%, #1a1a1a 0%, #0a0a0a 100%); box-sizing: border-box;
z-index: -1; position: relative;
z-index: 1;
} }
.navbar { @keyframes gradient {
padding: 1.5rem 2rem; 0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.chat-container {
width: 100%;
max-width: 600px;
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 20px;
display: flex;
flex-direction: column;
height: 85vh;
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
overflow: hidden;
}
.chat-header {
padding: 1.5rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
background: rgba(255, 255, 255, 0.5);
font-weight: 700;
font-size: 1.1rem;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
border-bottom: 1px solid var(--border-color);
backdrop-filter: blur(10px);
position: sticky;
top: 0;
z-index: 100;
} }
.logo { .chat-messages {
font-weight: 800; flex: 1;
font-size: 1.5rem; overflow-y: auto;
letter-spacing: -0.02em; padding: 1.5rem;
color: var(--text-primary); display: flex;
text-decoration: none; flex-direction: column;
gap: 1.25rem;
} }
.logo span { /* Custom Scrollbar */
color: var(--accent-color); ::-webkit-scrollbar {
width: 6px;
} }
.hero { ::-webkit-scrollbar-track {
text-align: center; background: transparent;
padding: 6rem 2rem;
max-width: 800px;
margin: 0 auto;
} }
.hero h1 { ::-webkit-scrollbar-thumb {
font-size: 3.5rem; background: rgba(255, 255, 255, 0.3);
font-weight: 800; border-radius: 10px;
line-height: 1.1;
margin-bottom: 1.5rem;
letter-spacing: -0.04em;
} }
.hero p { ::-webkit-scrollbar-thumb:hover {
font-size: 1.25rem; background: rgba(255, 255, 255, 0.5);
color: var(--text-secondary);
margin-bottom: 3rem;
line-height: 1.6;
} }
.upload-card { .message {
background: var(--surface-color); max-width: 85%;
border: 1px solid var(--border-color); padding: 0.85rem 1.1rem;
border-radius: 16px;
line-height: 1.5;
font-size: 0.95rem;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px) scale(0.95); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
.message.visitor {
align-self: flex-end;
background: linear-gradient(135deg, #212529 0%, #343a40 100%);
color: #fff;
border-bottom-right-radius: 4px;
}
.message.bot {
align-self: flex-start;
background: #ffffff;
color: #212529;
border-bottom-left-radius: 4px;
}
.chat-input-area {
padding: 1.25rem;
background: rgba(255, 255, 255, 0.5);
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
.chat-input-area form {
display: flex;
gap: 0.75rem;
}
.chat-input-area input {
flex: 1;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 12px; border-radius: 12px;
padding: 3rem; padding: 0.75rem 1rem;
max-width: 600px; outline: none;
margin: 0 auto; background: rgba(255, 255, 255, 0.9);
position: relative;
overflow: hidden;
transition: transform 0.3s ease, border-color 0.3s ease;
}
.upload-card:hover {
border-color: var(--accent-color);
}
.upload-zone {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 4rem 2rem;
cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
text-align: center;
} }
.upload-zone:hover { .chat-input-area input:focus {
background: var(--glass-bg); border-color: #23a6d5;
border-color: var(--accent-color); box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2);
} }
.upload-zone i { .chat-input-area button {
font-size: 3rem; background: #212529;
color: var(--accent-color); color: #fff;
margin-bottom: 1rem;
}
.btn-primary {
background: var(--accent-color);
color: #000;
border: none; border: none;
padding: 1rem 2.5rem; padding: 0.75rem 1.5rem;
font-weight: 600; border-radius: 12px;
border-radius: 6px;
cursor: pointer; cursor: pointer;
font-weight: 600;
transition: all 0.3s ease; transition: all 0.3s ease;
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 0.05em;
} }
.btn-primary:hover { .chat-input-area button:hover {
background: #000;
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(212, 175, 55, 0.2); box-shadow: 0 5px 15px rgba(0,0,0,0.2);
background: #e5c05b;
} }
.style-grid { /* Background Animations */
display: grid; .bg-animations {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
margin-top: 4rem;
padding: 2rem;
}
.style-item {
position: relative;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
border: 2px solid transparent;
transition: all 0.3s ease;
}
.style-item img {
width: 100%;
height: 250px;
object-fit: cover;
transition: transform 0.3s ease;
}
.style-item:hover img {
transform: scale(1.05);
}
.style-item.active {
border-color: var(--accent-color);
}
.style-item .label {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0,0,0,0.8));
padding: 1rem;
font-size: 0.875rem;
font-weight: 600;
}
#processing-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: rgba(0,0,0,0.9); z-index: 0;
z-index: 1000; overflow: hidden;
display: none; pointer-events: none;
flex-direction: column;
justify-content: center;
align-items: center;
} }
.spinner { .blob {
width: 50px; position: absolute;
height: 50px; width: 500px;
border: 3px solid var(--border-color); height: 500px;
border-top: 3px solid var(--accent-color); background: rgba(255, 255, 255, 0.2);
border-radius: 50%; border-radius: 50%;
animation: spin 1s linear infinite; filter: blur(80px);
margin-bottom: 2rem; animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1);
} }
@keyframes spin { .blob-1 {
0% { transform: rotate(0deg); } top: -10%;
100% { transform: rotate(360deg); } left: -10%;
background: rgba(238, 119, 82, 0.4);
} }
.progress-text { .blob-2 {
font-size: 1.25rem; bottom: -10%;
font-weight: 300; right: -10%;
letter-spacing: 0.1em; background: rgba(35, 166, 213, 0.4);
color: var(--text-secondary); animation-delay: -7s;
width: 600px;
height: 600px;
} }
.result-container { .blob-3 {
display: none; top: 40%;
max-width: 1000px; left: 30%;
margin: 4rem auto; background: rgba(231, 60, 126, 0.3);
padding: 2rem; animation-delay: -14s;
width: 450px;
height: 450px;
} }
.comparison-view { @keyframes move {
display: grid; 0% { transform: translate(0, 0) rotate(0deg) scale(1); }
grid-template-columns: 1fr 1fr; 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); }
gap: 2rem; 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); }
margin-bottom: 3rem; 100% { transform: translate(0, 0) rotate(360deg) scale(1); }
} }
.comparison-item { .admin-link {
text-align: center; font-size: 14px;
color: #fff;
text-decoration: none;
background: rgba(0, 0, 0, 0.2);
padding: 0.5rem 1rem;
border-radius: 8px;
transition: all 0.3s ease;
} }
.comparison-item img { .admin-link:hover {
background: rgba(0, 0, 0, 0.4);
text-decoration: none;
}
/* Admin Styles */
.admin-container {
max-width: 900px;
margin: 3rem auto;
padding: 2.5rem;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 20px 50px rgba(0,0,0,0.15);
border: 1px solid rgba(255, 255, 255, 0.4);
position: relative;
z-index: 1;
}
.admin-container h1 {
margin-top: 0;
color: #212529;
font-weight: 800;
}
.table {
width: 100%; width: 100%;
border-radius: 12px; border-collapse: separate;
border: 1px solid var(--border-color); border-spacing: 0 8px;
margin-top: 1.5rem;
} }
.comparison-item span { .table th {
display: block; background: transparent;
margin-top: 1rem; border: none;
color: var(--text-secondary); padding: 1rem;
color: #6c757d;
font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
font-size: 0.75rem; font-size: 0.75rem;
letter-spacing: 0.1em; letter-spacing: 1px;
} }
@media (max-width: 768px) { .table td {
.hero h1 { font-size: 2.5rem; } background: #fff;
.comparison-view { grid-template-columns: 1fr; } padding: 1rem;
border: none;
}
.table tr td:first-child { border-radius: 12px 0 0 12px; }
.table tr td:last-child { border-radius: 0 12px 12px 0; }
.form-group {
margin-bottom: 1.25rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
font-size: 0.9rem;
}
.form-control {
width: 100%;
padding: 0.75rem 1rem;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 12px;
background: #fff;
transition: all 0.3s ease;
box-sizing: border-box;
}
.form-control:focus {
outline: none;
border-color: #23a6d5;
box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1);
} }

View File

@ -1,99 +1,39 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const photoInput = document.getElementById('photo-input'); const chatForm = document.getElementById('chat-form');
const uploadForm = document.getElementById('upload-form'); const chatInput = document.getElementById('chat-input');
const imagePreview = document.getElementById('image-preview'); const chatMessages = document.getElementById('chat-messages');
const previewContainer = document.getElementById('preview-container');
const uploadZone = document.querySelector('.upload-zone');
const processBtn = document.getElementById('process-btn');
const styleItems = document.querySelectorAll('.style-item');
const overlay = document.getElementById('processing-overlay');
const statusDetail = document.getElementById('status-detail');
let selectedStyle = 'penthouse-1'; const appendMessage = (text, sender) => {
let uploadedFile = null; const msgDiv = document.createElement('div');
msgDiv.classList.add('message', sender);
// Handle File Preview msgDiv.textContent = text;
photoInput.addEventListener('change', (e) => { chatMessages.appendChild(msgDiv);
const file = e.target.files[0]; chatMessages.scrollTop = chatMessages.scrollHeight;
if (file) {
uploadedFile = file;
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
previewContainer.classList.remove('d-none');
uploadZone.classList.add('d-none');
processBtn.classList.remove('d-none');
};
reader.readAsDataURL(file);
}
});
// Style Selection
styleItems.forEach(item => {
item.addEventListener('click', () => {
styleItems.forEach(i => i.classList.remove('active'));
item.classList.add('active');
selectedStyle = item.getAttribute('data-style');
});
});
// Reset Upload
window.resetUpload = () => {
photoInput.value = '';
uploadedFile = null;
previewContainer.classList.add('d-none');
uploadZone.classList.remove('d-none');
processBtn.classList.add('d-none');
}; };
// Process Logic chatForm.addEventListener('submit', async (e) => {
processBtn.addEventListener('click', async () => { e.preventDefault();
if (!uploadedFile) return; const message = chatInput.value.trim();
if (!message) return;
overlay.style.display = 'flex'; appendMessage(message, 'visitor');
chatInput.value = '';
// Mocking AI Steps
const steps = [
"Detecting portrait contours...",
"Isolating subject from background...",
"Matching color temperature to luxury night...",
"Applying soft cinematic depth of field...",
"Finalizing luxury textures..."
];
for (let i = 0; i < steps.length; i++) {
statusDetail.textContent = steps[i];
await new Promise(r => setTimeout(r, 1200));
}
const formData = new FormData();
formData.append('photo', uploadedFile);
formData.append('style', selectedStyle);
try { try {
const response = await fetch('api/process.php', { const response = await fetch('api/chat.php', {
method: 'POST', method: 'POST',
body: formData headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
}); });
const data = await response.json(); const data = await response.json();
if (data.success) { // Artificial delay for realism
document.getElementById('upload-section').classList.add('d-none'); setTimeout(() => {
document.getElementById('result-section').classList.remove('d-none'); appendMessage(data.reply, 'bot');
document.getElementById('original-res').src = data.original_url; }, 500);
document.getElementById('processed-res').src = data.processed_url;
document.getElementById('download-btn').href = data.processed_url;
// Smooth scroll to results
window.scrollTo({ top: 0, behavior: 'smooth' });
} else {
alert("Processing failed: " + (data.error || "Unknown error"));
}
} catch (error) { } catch (error) {
console.error('Error:', error); console.error('Error:', error);
alert("Something went wrong with the AI engine."); appendMessage("Sorry, something went wrong. Please try again.", 'bot');
} finally {
overlay.style.display = 'none';
} }
}); });
}); });

238
index.php
View File

@ -1,106 +1,150 @@
<?php <?php
require_once 'db/config.php'; declare(strict_types=1);
$projectName = $_SERVER['PROJECT_NAME'] ?? 'LuxuryPortrait AI'; @ini_set('display_errors', '1');
$projectDesc = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Elevate your portrait with AI-powered luxury night backgrounds.'; @error_reporting(E_ALL);
@date_default_timezone_set('UTC');
$phpVersion = PHP_VERSION;
$now = date('Y-m-d H:i:s');
?> ?>
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title><?php echo htmlspecialchars($projectName); ?></title> <title>New Style</title>
<meta name="description" content="<?php echo htmlspecialchars($projectDesc); ?>"> <?php
// Read project preview data from environment
<!-- Bootstrap 5 CSS --> $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
<!-- Font Awesome --> ?>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <?php if ($projectDescription): ?>
<!-- Custom Luxury CSS --> <!-- Meta description -->
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>"> <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> </head>
<body> <body>
<div class="luxury-bg"></div> <main>
<div class="card">
<nav class="navbar"> <h1>Analyzing your requirements and generating your website…</h1>
<a href="/" class="logo">LUXURY<span>PORTRAIT</span></a> <div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<div class="nav-links d-none d-md-flex"> <span class="sr-only">Loading…</span>
<span class="text-secondary small">AI-Powered Transformation</span> </div>
</div> <p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
</nav> <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>
<main class="container">
<!-- Step 1: Landing & Upload -->
<section id="upload-section" class="hero">
<h1>Elevate Your Presence to <span style="color:var(--accent-color)">Luxury</span>.</h1>
<p>Our AI preserves your natural features while placing you in the world's most exclusive night penthouses.</p>
<div class="upload-card">
<form id="upload-form" enctype="multipart/form-data">
<div class="upload-zone" onclick="document.getElementById('photo-input').click()">
<i class="fa-solid fa-cloud-arrow-up"></i>
<h3>Drop your portrait here</h3>
<p class="text-secondary">PNG, JPG or WEBP (Max 10MB)</p>
<input type="file" id="photo-input" name="photo" hidden accept="image/*">
</div>
<div id="preview-container" class="mt-4 d-none">
<img id="image-preview" src="" alt="Preview" class="img-fluid rounded mb-3">
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="resetUpload()">Change Photo</button>
</div>
</form>
</div>
<div class="style-selection mt-5">
<h4 class="mb-4">Select Your Luxury Scene</h4>
<div class="style-grid">
<div class="style-item active" data-style="penthouse-1">
<img src="https://images.pexels.com/photos/323705/pexels-photo-323705.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Penthouse Night">
<div class="label">Manhattan Penthouse</div>
</div>
<div class="style-item" data-style="penthouse-2">
<img src="https://images.pexels.com/photos/1571460/pexels-photo-1571460.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Skyline View">
<div class="label">Tokyo Skyline</div>
</div>
<div class="style-item" data-style="penthouse-3">
<img src="https://images.pexels.com/photos/261102/pexels-photo-261102.jpeg?auto=compress&cs=tinysrgb&w=600" alt="Infinity Pool">
<div class="label">Dubai Infinity</div>
</div>
</div>
</div>
<div class="mt-5">
<button id="process-btn" class="btn-primary d-none">Generate My Luxury Portrait</button>
</div>
</section>
<!-- Step 2: Results -->
<section id="result-section" class="result-container">
<h2 class="text-center mb-5">Your Luxury Transformation</h2>
<div class="comparison-view">
<div class="comparison-item">
<img id="original-res" src="" alt="Original">
<span>Natural Portrait</span>
</div>
<div class="comparison-item">
<img id="processed-res" src="" alt="Processed">
<span>Luxury Night Edition</span>
</div>
</div>
<div class="text-center">
<a id="download-btn" href="#" download class="btn-primary me-3">Download HD Result</a>
<button class="btn btn-link text-secondary" onclick="window.location.reload()">Start Over</button>
</div>
</section>
</main>
<!-- Processing Overlay -->
<div id="processing-overlay">
<div class="spinner"></div>
<div class="progress-text">AI IS ANALYZING TEXTURES...</div>
<div class="mt-3 text-secondary small" id="status-detail">Preserving natural facial lighting</div>
</div> </div>
</main>
<!-- Scripts --> <footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> Page updated: <?= htmlspecialchars($now) ?> (UTC)
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script> </footer>
</body> </body>
</html> </html>