Airline — Private Charter Landing
A discreet, luxury private-charter and jet-card landing page for the fictional Méridian Air. Black, champagne, and slate with an elegant serif set the bespoke tone across a request-a-quote hero, a tabbed fleet showcase spanning light, midsize, and heavy jets, three membership tiers, a four-step on-demand process, a concierge section, and a full quote form. Vanilla JS drives tab switching, scroll reveals, form validation, and a toast confirmation.
MCP
Code
:root {
--black: #0c0c0f;
--black-2: #15151a;
--black-3: #1e1e25;
--champagne: #e6d2a8;
--champagne-d: #c9b486;
--champagne-50: #f7f1e4;
--slate: #6f7686;
--slate-d: #4a4f5c;
--ink: #16171c;
--ink-2: #3a3d47;
--muted: #8b8f9c;
--line: rgba(12, 12, 15, 0.1);
--line-2: rgba(12, 12, 15, 0.18);
--line-gold: rgba(230, 210, 168, 0.28);
--bg: #faf8f3;
--surface: #ffffff;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--shadow-sm: 0 2px 10px rgba(12, 12, 15, 0.06);
--shadow-md: 0 14px 40px rgba(12, 12, 15, 0.1);
--shadow-lg: 0 30px 80px rgba(12, 12, 15, 0.18);
--serif: "Cormorant Garamond", Georgia, "Times New Roman", serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
--tnum: "Inter", system-ui, sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: var(--sans);
color: var(--ink);
background: var(--bg);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
img, svg { display: block; max-width: 100%; }
.tnum { font-feature-settings: "tnum" 1; font-variant-numeric: tabular-nums; }
.wrap { width: min(1180px, 92vw); margin-inline: auto; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0; font-family: var(--serif); font-weight: 600; letter-spacing: 0.01em; }
em { font-style: italic; }
/* ===== buttons ===== */
.btn {
font-family: var(--sans);
font-weight: 600;
font-size: 0.82rem;
letter-spacing: 0.06em;
text-transform: uppercase;
border: 0;
border-radius: 999px;
padding: 0.72em 1.5em;
cursor: pointer;
transition: transform 0.18s ease, background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5em;
}
.btn.lg { padding: 0.95em 1.9em; font-size: 0.86rem; }
.btn.full { width: 100%; }
.btn-gold {
background: linear-gradient(135deg, var(--champagne) 0%, var(--champagne-d) 100%);
color: var(--black);
box-shadow: 0 8px 22px rgba(201, 180, 134, 0.35);
}
.btn-gold:hover { transform: translateY(-2px); box-shadow: 0 12px 30px rgba(201, 180, 134, 0.45); }
.btn-gold:active { transform: translateY(0); }
.btn-ghost {
background: transparent;
color: var(--ink);
border: 1px solid var(--line-2);
}
.btn-ghost:hover { border-color: var(--black); background: rgba(12, 12, 15, 0.04); transform: translateY(-2px); }
.btn:focus-visible { outline: 2px solid var(--champagne-d); outline-offset: 3px; }
/* ===== nav ===== */
.nav {
position: sticky;
top: 0;
z-index: 50;
background: rgba(12, 12, 15, 0.92);
backdrop-filter: blur(12px);
border-bottom: 1px solid rgba(230, 210, 168, 0.14);
color: #fff;
}
.nav-inner { display: flex; align-items: center; gap: 1.5rem; height: 72px; }
.brand { display: inline-flex; align-items: center; gap: 0.6rem; color: #fff; }
.brand-mark {
width: 34px; height: 34px; border-radius: 50%;
display: grid; place-items: center;
border: 1px solid var(--line-gold);
color: var(--champagne);
}
.brand-text { font-family: var(--serif); font-weight: 600; font-size: 1.2rem; letter-spacing: 0.18em; }
.brand-text em { color: var(--champagne); font-style: normal; }
.nav-links { display: flex; gap: 1.7rem; margin-left: auto; }
.nav-links a {
font-size: 0.78rem; letter-spacing: 0.08em; text-transform: uppercase;
color: rgba(255, 255, 255, 0.78); position: relative; padding: 4px 0;
}
.nav-links a::after {
content: ""; position: absolute; left: 0; bottom: -2px; width: 0; height: 1px;
background: var(--champagne); transition: width 0.25s ease;
}
.nav-links a:hover { color: #fff; }
.nav-links a:hover::after { width: 100%; }
.nav-cta { display: flex; align-items: center; gap: 1.1rem; }
.phone { font-size: 0.82rem; letter-spacing: 0.05em; color: var(--champagne); font-weight: 500; }
.phone:hover { color: #fff; }
.burger { display: none; background: none; border: 0; cursor: pointer; flex-direction: column; gap: 5px; padding: 6px; }
.burger span { width: 24px; height: 2px; background: var(--champagne); transition: 0.25s ease; }
.burger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger.open span:nth-child(2) { opacity: 0; }
.burger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.mobile-nav {
display: none;
flex-direction: column;
gap: 0.3rem;
padding: 0.5rem 4vw 1.4rem;
background: var(--black);
border-bottom: 1px solid rgba(230, 210, 168, 0.14);
}
.mobile-nav.open { display: flex; }
.mobile-nav a {
color: rgba(255, 255, 255, 0.85); padding: 0.85rem 0.2rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
text-transform: uppercase; font-size: 0.82rem; letter-spacing: 0.07em;
}
.mobile-nav .btn { margin-top: 0.8rem; }
/* ===== hero ===== */
.hero { position: relative; color: #fff; overflow: hidden; }
.hero-bg {
position: absolute; inset: 0;
background:
radial-gradient(1100px 500px at 78% -10%, rgba(230, 210, 168, 0.22), transparent 60%),
radial-gradient(800px 600px at 10% 110%, rgba(111, 118, 134, 0.25), transparent 55%),
linear-gradient(160deg, #0c0c0f 0%, #16161c 55%, #0c0c0f 100%);
}
.hero-bg::after {
content: ""; position: absolute; inset: 0;
background-image: linear-gradient(transparent 96%, rgba(230, 210, 168, 0.05) 96%);
background-size: 100% 26px;
}
.hero-grid {
position: relative;
display: grid;
grid-template-columns: 1.25fr 0.85fr;
gap: 3.5rem;
align-items: center;
padding: 5.5rem 0 5rem;
}
.eyebrow {
display: inline-block;
font-size: 0.74rem; letter-spacing: 0.22em; text-transform: uppercase;
color: var(--champagne); margin-bottom: 1.4rem;
padding-bottom: 0.6rem; border-bottom: 1px solid var(--line-gold);
}
.hero-copy h1 {
font-size: clamp(2.7rem, 6vw, 4.6rem);
line-height: 1.02; letter-spacing: -0.01em; margin-bottom: 1.4rem;
}
.hero-copy h1 em { color: var(--champagne); }
.lede { font-size: 1.1rem; color: rgba(255, 255, 255, 0.82); max-width: 44ch; margin: 0 0 2.2rem; }
.hero-actions { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 3rem; }
.hero-stats {
list-style: none; margin: 0; padding: 1.6rem 0 0; display: flex; gap: 2.6rem;
border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.hero-stats strong { display: block; font-family: var(--serif); font-size: 1.8rem; color: var(--champagne); }
.hero-stats span { font-size: 0.74rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
/* ===== quote rail ===== */
.quote-rail {
background: var(--surface);
color: var(--ink);
border-radius: var(--r-lg);
padding: 2.1rem 1.9rem;
box-shadow: var(--shadow-lg);
border: 1px solid var(--line);
position: relative;
}
.quote-rail::before {
content: ""; position: absolute; inset: 0; border-radius: var(--r-lg);
padding: 1px; pointer-events: none;
background: linear-gradient(135deg, var(--champagne), transparent 50%);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor; mask-composite: exclude;
}
.rail-kicker { font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--champagne-d); margin: 0 0 0.4rem; }
.rail-title { font-size: 1.55rem; margin-bottom: 1.3rem; }
.rail-form { display: grid; gap: 0.85rem; }
.rail-form label, .field label {
display: block; font-size: 0.72rem; letter-spacing: 0.07em; text-transform: uppercase;
color: var(--muted); font-weight: 600;
}
.rail-form input, .field input, .field select, .field textarea {
width: 100%; margin-top: 0.4rem;
font-family: var(--sans); font-size: 0.95rem; color: var(--ink);
padding: 0.72rem 0.85rem;
border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--bg);
transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.rail-form input:focus, .field input:focus, .field select:focus, .field textarea:focus {
outline: none; border-color: var(--champagne-d); background: #fff;
box-shadow: 0 0 0 3px rgba(230, 210, 168, 0.3);
}
.field input.invalid, .field select.invalid, .field textarea.invalid,
.rail-form input.invalid { border-color: #c4564a; box-shadow: 0 0 0 3px rgba(196, 86, 74, 0.18); }
.rail-fine { font-size: 0.74rem; color: var(--muted); margin: 1rem 0 0; }
/* ===== trust strip ===== */
.strip { background: var(--black); color: rgba(255, 255, 255, 0.82); }
.strip-inner {
display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
gap: 1.4rem; padding: 1.1rem 0;
font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase;
}
.strip-inner i { width: 4px; height: 4px; border-radius: 50%; background: var(--champagne); }
/* ===== sections ===== */
.section { padding: 5.5rem 0; }
.section-dark { background: var(--black); color: #fff; }
.section-soft { background: var(--champagne-50); }
.sec-head { max-width: 56ch; margin: 0 auto 3rem; text-align: center; }
.sec-kicker {
display: inline-block; font-size: 0.74rem; letter-spacing: 0.2em; text-transform: uppercase;
color: var(--slate-d); margin-bottom: 0.9rem;
}
.sec-kicker.gold { color: var(--champagne-d); }
.sec-head h2 { font-size: clamp(2rem, 4vw, 2.9rem); line-height: 1.08; margin-bottom: 1rem; }
.sec-head p { color: var(--ink-2); font-size: 1.02rem; margin: 0; }
.section-dark .sec-head p { color: rgba(255, 255, 255, 0.72); }
/* ===== fleet ===== */
.fleet-tabs { display: flex; justify-content: center; gap: 0.5rem; margin-bottom: 2.5rem; flex-wrap: wrap; }
.ftab {
font-family: var(--sans); font-size: 0.78rem; letter-spacing: 0.07em; text-transform: uppercase;
font-weight: 600; padding: 0.65em 1.4em; border-radius: 999px; cursor: pointer;
border: 1px solid var(--line-2); background: transparent; color: var(--ink-2);
transition: 0.2s ease;
}
.ftab:hover { border-color: var(--black); }
.ftab.is-active { background: var(--black); color: var(--champagne); border-color: var(--black); }
.ftab:focus-visible { outline: 2px solid var(--champagne-d); outline-offset: 2px; }
.fleet-grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 1.6rem; align-items: stretch; }
.fleet-card {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
overflow: hidden; box-shadow: var(--shadow-sm); display: flex; flex-direction: column;
}
.fleet-art {
height: 200px; display: grid; place-items: center;
background: linear-gradient(150deg, #0c0c0f, #20202a);
color: var(--champagne);
}
.fleet-art svg { width: 70%; max-width: 320px; opacity: 0.92; }
.fleet-body { padding: 1.8rem; }
.fleet-tag {
display: inline-block; font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
color: var(--champagne-d); margin-bottom: 0.6rem; font-weight: 600;
}
.fleet-body h3 { font-size: 1.7rem; margin-bottom: 0.6rem; }
.fleet-body > p { color: var(--ink-2); margin: 0 0 1.4rem; font-size: 0.98rem; }
.fleet-specs { display: grid; grid-template-columns: 1fr 1fr; gap: 0.9rem 1.4rem; margin: 0; }
.fleet-specs div { border-top: 1px solid var(--line); padding-top: 0.7rem; }
.fleet-specs dt { font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.fleet-specs dd { margin: 0.2rem 0 0; font-family: var(--serif); font-size: 1.35rem; font-weight: 600; color: var(--ink); }
.fleet-features {
list-style: none; margin: 0; padding: 0; display: grid; gap: 0.7rem; align-content: start;
}
.fleet-features li {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
padding: 1rem 1.2rem; display: flex; gap: 0.85rem; align-items: flex-start;
box-shadow: var(--shadow-sm); transition: transform 0.2s ease, border-color 0.2s ease;
}
.fleet-features li:hover { transform: translateX(4px); border-color: var(--champagne-d); }
.fleet-features b { font-family: var(--serif); font-size: 1.05rem; display: block; }
.fleet-features span { color: var(--muted); font-size: 0.86rem; }
.fleet-features .ff-mark { color: var(--champagne-d); font-size: 1.1rem; line-height: 1.3; }
/* ===== tiers ===== */
.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.4rem; align-items: stretch; }
.tier {
position: relative;
background: var(--black-2); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: var(--r-lg);
padding: 2rem 1.7rem; display: flex; flex-direction: column;
transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}
.tier:hover { transform: translateY(-6px); border-color: var(--line-gold); box-shadow: var(--shadow-lg); }
.tier-feature {
background: linear-gradient(170deg, #1c1b18, #131217);
border-color: var(--champagne-d);
box-shadow: 0 24px 60px rgba(230, 210, 168, 0.12);
}
.tier-flag {
position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
background: linear-gradient(135deg, var(--champagne), var(--champagne-d)); color: var(--black);
font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 700;
padding: 0.35em 1em; border-radius: 999px; white-space: nowrap;
}
.tier header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 1rem; }
.tier-name { font-family: var(--serif); font-size: 1.5rem; color: #fff; }
.tier-hours { font-size: 0.82rem; letter-spacing: 0.06em; color: var(--champagne); }
.tier-price { margin: 0 0 1.4rem; }
.tier-price span { font-family: var(--serif); font-size: 2.2rem; color: var(--champagne); font-weight: 600; }
.tier-price small { display: block; font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); margin-top: 0.2rem; }
.tier ul { list-style: none; margin: 0 0 1.7rem; padding: 0; display: grid; gap: 0.7rem; }
.tier li {
font-size: 0.9rem; color: rgba(255, 255, 255, 0.82); padding-left: 1.4rem; position: relative;
}
.tier li::before { content: "◆"; position: absolute; left: 0; color: var(--champagne-d); font-size: 0.7rem; top: 0.18rem; }
.tier .btn { margin-top: auto; }
.tier .btn-ghost { color: #fff; border-color: rgba(255, 255, 255, 0.25); }
.tier .btn-ghost:hover { border-color: var(--champagne); background: rgba(230, 210, 168, 0.08); }
/* ===== steps ===== */
.steps {
list-style: none; margin: 0; padding: 0;
display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.4rem;
counter-reset: step;
}
.steps li {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
padding: 1.8rem 1.5rem; box-shadow: var(--shadow-sm); position: relative;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.steps li:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.step-no {
font-family: var(--serif); font-size: 2rem; color: var(--champagne-d);
display: block; margin-bottom: 0.8rem;
}
.steps h3 { font-size: 1.25rem; margin-bottom: 0.5rem; }
.steps p { color: var(--ink-2); font-size: 0.92rem; margin: 0; }
/* ===== concierge ===== */
.concierge-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3.5rem; align-items: center; }
.concierge-title { font-size: clamp(2rem, 4vw, 2.9rem); margin: 0.4rem 0 1rem; }
.concierge-lede { color: var(--ink-2); font-size: 1.05rem; max-width: 42ch; margin: 0 0 1.8rem; }
.concierge-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.9rem; }
.concierge-list li {
display: flex; gap: 0.8rem; align-items: center; font-size: 1rem; color: var(--ink);
padding-bottom: 0.9rem; border-bottom: 1px solid var(--line);
}
.concierge-list span { color: var(--champagne-d); font-size: 0.8rem; }
.concierge-quote {
background: var(--black); color: #fff; border-radius: var(--r-lg);
padding: 2.6rem 2.4rem; box-shadow: var(--shadow-lg); margin: 0;
border: 1px solid var(--line-gold);
}
.concierge-quote blockquote {
margin: 0 0 1.6rem; font-family: var(--serif); font-style: italic;
font-size: 1.55rem; line-height: 1.35; color: var(--champagne-50);
}
.concierge-quote figcaption strong { display: block; color: var(--champagne); font-family: var(--serif); font-size: 1.1rem; }
.concierge-quote figcaption span { font-size: 0.8rem; color: var(--muted); letter-spacing: 0.04em; }
/* ===== quote section ===== */
.quote-sec { background: var(--black); color: #fff; }
.quote-wrap {
display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 3rem; align-items: start;
}
.quote-intro h2 { font-size: clamp(2rem, 4vw, 2.9rem); margin: 0.4rem 0 1rem; }
.quote-intro p { color: rgba(255, 255, 255, 0.74); max-width: 38ch; }
.quote-form {
background: var(--surface); color: var(--ink); border-radius: var(--r-lg);
padding: 2.2rem; display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem;
box-shadow: var(--shadow-lg);
}
.field-full { grid-column: 1 / -1; }
.quote-form .btn { grid-column: 1 / -1; }
.quote-fine { grid-column: 1 / -1; font-size: 0.74rem; color: var(--muted); margin: 0; text-align: center; }
/* ===== footer ===== */
.footer { background: var(--black); color: rgba(255, 255, 255, 0.7); padding: 3.5rem 0 1.8rem; border-top: 1px solid rgba(230, 210, 168, 0.14); }
.foot-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 2rem; padding-bottom: 2.4rem; border-bottom: 1px solid rgba(255, 255, 255, 0.1); }
.foot-brand .brand-text { color: #fff; font-size: 1.3rem; }
.foot-brand p { margin: 1rem 0; max-width: 32ch; font-size: 0.9rem; }
.foot-phone { color: var(--champagne); font-weight: 500; letter-spacing: 0.05em; }
.footer h4 { font-family: var(--sans); font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--champagne); margin-bottom: 1rem; }
.footer nav a { display: block; padding: 0.32rem 0; font-size: 0.9rem; color: rgba(255, 255, 255, 0.7); transition: color 0.2s ease; }
.footer nav a:hover { color: var(--champagne); }
.foot-base { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding-top: 1.6rem; font-size: 0.78rem; color: var(--muted); }
/* ===== toast ===== */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 24px);
background: var(--black); color: var(--champagne-50);
border: 1px solid var(--line-gold); border-radius: var(--r-md);
padding: 0.85rem 1.3rem; font-size: 0.88rem; box-shadow: var(--shadow-lg);
opacity: 0; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; z-index: 100;
max-width: min(420px, 90vw);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast strong { color: var(--champagne); }
/* ===== reveal ===== */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.7s ease, transform 0.7s ease; }
.reveal.in { opacity: 1; transform: none; }
/* ===== responsive ===== */
@media (max-width: 960px) {
.nav-links, .nav-cta { display: none; }
.burger { display: flex; }
.hero-grid { grid-template-columns: 1fr; gap: 2.5rem; padding: 3.5rem 0 4rem; }
.fleet-grid, .concierge-grid, .quote-wrap { grid-template-columns: 1fr; gap: 2rem; }
.tiers { grid-template-columns: 1fr; max-width: 460px; margin-inline: auto; }
.steps { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
.wrap { width: 90vw; }
.section { padding: 4rem 0; }
.hero-copy h1 { font-size: clamp(2.3rem, 11vw, 3rem); }
.hero-stats { gap: 1.4rem; }
.hero-stats strong { font-size: 1.4rem; }
.hero-actions .btn { width: 100%; }
.steps { grid-template-columns: 1fr; }
.quote-form { grid-template-columns: 1fr; padding: 1.6rem; }
.fleet-specs { grid-template-columns: 1fr; }
.foot-grid { grid-template-columns: 1fr 1fr; }
.foot-base { flex-direction: column; }
}
@media (prefers-reduced-motion: reduce) {
* { scroll-behavior: auto !important; }
.reveal { opacity: 1; transform: none; transition: none; }
}(function () {
"use strict";
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.innerHTML = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 3600);
}
/* ---------- smooth scroll for data-scroll buttons ---------- */
document.querySelectorAll("[data-scroll]").forEach(function (btn) {
btn.addEventListener("click", function () {
var target = document.querySelector(btn.getAttribute("data-scroll"));
if (target) target.scrollIntoView({ behavior: "smooth", block: "start" });
closeMobile();
});
});
/* ---------- mobile nav ---------- */
var burger = document.getElementById("burger");
var mobileNav = document.getElementById("mobileNav");
function closeMobile() {
if (!burger) return;
burger.classList.remove("open");
burger.setAttribute("aria-expanded", "false");
mobileNav.classList.remove("open");
}
if (burger) {
burger.addEventListener("click", function () {
var open = burger.classList.toggle("open");
burger.setAttribute("aria-expanded", open ? "true" : "false");
mobileNav.classList.toggle("open", open);
});
mobileNav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", closeMobile);
});
}
/* ---------- fleet data + tabs ---------- */
var FLEET = {
light: {
tag: "Light Jet",
name: "Méridian Phenom 300E",
desc: "Nimble and efficient for short hops and quick getaways — ideal for regional jaunts and one-day round trips.",
pax: "6",
range: "2,010 nm",
speed: "453 kt",
price: "$4,200/hr",
features: [
["Best for", "1–3 hour sectors, KTEB → KMVY, EGGW → LFMN"],
["Cabin", "Stand-up comfort for six, refreshment centre"],
["Runway", "Access to short fields larger jets cannot reach"]
]
},
mid: {
tag: "Midsize Jet",
name: "Méridian Praetor 600",
desc: "The everyday workhorse of the fleet — transcontinental range with a fully appointed cabin and a generous baggage hold.",
pax: "9",
range: "4,018 nm",
speed: "466 kt",
price: "$7,600/hr",
features: [
["Best for", "Coast-to-coast U.S. or transatlantic with a tailwind"],
["Cabin", "Flat-floor stand-up cabin, full galley, enclosed lavatory"],
["Connectivity", "Ka-band Wi-Fi suitable for live video calls"]
]
},
heavy: {
tag: "Heavy Jet",
name: "Méridian Global 7500",
desc: "Long-range flagship with four living zones and a permanent crew rest — intercontinental in a single, seamless leg.",
pax: "14",
range: "7,700 nm",
speed: "516 kt",
price: "$14,900/hr",
features: [
["Best for", "Nonstop New York → Tokyo, London → Cape Town"],
["Cabin", "Four zones: dining, conference, lounge, private suite"],
["Crew", "Dedicated cabin host and onboard chef on request"]
]
}
};
var els = {
tag: document.getElementById("fleetTag"),
name: document.getElementById("fleetName"),
desc: document.getElementById("fleetDesc"),
pax: document.getElementById("specPax"),
range: document.getElementById("specRange"),
speed: document.getElementById("specSpeed"),
price: document.getElementById("specPrice"),
features: document.getElementById("fleetFeatures"),
card: document.getElementById("fleetCard")
};
function renderFleet(key) {
var d = FLEET[key];
if (!d) return;
els.tag.textContent = d.tag;
els.name.textContent = d.name;
els.desc.textContent = d.desc;
els.pax.textContent = d.pax;
els.range.textContent = d.range;
els.speed.textContent = d.speed;
els.price.textContent = d.price;
els.features.innerHTML = d.features
.map(function (f) {
return (
'<li><span class="ff-mark" aria-hidden="true">◆</span>' +
"<span><b>" + f[0] + "</b><span>" + f[1] + "</span></span></li>"
);
})
.join("");
// subtle re-entrance animation
els.card.style.opacity = "0";
els.card.style.transform = "translateY(10px)";
requestAnimationFrame(function () {
els.card.style.transition = "opacity .4s ease, transform .4s ease";
els.card.style.opacity = "1";
els.card.style.transform = "none";
});
}
var tabs = document.querySelectorAll(".ftab");
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("is-active");
t.setAttribute("aria-selected", "false");
});
tab.classList.add("is-active");
tab.setAttribute("aria-selected", "true");
renderFleet(tab.getAttribute("data-fleet"));
});
});
renderFleet("light");
/* ---------- form validation helpers ---------- */
function markInvalid(field) {
field.classList.add("invalid");
field.addEventListener(
"input",
function () { field.classList.remove("invalid"); },
{ once: true }
);
}
function validate(form) {
var ok = true;
var firstBad = null;
form.querySelectorAll("[required]").forEach(function (f) {
var val = (f.value || "").trim();
var bad = !val;
if (f.type === "email" && val) bad = !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
if (bad) {
markInvalid(f);
ok = false;
if (!firstBad) firstBad = f;
}
});
if (firstBad) firstBad.focus();
return ok;
}
/* ---------- rail (hero) form -> scroll to full quote ---------- */
var railForm = document.getElementById("railForm");
if (railForm) {
railForm.addEventListener("submit", function (e) {
e.preventDefault();
if (!validate(railForm)) {
toast("Please complete the route and date.");
return;
}
var data = new FormData(railForm);
// prefill the full quote form
var setIf = function (id, v) {
var el = document.getElementById(id);
if (el && v) el.value = v;
};
setIf("qFrom", data.get("from"));
setIf("qTo", data.get("to"));
setIf("qDate", data.get("date"));
var quote = document.getElementById("quote");
if (quote) quote.scrollIntoView({ behavior: "smooth", block: "start" });
toast("Carried over — just add your details below.");
});
}
/* ---------- full quote form ---------- */
var quoteForm = document.getElementById("quoteForm");
if (quoteForm) {
quoteForm.addEventListener("submit", function (e) {
e.preventDefault();
if (!validate(quoteForm)) {
toast("A few fields still need your attention.");
return;
}
var data = new FormData(quoteForm);
var name = (data.get("name") || "").trim().split(" ")[0] || "there";
var from = (data.get("from") || "").trim();
var to = (data.get("to") || "").trim();
var btn = quoteForm.querySelector('button[type="submit"]');
if (btn) {
btn.disabled = true;
btn.textContent = "Sending…";
}
setTimeout(function () {
quoteForm.reset();
if (btn) {
btn.disabled = false;
btn.textContent = "Send request";
}
toast(
"Thank you, <strong>" +
name +
"</strong> — an advisor will reach out about " +
(from && to ? from + " → " + to : "your trip") +
" within the hour."
);
}, 900);
});
}
/* ---------- scroll reveal ---------- */
var reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(
function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting) {
en.target.classList.add("in");
io.unobserve(en.target);
}
});
},
{ threshold: 0.14, rootMargin: "0px 0px -40px 0px" }
);
reveals.forEach(function (r) { io.observe(r); });
} else {
reveals.forEach(function (r) { r.classList.add("in"); });
}
/* ---------- min date = today on date inputs ---------- */
var today = new Date().toISOString().split("T")[0];
document.querySelectorAll('input[type="date"]').forEach(function (d) {
d.min = today;
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Méridian Air — Private Charter & Jet Card</title>
<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@500;600;700&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- ===== NAV ===== -->
<header class="nav" id="top">
<div class="wrap nav-inner">
<a href="#top" class="brand" aria-label="Méridian Air home">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5z"/></svg>
</span>
<span class="brand-text">MÉRIDIAN <em>AIR</em></span>
</a>
<nav class="nav-links" aria-label="Primary">
<a href="#fleet">Fleet</a>
<a href="#card">Jet Card</a>
<a href="#process">On Demand</a>
<a href="#concierge">Concierge</a>
</nav>
<div class="nav-cta">
<a href="tel:+18005550199" class="phone" aria-label="Call the charter desk">+1 800 555 0199</a>
<button class="btn btn-gold" data-scroll="#quote">Request a Quote</button>
</div>
<button class="burger" id="burger" aria-label="Open menu" aria-expanded="false" aria-controls="mobileNav">
<span></span><span></span><span></span>
</button>
</div>
<nav class="mobile-nav" id="mobileNav" aria-label="Mobile">
<a href="#fleet">Fleet</a>
<a href="#card">Jet Card</a>
<a href="#process">On Demand</a>
<a href="#concierge">Concierge</a>
<button class="btn btn-gold" data-scroll="#quote">Request a Quote</button>
</nav>
</header>
<main>
<!-- ===== HERO ===== -->
<section class="hero">
<div class="hero-bg" aria-hidden="true"></div>
<div class="wrap hero-grid">
<div class="hero-copy reveal">
<span class="eyebrow">Private aviation · By invitation</span>
<h1>The sky, on<br><em>your</em> schedule.</h1>
<p class="lede">Bespoke jet charter and membership for those who measure time in moments, not minutes. Wheels up in as little as four hours, anywhere our fleet flies.</p>
<div class="hero-actions">
<button class="btn btn-gold lg" data-scroll="#quote">Request a Quote</button>
<a class="btn btn-ghost lg" href="#fleet">Explore the Fleet</a>
</div>
<ul class="hero-stats">
<li><strong class="tnum">4 hrs</strong><span>Average call-out</span></li>
<li><strong class="tnum">5,000+</strong><span>Airports served</span></li>
<li><strong class="tnum">98.9%</strong><span>On-time departure</span></li>
</ul>
</div>
<aside class="quote-rail reveal" aria-label="Quick quote">
<p class="rail-kicker">Begin discreetly</p>
<h2 class="rail-title">Where shall we take you?</h2>
<form class="rail-form" id="railForm" novalidate>
<label>From
<input type="text" name="from" placeholder="New York (KTEB)" autocomplete="off" required />
</label>
<label>To
<input type="text" name="to" placeholder="London (EGGW)" autocomplete="off" required />
</label>
<label>When
<input type="date" name="date" required />
</label>
<button class="btn btn-gold full" type="submit">Continue request</button>
</form>
<p class="rail-fine">No obligation. A charter advisor responds within the hour.</p>
</aside>
</div>
</section>
<!-- ===== TRUST STRIP ===== -->
<section class="strip" aria-label="Credentials">
<div class="wrap strip-inner">
<span>ARGUS Platinum</span><i></i>
<span>IS-BAO Stage 3</span><i></i>
<span>Wyvern Wingman</span><i></i>
<span>24/7 Concierge</span>
</div>
</section>
<!-- ===== FLEET ===== -->
<section class="section" id="fleet">
<div class="wrap">
<header class="sec-head reveal">
<span class="sec-kicker">The Fleet</span>
<h2>Aircraft for every distance</h2>
<p>Each tail is owned or vetted to our standard, crewed by two ATP pilots, and presented immaculately. Select a category to preview its character.</p>
</header>
<div class="fleet-tabs reveal" role="tablist" aria-label="Aircraft categories">
<button class="ftab is-active" role="tab" aria-selected="true" data-fleet="light">Light Jet</button>
<button class="ftab" role="tab" aria-selected="false" data-fleet="mid">Midsize Jet</button>
<button class="ftab" role="tab" aria-selected="false" data-fleet="heavy">Heavy Jet</button>
</div>
<div class="fleet-grid reveal">
<article class="fleet-card" id="fleetCard">
<div class="fleet-art" aria-hidden="true">
<svg viewBox="0 0 120 60" fill="none" stroke="currentColor" stroke-width="1.2"><path d="M6 34c14-3 30-5 48-5 10 0 18 1 24 3 8 2 30 3 34 1-2-3-22-7-30-8-4-6-9-11-13-11-2 0-2 4-1 9-8-1-16-1-24 0l-9-9c-2-2-4-1-3 2l3 8c-12 2-22 5-29 8z"/></svg>
</div>
<div class="fleet-body">
<span class="fleet-tag" id="fleetTag">Light Jet</span>
<h3 id="fleetName">Méridian Phenom 300E</h3>
<p id="fleetDesc">Nimble and efficient for short hops and quick getaways — ideal for regional jaunts and one-day round trips.</p>
<dl class="fleet-specs">
<div><dt>Passengers</dt><dd class="tnum" id="specPax">6</dd></div>
<div><dt>Range</dt><dd class="tnum" id="specRange">2,010 nm</dd></div>
<div><dt>Cruise</dt><dd class="tnum" id="specSpeed">453 kt</dd></div>
<div><dt>From</dt><dd class="tnum" id="specPrice">$4,200/hr</dd></div>
</dl>
</div>
</article>
<ul class="fleet-features" id="fleetFeatures"></ul>
</div>
</div>
</section>
<!-- ===== JET CARD TIERS ===== -->
<section class="section section-dark" id="card">
<div class="wrap">
<header class="sec-head reveal">
<span class="sec-kicker gold">Membership</span>
<h2>The Méridian Jet Card</h2>
<p>Pre-funded flight hours with fixed hourly rates, guaranteed availability, and a single advisor who knows you by name. Three tiers, no asterisks.</p>
</header>
<div class="tiers reveal">
<article class="tier">
<header><span class="tier-name">Voyager</span><span class="tier-hours tnum">25 hrs</span></header>
<p class="tier-price"><span class="tnum">$165,000</span><small>deposit</small></p>
<ul>
<li>Fixed light & midsize rates</li>
<li>72-hour booking window</li>
<li>Dedicated advisor</li>
<li>Catering & ground included</li>
</ul>
<button class="btn btn-ghost full" data-scroll="#quote">Enquire</button>
</article>
<article class="tier tier-feature">
<span class="tier-flag">Most chosen</span>
<header><span class="tier-name">Meridian</span><span class="tier-hours tnum">50 hrs</span></header>
<p class="tier-price"><span class="tnum">$385,000</span><small>deposit</small></p>
<ul>
<li>All Voyager benefits</li>
<li>48-hour guaranteed availability</li>
<li>One-way pricing, no repositioning</li>
<li>Complimentary cabin upgrades</li>
<li>Concierge lifestyle desk</li>
</ul>
<button class="btn btn-gold full" data-scroll="#quote">Enquire</button>
</article>
<article class="tier">
<header><span class="tier-name">Zenith</span><span class="tier-hours tnum">100 hrs</span></header>
<p class="tier-price"><span class="tnum">$890,000</span><small>deposit</small></p>
<ul>
<li>All Meridian benefits</li>
<li>10-hour guaranteed availability</li>
<li>Heavy-jet fixed rates</li>
<li>Global itineraries & visas</li>
</ul>
<button class="btn btn-ghost full" data-scroll="#quote">Enquire</button>
</article>
</div>
</div>
</section>
<!-- ===== PROCESS ===== -->
<section class="section" id="process">
<div class="wrap">
<header class="sec-head reveal">
<span class="sec-kicker">On Demand</span>
<h2>From request to runway</h2>
<p>No app to learn, no queue to join. A conversation, a confirmation, and a car waiting on the ramp.</p>
</header>
<ol class="steps reveal">
<li>
<span class="step-no tnum">01</span>
<h3>Tell us the brief</h3>
<p>Route, time, party. By phone, message, or the form below — whatever suits the moment.</p>
</li>
<li>
<span class="step-no tnum">02</span>
<h3>Receive options</h3>
<p>Tailored aircraft and all-in pricing within the hour, with no hidden repositioning fees.</p>
</li>
<li>
<span class="step-no tnum">03</span>
<h3>Confirm in one tap</h3>
<p>Approve digitally. We handle catering, ground transfers, and customs slots.</p>
</li>
<li>
<span class="step-no tnum">04</span>
<h3>Arrive & ascend</h3>
<p>Walk from car to cabin in minutes. Wheels up the moment you are seated.</p>
</li>
</ol>
</div>
</section>
<!-- ===== CONCIERGE ===== -->
<section class="section section-soft" id="concierge">
<div class="wrap concierge-grid">
<div class="reveal">
<span class="sec-kicker">Concierge</span>
<h2 class="concierge-title">Beyond the flight</h2>
<p class="concierge-lede">Your advisor is a single point of contact for far more than the air. Quietly, completely, on your terms.</p>
<ul class="concierge-list">
<li><span aria-hidden="true">◆</span> Reservations, residences & private events</li>
<li><span aria-hidden="true">◆</span> Chauffeur, helicopter & yacht transfers</li>
<li><span aria-hidden="true">◆</span> In-flight dining by Michelin partners</li>
<li><span aria-hidden="true">◆</span> Pet, medical & security travel</li>
</ul>
</div>
<figure class="concierge-quote reveal">
<blockquote>"They moved a board meeting across three cities in a day and we never once felt the logistics. That is the whole point."</blockquote>
<figcaption><strong>Eleanor Vance</strong><span>Jet Card member since 2019</span></figcaption>
</figure>
</div>
</section>
<!-- ===== QUOTE FORM ===== -->
<section class="section quote-sec" id="quote">
<div class="wrap quote-wrap reveal">
<div class="quote-intro">
<span class="sec-kicker gold">Request a Quote</span>
<h2>Start your itinerary</h2>
<p>Share the essentials and a charter advisor will respond personally — typically within the hour, discreetly and without obligation.</p>
</div>
<form class="quote-form" id="quoteForm" novalidate>
<div class="field">
<label for="qName">Full name</label>
<input id="qName" name="name" type="text" placeholder="Alexandra Whitmore" required />
</div>
<div class="field">
<label for="qEmail">Email</label>
<input id="qEmail" name="email" type="email" placeholder="[email protected]" required />
</div>
<div class="field">
<label for="qFrom">Departure</label>
<input id="qFrom" name="from" type="text" placeholder="New York (KTEB)" required />
</div>
<div class="field">
<label for="qTo">Destination</label>
<input id="qTo" name="to" type="text" placeholder="London (EGGW)" required />
</div>
<div class="field">
<label for="qDate">Date</label>
<input id="qDate" name="date" type="date" required />
</div>
<div class="field">
<label for="qPax">Passengers</label>
<select id="qPax" name="pax">
<option>1–2</option><option>3–4</option><option>5–6</option><option>7–9</option><option>10+</option>
</select>
</div>
<div class="field field-full">
<label for="qTier">Interested in</label>
<select id="qTier" name="tier">
<option>On-demand charter</option>
<option>Voyager Jet Card · 25 hrs</option>
<option>Meridian Jet Card · 50 hrs</option>
<option>Zenith Jet Card · 100 hrs</option>
</select>
</div>
<div class="field field-full">
<label for="qNotes">Notes (optional)</label>
<textarea id="qNotes" name="notes" rows="2" placeholder="Pets, catering preferences, ground transport…"></textarea>
</div>
<button class="btn btn-gold full lg" type="submit">Send request</button>
<p class="quote-fine">By submitting you agree to be contacted by a Méridian advisor. We never share your details.</p>
</form>
</div>
</section>
</main>
<!-- ===== FOOTER ===== -->
<footer class="footer">
<div class="wrap foot-grid">
<div class="foot-brand">
<span class="brand-text">MÉRIDIAN <em>AIR</em></span>
<p>Bespoke private aviation. Members and charter clients across 60 countries.</p>
<a href="tel:+18005550199" class="foot-phone">+1 800 555 0199</a>
</div>
<nav aria-label="Fleet">
<h4>Fleet</h4>
<a href="#fleet">Light jets</a>
<a href="#fleet">Midsize jets</a>
<a href="#fleet">Heavy jets</a>
</nav>
<nav aria-label="Membership">
<h4>Membership</h4>
<a href="#card">Voyager</a>
<a href="#card">Meridian</a>
<a href="#card">Zenith</a>
</nav>
<nav aria-label="Company">
<h4>Company</h4>
<a href="#concierge">Concierge</a>
<a href="#process">Safety</a>
<a href="#quote">Contact</a>
</nav>
</div>
<div class="wrap foot-base">
<span>© 2026 Méridian Air, LLC · Fictional brand for demonstration</span>
<span class="foot-legal">Privacy · Terms · ARGUS Platinum Rated</span>
</div>
</footer>
<!-- toast host -->
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Private Charter Landing
A full marketing landing page for Méridian Air, a fictional private-charter and jet-card brand. The aesthetic leans into a black, champagne, and slate palette with a Cormorant Garamond serif for an exclusive, discreet, bespoke feel — Inter with tabular figures handles flight specs, prices, and step numbers. A sticky dark navigation, a split hero with an inline quick-quote rail, and a credentials strip open the page; tabular hero stats and ARGUS Platinum badges set the status-forward tone.
The fleet section is interactive: three tabs (light, midsize, heavy) swap the aircraft card — name, description, passenger/range/cruise/price specs — alongside a matching feature list, with a subtle re-entrance animation on each switch. Below it, three jet-card tiers (Voyager, Meridian, Zenith) highlight the most-chosen plan, a four-step on-demand process explains request-to-runway, and a concierge section pairs lifestyle services with a member testimonial.
Two forms share logic: the hero rail carries the route and date into the full quote form below and scrolls to it, while the main form validates required fields and email format inline, simulates submission with a disabled-button state, and confirms with a personalised toast. Everything is vanilla JS — scroll-reveal via IntersectionObserver, a reusable toast() helper, a mobile burger menu, and date inputs pinned to today — and the layout reflows cleanly down to ~360px.
Illustrative UI only — fictional airline, not a real booking or flight system.