<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ALTO Digital | Videography & Strategy</title>
<!-- React & ReactDOM -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<!-- Babel for JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Google Fonts -->
<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=Cormorant+Garamond:wght@300;400;500;600&family=Manrope:wght@300;400;500;600&family=Oswald:wght@500;700&display=swap" rel="stylesheet">
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
alto: {
bg: '#F5F5F0', // Main background (Stone/Off-white)
beige: '#E8E6E1', // New Beige for sections
surface: '#EBEBE6', // Secondary background
text: '#1C1C1C', // Almost black
accent: '#1B4D3E', // Forest Green
subtle: '#D4D4D0' // Borders
}
},
fontFamily: {
serif: ['"Cormorant Garamond"', 'serif'],
sans: ['"Manrope"', 'sans-serif'],
logo: ['"Oswald"', 'sans-serif'],
},
animation: {
'fade-in-up': 'fadeInUp 0.8s ease-out forwards',
},
keyframes: {
fadeInUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
},
}
}
}
</script>
<style>
/* Global Smooth Scroll */
html {
scroll-behavior: smooth;
}
/* Custom scrollbar for webkit */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: #F5F5F0;
}
::-webkit-scrollbar-thumb {
background: #D4D4D0;
}
::-webkit-scrollbar-thumb:hover {
background: #1B4D3E; /* Forest Green hover */
}
body {
background-color: #F5F5F0;
color: #1C1C1C;
position: relative;
}
/* Image-based Paper Texture */
body::before {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0.3;
pointer-events: none;
z-index: -1;
background-image: url("image_0.png");
background-repeat: repeat;
background-size: 300px 300px;
mix-blend-mode: multiply;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect, useRef } = React;
// Logo Component
const AltoLogo = ({ className }) => (
<div className={`font-logo font-bold tracking-tighter leading-none inline-block ${className}`}>
ALTO.
</div>
);
// Custom Hook for intersection observer (fade in elements on scroll)
const useOnScreen = (options) => {
const ref = useRef(null);
const [visible, setVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setVisible(true);
observer.disconnect();
}
}, options);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
if (ref.current) observer.unobserve(ref.current);
}
}, [ref, options]);
return [ref, visible];
}
const FadeInSection = ({ children, delay = 0 }) => {
const [ref, visible] = useOnScreen({ threshold: 0.1 });
return (
<div
ref={ref}
className={`transition-all duration-1000 ease-out transform ${visible ? 'opacity-100 translate-y-0 scale-100' : 'opacity-0 translate-y-10 scale-95'}`}
style={{ transitionDelay: `${delay}ms` }}
>
{children}
</div>
);
};
// --- Components ---
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const scrollTo = (id) => {
setIsOpen(false);
document.getElementById(id).scrollIntoView({ behavior: 'smooth' });
}
return (
<nav className={`fixed w-full z-50 transition-all duration-500 ${scrolled ? 'py-4 bg-alto-accent shadow-md' : 'py-6 bg-transparent'}`}>
<div className="container mx-auto px-6 flex justify-between items-center">
<div className="cursor-pointer z-50" onClick={() => scrollTo('hero')}>
{/* Logo changes color based on scroll state */}
<AltoLogo className={`text-3xl md:text-4xl transition-colors duration-500 ${scrolled ? 'text-alto-bg' : 'text-alto-accent'}`} />
</div>
{/* Desktop Menu */}
<div className={`hidden md:flex space-x-12 font-sans text-xs tracking-widest uppercase font-medium transition-colors duration-500 ${scrolled ? 'text-alto-bg/90' : 'text-alto-text'}`}>
{['Agency', 'Work', 'Packages', 'Contact'].map((item) => (
<button
key={item}
onClick={() => scrollTo(item.toLowerCase())}
className={`transition-colors duration-300 ${scrolled ? 'hover:text-white' : 'hover:text-alto-accent'}`}
>
{item}
</button>
))}
</div>
{/* Mobile Menu Button */}
<div className="md:hidden z-50">
<button onClick={() => setIsOpen(!isOpen)} className={`focus:outline-none transition-colors duration-500 ${scrolled ? 'text-alto-bg' : 'text-alto-text'}`}>
{isOpen ? (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
)}
</button>
</div>
{/* Mobile Overlay (Stays light themed) */}
<div className={`fixed inset-0 bg-alto-bg flex flex-col justify-center items-center space-y-8 transition-all duration-500 ease-in-out md:hidden ${isOpen ? 'opacity-100 visible' : 'opacity-0 invisible pointer-events-none'}`}>
{['Agency', 'Work', 'Packages', 'Contact'].map((item) => (
<button
key={item}
onClick={() => scrollTo(item.toLowerCase())}
className="font-serif text-3xl text-alto-text hover:text-alto-accent transition-colors"
>
{item}
</button>
))}
</div>
</div>
</nav>
);
};
const Hero = () => {
return (
<section id="hero" className="relative h-screen w-full flex items-center justify-center overflow-hidden">
<div className="container mx-auto px-6 text-center z-10 pt-20">
<div className="animate-fade-in-up">
<AltoLogo className="text-7xl md:text-9xl mx-auto mb-8 text-alto-accent" />
<p className="font-sans text-xs md:text-sm uppercase tracking-[0.3em] mb-6 text-alto-text/60 font-medium">
Videography & Digital Strategy | Brisbane, Australia
</p>
<h1 className="font-serif text-5xl md:text-7xl lg:text-8xl text-alto-text leading-tight mb-8 font-medium">
Visuals That<br/><span className="italic font-normal text-alto-accent">Speak Volumes.</span>
</h1>
<div className="mt-12">
<button
onClick={() => document.getElementById('packages').scrollIntoView({ behavior: 'smooth' })}
className="group relative inline-flex items-center justify-center px-8 py-3 overflow-hidden font-sans font-medium tracking-tighter text-alto-accent bg-transparent border border-alto-accent/30 rounded-full hover:bg-alto-accent hover:text-alto-bg transition-all duration-300"
>
<span className="absolute w-0 h-0 transition-all duration-500 ease-out bg-alto-accent rounded-full group-hover:w-64 group-hover:h-64 opacity-100"></span>
<span className="relative text-sm tracking-widest uppercase flex items-center gap-2 group-hover:text-white transition-colors duration-300">
View Packages
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
</span>
</button>
</div>
</div>
</div>
{/* Decorative Elements */}
<div className="absolute bottom-10 right-10 hidden md:block animate-pulse">
<span className="font-sans text-xs tracking-widest rotate-90 origin-right block text-alto-accent/60">SCROLL DOWN</span>
</div>
</section>
);
};
const Agency = () => {
return (
<section id="agency" className="py-24 md:py-32 bg-alto-beige overflow-hidden">
<div className="container mx-auto px-6">
<div className="flex flex-col lg:flex-row items-center gap-16 lg:gap-24">
<div className="lg:w-1/2">
<FadeInSection>
<div className="relative">
<div className="aspect-[3/4] md:aspect-square bg-alto-surface overflow-hidden w-full max-w-md mx-auto">
<img
src="https://images.unsplash.com/photo-1542744173-8e7e53415bb0?auto=format&fit=crop&q=80&w=1000"
alt="Strategy Meeting"
className="object-cover w-full h-full grayscale opacity-90 hover:opacity-100 transition-opacity duration-700"
/>
</div>
</div>
</FadeInSection>
</div>
<div className="lg:w-1/2">
<FadeInSection delay={200}>
<p className="font-sans text-xs uppercase tracking-widest text-alto-accent mb-4">Our Approach</p>
<h2 className="font-serif text-4xl md:text-5xl mb-8 leading-tight font-medium">
We craft digital narratives for the modern age.
</h2>
<p className="font-sans text-alto-text/80 mb-6 leading-relaxed text-lg">
ALTO Digital bridges the gap between cinematic artistry and data-driven strategy. We don't just create visuals; we build campaigns that perform.
</p>
<p className="font-sans text-alto-text/80 mb-8 leading-relaxed text-lg">
Specializing in real estate, hospitality, and local business, our all-inclusive approach handles everything from concept and content planning to production and distribution, so you can focus on running your business.
</p>
</FadeInSection>
</div>
</div>
</div>
</section>
);
};
const Work = () => {
const projects = [
{ id: 1, title: "Lumina Fashion", cat: "Campaign", img: "https://images.unsplash.com/photo-1483985988355-763728e1935b?auto=format&fit=crop&q=80&w=1000" },
{ id: 2, title: "The Local Bistro", cat: "Restaurant", img: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?auto=format&fit=crop&q=80&w=1000" },
{ id: 3, title: "Apex Realty", cat: "Real Estate", img: "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&q=80&w=1000" },
];
return (
<section id="work" className="py-24 bg-alto-surface">
<div className="container mx-auto px-6">
<FadeInSection>
<div className="flex flex-col md:flex-row justify-between items-end mb-16">
<h2 className="font-serif text-4xl md:text-5xl text-alto-text font-medium">Selected Works</h2>
<button onClick={() => document.getElementById('contact').scrollIntoView({ behavior: 'smooth' })} className="hidden md:block font-sans text-sm uppercase tracking-widest border-b border-alto-text pb-1 hover:text-alto-accent hover:border-alto-accent transition-colors">
Start Your Project
</button>
</div>
</FadeInSection>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{projects.map((project, index) => (
<FadeInSection key={project.id} delay={index * 150}>
<div className="group cursor-pointer">
<div className="relative overflow-hidden aspect-[4/5] bg-alto-bg mb-4">
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/10 transition-all duration-500 z-10"></div>
<img
src={project.img}
alt={project.title}
className="object-cover w-full h-full transform group-hover:scale-105 transition-transform duration-700 ease-out grayscale group-hover:grayscale-0"
/>
{/* Play Icon Overlay */}
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-20">
<div className="w-14 h-14 bg-white/90 backdrop-blur-sm rounded-full flex items-center justify-center">
<svg className="w-5 h-5 ml-1 text-black" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
</div>
</div>
</div>
<div className="flex flex-col items-start">
<h3 className="font-serif text-2xl text-alto-text group-hover:text-alto-accent group-hover:italic transition-all mb-2">{project.title}</h3>
<span className="font-sans text-xs uppercase tracking-wider text-alto-accent">{project.cat}</span>
</div>
</div>
</FadeInSection>
))}
</div>
<div className="mt-12 text-center md:hidden">
<button onClick={() => document.getElementById('contact').scrollIntoView({ behavior: 'smooth' })} className="font-sans text-sm uppercase tracking-widest border-b border-alto-text pb-1">
Start Your Project
</button>
</div>
</div>
</section>
);
};
const Packages = () => {
const packages = [
{
title: "The One-Off Ad",
desc: "A high-impact single advertisement designed to launch a product or promote a specific campaign.",
features: ["Concept & Scripting", "1 Full Day Shoot", "4K Cinema Quality", "Licensed Music & Sound Design", "2 Revisions"]
},
{
title: "The Monthly Content Day",
desc: "Efficient bulk content creation. We shoot everything in one day to provide you with a month's worth of consistent video assets.",
features: ["Monthly Strategy Call", "1 Full Day Shoot / Month", "12 Videos (3/Week)", "Formatted for Reels/TikTok", "Basic Captions & Branding"]
},
{
title: "The Full-Service Partner",
desc: "Our most popular package. We handle content creation and manage your social presence to ensure maximum reach and engagement.",
features: ["Everything in Monthly Plan", "Social Media Management", "Paid Ad Campaign Setup", "Community Engagement", "Monthly Performance Report"],
featured: true
}
];
return (
<section id="packages" className="py-24 bg-alto-beige">
<div className="container mx-auto px-6">
<FadeInSection>
<h2 className="font-serif text-4xl md:text-5xl mb-4 text-center font-medium">Content Packages</h2>
<p className="font-sans text-alto-accent text-center max-w-2xl mx-auto mb-16">Simple, transparent pricing tailored to grow your business.</p>
</FadeInSection>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{packages.map((pkg, index) => (
<FadeInSection key={index} delay={index * 100}>
<div className={`flex flex-col h-full p-8 border ${pkg.featured ? 'border-alto-accent bg-alto-surface' : 'border-alto-subtle hover:border-alto-accent'} transition-all duration-300 relative group`}>
{pkg.featured && <span className="absolute top-0 right-0 bg-alto-accent text-alto-bg text-xs uppercase tracking-widest px-3 py-1 font-medium">Most Popular</span>}
<h3 className="font-serif text-2xl mb-4 font-medium">{pkg.title}</h3>
<p className="font-sans text-sm text-alto-text/70 leading-relaxed mb-8">
{pkg.desc}
</p>
<ul className="space-y-3 mb-8 flex-grow">
{pkg.features.map((feature, i) => (
<li key={i} className="flex items-center font-sans text-sm text-alto-text">
<svg className="w-4 h-4 mr-3 text-alto-accent shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"/></svg>
{feature}
</li>
))}
</ul>
<button
onClick={() => document.getElementById('contact').scrollIntoView({ behavior: 'smooth' })}
className={`w-full py-3 text-sm uppercase tracking-widest font-medium transition-colors ${pkg.featured ? 'bg-alto-accent text-alto-bg hover:bg-alto-accent/90' : 'border border-alto-text text-alto-text hover:bg-alto-accent hover:border-alto-accent hover:text-alto-bg'}`}
>
Inquire Now
</button>
</div>
</FadeInSection>
))}
</div>
</div>
</section>
);
};
const Contact = () => {
const [formStatus, setFormStatus] = useState('idle');
const handleSubmit = (e) => {
e.preventDefault();
setFormStatus('sending');
setTimeout(() => {
setFormStatus('success');
}, 1500);
};
return (
<section id="contact" className="py-24 bg-alto-text text-alto-bg">
<div className="container mx-auto px-6">
<FadeInSection>
<div className="flex flex-col lg:flex-row gap-16 lg:gap-24">
<div className="lg:w-1/2">
<p className="text-alto-accent text-sm uppercase tracking-widest mb-4">Start a Project</p>
<h2 className="font-serif text-5xl md:text-6xl mb-8 font-medium leading-tight">Let's Create<br/>Something Timeless.</h2>
<p className="font-sans text-alto-bg/80 text-lg mb-12 max-w-md">
Ready to elevate your brand? Tell us about your vision, and let's design a content plan that works for you.
</p>
<div className="space-y-4 font-sans text-alto-bg/70 text-sm">
<p className="flex items-center"><lucide-react name="map-pin" className="w-4 h-4 mr-3 text-alto-accent"/> Brisbane, Australia</p>
<p className="flex items-center"><lucide-react name="mail" className="w-4 h-4 mr-3 text-alto-accent"/> martin@altodigital.net</p>
</div>
<div className="mt-12 flex space-x-6">
{['Instagram', 'LinkedIn'].map(social => (
<a key={social} href="#" className="text-xs uppercase tracking-widest border-b border-transparent hover:border-alto-accent hover:text-alto-accent transition-all pb-1">{social}</a>
))}
</div>
</div>
<div className="lg:w-1/2">
<form onSubmit={handleSubmit} className="space-y-8">
<div className="group relative">
<input
type="text"
id="name"
required
className="peer w-full bg-transparent border-b border-alto-bg/30 py-3 text-alto-bg focus:outline-none focus:border-alto-accent transition-colors placeholder-transparent"
placeholder="Name"
/>
<label htmlFor="name" className="absolute left-0 -top-3.5 text-alto-accent text-xs transition-all peer-placeholder-shown:text-base peer-placeholder-shown:text-alto-bg/50 peer-placeholder-shown:top-3 peer-focus:-top-3.5 peer-focus:text-alto-accent peer-focus:text-xs">Name</label>
</div>
<div className="group relative">
<input
type="email"
id="email"
required
className="peer w-full bg-transparent border-b border-alto-bg/30 py-3 text-alto-bg focus:outline-none focus:border-alto-accent transition-colors placeholder-transparent"
placeholder="Email"
/>
<label htmlFor="email" className="absolute left-0 -top-3.5 text-alto-accent text-xs transition-all peer-placeholder-shown:text-base peer-placeholder-shown:text-alto-bg/50 peer-placeholder-shown:top-3 peer-focus:-top-3.5 peer-focus:text-alto-accent peer-focus:text-xs">Email</label>
</div>
<div className="group">
<select className="w-full bg-transparent border-b border-alto-bg/30 py-3 text-alto-bg/90 focus:outline-none focus:border-alto-accent transition-colors cursor-pointer">
<option value="" className="text-alto-text">Select a Package</option>
<option value="one-off" className="text-alto-text">The One-Off Ad</option>
<option value="monthly" className="text-alto-text">The Monthly Content Day</option>
<option value="full-service" className="text-alto-text">The Full-Service Partner</option>
<option value="other" className="text-alto-text">Other / Custom Inquiry</option>
</select>
</div>
<div className="group relative">
<textarea
id="message"
rows="4"
className="peer w-full bg-transparent border-b border-alto-bg/30 py-3 text-alto-bg focus:outline-none focus:border-alto-accent transition-colors placeholder-transparent resize-none"
placeholder="Tell us about your project..."
></textarea>
<label htmlFor="message" className="absolute left-0 -top-3.5 text-alto-accent text-xs transition-all peer-placeholder-shown:text-base peer-placeholder-shown:text-alto-bg/50 peer-placeholder-shown:top-3 peer-focus:-top-3.5 peer-focus:text-alto-accent peer-focus:text-xs">Tell us about your project...</label>
</div>
<button
type="submit"
disabled={formStatus === 'success'}
className="mt-8 px-10 py-4 bg-alto-accent text-alto-bg font-sans font-medium uppercase tracking-widest hover:bg-white hover:text-alto-text transition-colors w-full md:w-auto"
>
{formStatus === 'idle' && 'Submit Inquiry'}
{formStatus === 'sending' && 'Sending...'}
{formStatus === 'success' && 'Message Sent'}
</button>
</form>
</div>
</div>
</FadeInSection>
</div>
</section>
);
};
const Footer = () => {
return (
<footer className="bg-alto-text py-8 border-t border-white/10 text-alto-bg/40 text-xs font-sans">
<div className="container mx-auto px-6 flex flex-col md:flex-row justify-between items-center">
<div className="mb-4 md:mb-0">
<AltoLogo className="text-2xl text-alto-accent mb-2" />
<p>© {new Date().getFullYear()} ALTO Digital. Brisbane, Australia.</p>
</div>
<div className="flex space-x-8">
<a href="#" className="hover:text-alto-bg transition-colors">Privacy Policy</a>
<a href="#" className="hover:text-alto-bg transition-colors">Terms of Service</a>
</div>
</div>
</footer>
);
};
const App = () => {
return (
<div className="antialiased selection:bg-alto-accent selection:text-white">
<Navbar />
<Hero />
<Agency />
<Work />
<Packages />
<Contact />
<Footer />
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>