Airline — Airline Landing
A polished marketing landing page for a fictional airline, built with vanilla HTML, CSS, and JavaScript. It pairs a horizon hero with an integrated flight-search widget (round-trip and one-way modes, swap, date defaults), a swipeable fare-deals carousel, a trending-destinations grid, a why-fly-us feature row, a SkyMiles loyalty teaser with a membership card, an app-download block with a boarding-pass mockup, and a full footer. Status pills, tabular figures, and scroll reveals give it an aviation feel.
MCP
Code
:root {
--sky: #0a66c2;
--sky-d: #084e95;
--sky-50: #e9f2fb;
--cloud: #f5f8fc;
--sunrise: #ff7a33;
--sunrise-50: #fff0e7;
--ink: #13233b;
--ink-2: #3a4d68;
--muted: #6b7c93;
--bg: #f5f8fc;
--surface: #ffffff;
--line: rgba(19, 35, 59, 0.1);
--line-2: rgba(19, 35, 59, 0.18);
--ok: #1f9d62;
--warn: #e0962a;
--danger: #d4493e;
--boarding: #1f9d62;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--sh-sm: 0 1px 2px rgba(19, 35, 59, 0.06), 0 1px 3px rgba(19, 35, 59, 0.08);
--sh-md: 0 6px 18px rgba(19, 35, 59, 0.08), 0 2px 6px rgba(19, 35, 59, 0.06);
--sh-lg: 0 18px 50px rgba(19, 35, 59, 0.16);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
color: var(--ink);
background: var(--bg);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.tnum, .tnum * { font-variant-numeric: tabular-nums; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
.wrap { width: min(1140px, 92vw); margin-inline: auto; }
.skip {
position: absolute; left: -999px; top: 0;
background: var(--ink); color: #fff; padding: 10px 16px; border-radius: 0 0 var(--r-sm) 0; z-index: 100;
}
.skip:focus { left: 0; }
/* Buttons */
.btn {
font-family: inherit; font-size: .92rem; font-weight: 600;
border: 1px solid transparent; border-radius: var(--r-sm);
padding: .62rem 1.05rem; cursor: pointer; transition: transform .12s, box-shadow .15s, background .15s;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--sky); outline-offset: 2px; }
.btn.primary { background: var(--sky); color: #fff; box-shadow: var(--sh-sm); }
.btn.primary:hover { background: var(--sky-d); box-shadow: var(--sh-md); }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn.ghost:hover { background: var(--sky-50); border-color: var(--sky); color: var(--sky-d); }
.btn.light { background: #fff; color: var(--sky-d); }
.btn.light:hover { background: var(--sky-50); }
.btn.block { width: 100%; padding: .8rem; font-size: 1rem; margin-top: .35rem; }
/* Header */
.site-head {
position: sticky; top: 0; z-index: 40;
background: rgba(255, 255, 255, 0.86);
backdrop-filter: saturate(1.4) blur(10px);
border-bottom: 1px solid var(--line);
}
.head-inner { display: flex; align-items: center; gap: 1.2rem; height: 66px; }
.brand {
display: inline-flex; align-items: center; gap: .5rem;
font-weight: 800; font-size: 1.22rem; letter-spacing: -.02em; color: var(--ink);
}
.brand-mark {
display: grid; place-items: center; width: 32px; height: 32px;
border-radius: 9px; background: linear-gradient(135deg, var(--sky), var(--sky-d)); color: #fff;
}
.nav { display: flex; gap: .35rem; margin-left: .5rem; }
.nav a {
padding: .5rem .7rem; border-radius: var(--r-sm); font-weight: 500; font-size: .92rem; color: var(--ink-2);
}
.nav a:hover { background: var(--sky-50); color: var(--sky-d); }
.head-actions { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.nav-toggle {
display: none; flex-direction: column; gap: 5px; width: 42px; height: 38px;
border: 1px solid var(--line-2); border-radius: var(--r-sm); background: #fff; cursor: pointer;
align-items: center; justify-content: center;
}
.nav-toggle span { width: 18px; height: 2px; background: var(--ink); border-radius: 2px; transition: transform .2s, opacity .2s; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* Hero */
.hero {
position: relative; overflow: hidden;
background:
radial-gradient(900px 420px at 88% -8%, var(--sunrise-50), transparent 60%),
radial-gradient(1000px 560px at 8% 0%, var(--sky-50), transparent 62%),
linear-gradient(180deg, #fff, var(--bg));
border-bottom: 1px solid var(--line);
}
.hero::after {
content: ""; position: absolute; inset: 0; pointer-events: none;
background-image: linear-gradient(var(--line) 1px, transparent 1px);
background-size: 100% 92px; opacity: .35; mask-image: linear-gradient(180deg, transparent, #000 30%, transparent);
}
.hero-inner {
position: relative; z-index: 1;
display: grid; grid-template-columns: 1.05fr .95fr; gap: 2.4rem; align-items: center;
padding: clamp(2.2rem, 6vw, 4.6rem) 0;
}
.eyebrow {
display: inline-block; font-size: .76rem; font-weight: 700; letter-spacing: .04em;
color: var(--sunrise); background: var(--sunrise-50); padding: .35rem .65rem; border-radius: 999px;
}
.eyebrow.light { color: #fff; background: rgba(255, 255, 255, 0.18); }
.hero h1 {
margin: .85rem 0 .6rem; font-size: clamp(2.4rem, 6vw, 4rem); line-height: 1.04; letter-spacing: -.03em; font-weight: 800;
}
.hero h1 .hl {
background: linear-gradient(90deg, var(--sky), var(--sunrise)); -webkit-background-clip: text;
background-clip: text; color: transparent;
}
.lede { font-size: 1.08rem; color: var(--ink-2); max-width: 30rem; }
.hero-stats { display: flex; gap: 1.8rem; margin-top: 1.6rem; flex-wrap: wrap; }
.hero-stats strong { display: block; font-size: 1.5rem; font-weight: 800; letter-spacing: -.02em; }
.hero-stats span { font-size: .82rem; color: var(--muted); }
/* Search card */
.search-card {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
box-shadow: var(--sh-lg); padding: 1.1rem; position: relative;
}
.trip-toggle {
display: inline-flex; background: var(--cloud); border: 1px solid var(--line); border-radius: 999px;
padding: 3px; margin-bottom: 1rem;
}
.trip-opt {
border: none; background: transparent; font-family: inherit; font-weight: 600; font-size: .85rem;
color: var(--ink-2); padding: .42rem .9rem; border-radius: 999px; cursor: pointer; transition: background .15s, color .15s;
}
.trip-opt.active { background: #fff; color: var(--sky-d); box-shadow: var(--sh-sm); }
.field-row { display: flex; gap: .6rem; align-items: flex-end; margin-bottom: .6rem; position: relative; }
.field { flex: 1; display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.field > span { font-size: .72rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.field input, .field select {
font-family: inherit; font-size: .95rem; font-weight: 600; color: var(--ink);
border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: .62rem .7rem; background: #fff; width: 100%;
}
.field input:focus, .field select:focus { outline: none; border-color: var(--sky); box-shadow: 0 0 0 3px var(--sky-50); }
.swap {
flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line-2);
background: #fff; color: var(--sky); font-size: 1.05rem; cursor: pointer; align-self: flex-end; margin-bottom: 1px;
transition: transform .2s, background .15s;
}
.swap:hover { background: var(--sky-50); transform: rotate(180deg); }
.search-note { font-size: .8rem; color: var(--muted); margin: .55rem 0 0; text-align: center; }
.search-card.oneway .return-field { opacity: .45; pointer-events: none; }
/* Sections */
.section { padding: clamp(2.6rem, 6vw, 4.4rem) 0; }
.section.alt { background: linear-gradient(180deg, #fff, var(--cloud)); border-block: 1px solid var(--line); }
.sec-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; margin-bottom: 1.6rem; }
.sec-head.center { justify-content: center; text-align: center; }
.sec-head h2 { font-size: clamp(1.5rem, 3.4vw, 2.1rem); letter-spacing: -.02em; margin: 0; font-weight: 800; }
.sub { color: var(--muted); margin: .35rem 0 0; }
/* Carousel */
.carousel-ctrls { display: flex; gap: .5rem; }
.ctrl {
width: 42px; height: 42px; border-radius: 50%; border: 1px solid var(--line-2); background: #fff;
color: var(--ink); font-size: 1.3rem; cursor: pointer; transition: background .15s, border-color .15s;
}
.ctrl:hover { background: var(--sky-50); border-color: var(--sky); color: var(--sky-d); }
.ctrl:disabled { opacity: .4; cursor: default; }
.carousel { overflow: hidden; }
.track { display: flex; gap: 1rem; transition: transform .4s cubic-bezier(.4, 0, .2, 1); }
.deal {
flex: 0 0 calc((100% - 2rem) / 3); background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-md); overflow: hidden; box-shadow: var(--sh-sm); transition: transform .15s, box-shadow .15s;
display: flex; flex-direction: column;
}
.deal:hover { transform: translateY(-3px); box-shadow: var(--sh-md); }
.deal-img { height: 138px; position: relative; background-size: cover; background-position: center; }
.deal-tag {
position: absolute; top: 10px; left: 10px; font-size: .72rem; font-weight: 700; color: #fff;
background: var(--sunrise); padding: .25rem .55rem; border-radius: 999px;
}
.deal-body { padding: .9rem 1rem 1.05rem; display: flex; flex-direction: column; gap: .25rem; flex: 1; }
.deal-route { display: flex; align-items: center; gap: .45rem; font-weight: 700; font-size: 1.02rem; }
.deal-route .arr { color: var(--sky); }
.deal-city { color: var(--muted); font-size: .82rem; }
.deal-foot { margin-top: auto; padding-top: .65rem; display: flex; align-items: flex-end; justify-content: space-between; }
.deal-price small { display: block; font-size: .72rem; color: var(--muted); }
.deal-price strong { font-size: 1.35rem; font-weight: 800; letter-spacing: -.02em; }
.deal-btn {
border: 1px solid var(--line-2); background: #fff; color: var(--sky-d); font-family: inherit; font-weight: 600;
font-size: .82rem; padding: .45rem .7rem; border-radius: var(--r-sm); cursor: pointer; transition: background .15s;
}
.deal-btn:hover { background: var(--sky-50); }
/* Destinations grid */
.dest-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.dest {
position: relative; border-radius: var(--r-md); overflow: hidden; min-height: 230px; cursor: pointer;
display: flex; align-items: flex-end; color: #fff; background-size: cover; background-position: center;
box-shadow: var(--sh-sm); transition: transform .18s, box-shadow .18s;
}
.dest::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 35%, rgba(8, 20, 36, 0.82)); }
.dest:hover { transform: translateY(-3px); box-shadow: var(--sh-md); }
.dest:hover .dest-info { transform: translateY(-3px); }
.dest-info { position: relative; z-index: 1; padding: 1rem; width: 100%; transition: transform .18s; }
.dest-info .code { font-size: .72rem; font-weight: 700; opacity: .85; letter-spacing: .08em; }
.dest-info h3 { margin: .15rem 0 .3rem; font-size: 1.15rem; }
.dest-info .from { font-size: .85rem; font-weight: 600; }
.dest-info .from b { font-size: 1.05rem; }
.dest.big { grid-row: span 2; min-height: auto; }
/* Features */
.feat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.feat {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 1.4rem 1.2rem;
transition: transform .15s, box-shadow .15s;
}
.feat:hover { transform: translateY(-3px); box-shadow: var(--sh-md); }
.feat-ic {
display: inline-grid; place-items: center; width: 48px; height: 48px; font-size: 1.4rem;
background: var(--sky-50); border-radius: var(--r-sm); margin-bottom: .85rem;
}
.feat h3 { margin: 0 0 .35rem; font-size: 1.08rem; }
.feat p { margin: 0; color: var(--ink-2); font-size: .92rem; }
/* Loyalty */
.loyalty {
display: grid; grid-template-columns: 1.15fr .85fr; gap: 2rem; align-items: center;
background: linear-gradient(135deg, var(--sky-d), var(--sky)); color: #fff;
border-radius: var(--r-lg); padding: clamp(1.6rem, 4vw, 3rem); overflow: hidden; position: relative;
}
.loyalty::before {
content: ""; position: absolute; right: -80px; top: -80px; width: 280px; height: 280px; border-radius: 50%;
background: radial-gradient(circle, rgba(255, 122, 51, 0.5), transparent 70%);
}
.loyalty-copy { position: relative; z-index: 1; }
.loyalty-copy h2 { color: #fff; margin: .7rem 0 .5rem; }
.loyalty-copy p { color: rgba(255, 255, 255, 0.86); max-width: 32rem; }
.tier-bar {
position: relative; height: 30px; background: rgba(255, 255, 255, 0.18); border-radius: 999px; margin: 1.2rem 0 1.3rem;
display: flex; align-items: center;
}
.tier-fill { position: absolute; inset: 0 auto 0 0; background: linear-gradient(90deg, var(--sunrise), #ffb27a); border-radius: 999px; }
.tier-label { position: relative; z-index: 1; font-size: .78rem; font-weight: 700; padding-left: .85rem; }
.loyalty-card { position: relative; z-index: 1; display: grid; place-items: center; }
.mcard {
width: 100%; max-width: 320px; aspect-ratio: 1.6/1; border-radius: var(--r-md);
background: linear-gradient(150deg, #1c2c44, #0b1626); color: #fff; padding: 1.2rem;
box-shadow: var(--sh-lg); display: flex; flex-direction: column; justify-content: space-between;
border: 1px solid rgba(255, 255, 255, 0.12);
}
.mcard-top { display: flex; justify-content: space-between; align-items: center; font-weight: 800; letter-spacing: .02em; }
.chip { font-size: .68rem; background: var(--sunrise); padding: .2rem .5rem; border-radius: 999px; letter-spacing: .08em; }
.mcard-num { font-family: "Inter"; font-variant-numeric: tabular-nums; letter-spacing: .12em; font-size: 1.05rem; font-weight: 600; color: rgba(255, 255, 255, 0.8); }
.mcard-foot { display: flex; justify-content: space-between; }
.mcard-foot small { display: block; font-size: .66rem; color: rgba(255, 255, 255, 0.55); text-transform: uppercase; letter-spacing: .06em; }
.mcard-foot strong { font-size: .98rem; }
/* App */
.app-inner { display: grid; grid-template-columns: 1fr 1fr; gap: 2.4rem; align-items: center; }
.app-points { list-style: none; padding: 0; margin: 1.2rem 0 1.4rem; display: grid; gap: .55rem; }
.app-points li { position: relative; padding-left: 1.7rem; color: var(--ink-2); font-weight: 500; }
.app-points li::before {
content: "✓"; position: absolute; left: 0; top: 0; width: 22px; height: 22px; display: grid; place-items: center;
background: var(--sky-50); color: var(--sky-d); border-radius: 50%; font-size: .72rem; font-weight: 800;
}
.store-btns { display: flex; gap: .7rem; flex-wrap: wrap; }
.store {
font-family: inherit; font-weight: 700; font-size: .92rem; color: #fff; background: var(--ink);
border: none; border-radius: var(--r-sm); padding: .7rem 1.2rem; cursor: pointer; transition: background .15s, transform .12s;
}
.store:hover { background: #0a1626; }
.store:active { transform: translateY(1px); }
.app-mock { display: grid; place-items: center; }
.phone {
width: 100%; max-width: 320px; background: #fff; border: 1px solid var(--line); border-radius: var(--r-lg);
box-shadow: var(--sh-lg); padding: 1.3rem;
}
.phone-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.1rem; }
.flightno { font-weight: 800; font-size: 1.1rem; letter-spacing: .04em; }
.pill {
font-size: .72rem; font-weight: 800; letter-spacing: .04em; padding: .3rem .7rem; border-radius: 999px;
text-transform: uppercase; color: #fff;
}
.pill.boarding { background: var(--boarding); }
.phone-route {
display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .6rem; margin-bottom: 1.1rem;
padding-bottom: 1.1rem; border-bottom: 1px dashed var(--line-2);
}
.phone-route > div { text-align: center; }
.phone-route strong { display: block; font-size: 1.9rem; font-weight: 800; letter-spacing: -.02em; }
.phone-route small { color: var(--muted); font-weight: 600; font-variant-numeric: tabular-nums; }
.plane-line { position: relative; color: var(--sky); font-size: 1.3rem; }
.plane-line::before, .plane-line::after {
content: ""; position: absolute; top: 50%; width: 32px; height: 2px; background: var(--line-2);
}
.plane-line::before { right: 100%; margin-right: 4px; }
.plane-line::after { left: 100%; margin-left: 4px; }
.phone-meta { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem; text-align: center; }
.phone-meta small { display: block; font-size: .68rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.phone-meta strong { font-size: 1.1rem; }
/* Footer */
.site-foot { background: var(--ink); color: rgba(255, 255, 255, 0.74); margin-top: 1rem; }
.foot-inner { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 1.8rem; padding: 3rem 0 2rem; }
.site-foot .brand { color: #fff; }
.site-foot .brand-mark { background: linear-gradient(135deg, var(--sunrise), #ff9a5e); }
.foot-brand p { margin: .8rem 0 0; max-width: 24rem; font-size: .9rem; }
.foot-col h4 { color: #fff; font-size: .82rem; text-transform: uppercase; letter-spacing: .06em; margin: 0 0 .9rem; }
.foot-col a { display: block; padding: .25rem 0; font-size: .9rem; color: rgba(255, 255, 255, 0.7); }
.foot-col a:hover { color: #fff; }
.foot-bottom {
display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding: 1.2rem 0;
border-top: 1px solid rgba(255, 255, 255, 0.12); font-size: .82rem; color: rgba(255, 255, 255, 0.55);
}
.foot-links a:hover { color: #fff; }
/* Toast */
.toast {
position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 24px); opacity: 0; pointer-events: none;
background: var(--ink); color: #fff; padding: .8rem 1.2rem; border-radius: var(--r-md); box-shadow: var(--sh-lg);
font-size: .9rem; font-weight: 500; z-index: 90; transition: transform .25s, opacity .25s; max-width: 88vw;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* Reveal */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.reveal { opacity: 1; transform: none; transition: none; }
html { scroll-behavior: auto; }
}
/* Responsive */
@media (max-width: 900px) {
.hero-inner { grid-template-columns: 1fr; gap: 1.8rem; }
.dest-grid, .feat-grid { grid-template-columns: repeat(2, 1fr); }
.dest.big { grid-row: auto; }
.deal { flex-basis: calc((100% - 1rem) / 2); }
.loyalty, .app-inner { grid-template-columns: 1fr; }
.foot-inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 760px) {
.nav {
position: absolute; top: 66px; left: 0; right: 0; flex-direction: column; gap: 0;
background: #fff; border-bottom: 1px solid var(--line); padding: .5rem; box-shadow: var(--sh-md);
transform: translateY(-12px); opacity: 0; pointer-events: none; transition: transform .2s, opacity .2s;
}
.nav.open { transform: none; opacity: 1; pointer-events: auto; }
.nav a { padding: .8rem .7rem; }
.nav-toggle { display: flex; }
.head-actions .btn.ghost { display: none; }
}
@media (max-width: 520px) {
.wrap { width: 90vw; }
.deal { flex-basis: 100%; }
.dest-grid, .feat-grid, .foot-inner { grid-template-columns: 1fr; }
.hero-stats { gap: 1.2rem; }
.field-row { flex-wrap: wrap; }
.field-row .pax-field { flex-basis: 100%; }
.swap { align-self: center; margin: 0; }
.sec-head { flex-direction: column; align-items: flex-start; }
.foot-bottom { flex-direction: column; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
document.querySelectorAll("[data-toast]").forEach(function (el) {
el.addEventListener("click", function () {
toast(el.getAttribute("data-toast"));
});
});
/* ---------- Mobile nav ---------- */
var navToggle = document.getElementById("navToggle");
var nav = document.getElementById("nav");
if (navToggle && nav) {
navToggle.addEventListener("click", function () {
var open = nav.classList.toggle("open");
navToggle.setAttribute("aria-expanded", open ? "true" : "false");
});
nav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
nav.classList.remove("open");
navToggle.setAttribute("aria-expanded", "false");
});
});
}
/* ---------- Search widget ---------- */
var searchCard = document.querySelector(".search-card");
document.querySelectorAll(".trip-opt").forEach(function (opt) {
opt.addEventListener("click", function () {
document.querySelectorAll(".trip-opt").forEach(function (o) {
o.classList.remove("active");
o.setAttribute("aria-selected", "false");
});
opt.classList.add("active");
opt.setAttribute("aria-selected", "true");
searchCard.classList.toggle("oneway", opt.getAttribute("data-trip") === "oneway");
});
});
// Default dates: depart +14d, return +21d
function iso(d) { return d.toISOString().slice(0, 10); }
var dep = document.getElementById("depart");
var ret = document.getElementById("return");
var now = new Date();
if (dep) dep.value = iso(new Date(now.getTime() + 14 * 864e5));
if (ret) ret.value = iso(new Date(now.getTime() + 21 * 864e5));
var swap = document.getElementById("swap");
var fromI = document.getElementById("from");
var toI = document.getElementById("to");
if (swap && fromI && toI) {
swap.addEventListener("click", function () {
var t = fromI.value; fromI.value = toI.value; toI.value = t;
});
}
var form = document.getElementById("searchForm");
var note = document.getElementById("searchNote");
if (form) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var from = (fromI.value || "").trim();
var to = (toI.value || "").trim();
if (!from || !to) {
if (note) note.textContent = "Please enter both an origin and a destination.";
return;
}
var fromCode = from.split(" ")[0];
var toCode = to.split(" ")[0];
if (note) note.textContent = "Searching " + fromCode + " → " + toCode + " · 312 flights found (demo).";
toast("Found 312 flights " + fromCode + " → " + toCode + " — booking is illustrative only.");
});
}
/* ---------- Deals carousel ---------- */
var deals = [
{ tag: "Save 30%", from: "JFK", to: "CDG", city: "Paris", price: 389, hue: 18 },
{ tag: "Limited", from: "LAX", to: "NRT", city: "Tokyo", price: 642, hue: 205 },
{ tag: "Flash sale", from: "ORD", to: "BCN", city: "Barcelona", price: 415, hue: 34 },
{ tag: "Save 25%", from: "MIA", to: "GRU", city: "São Paulo", price: 498, hue: 145 },
{ tag: "New route", from: "SFO", to: "DXB", city: "Dubai", price: 711, hue: 42 },
{ tag: "Save 40%", from: "BOS", to: "KEF", city: "Reykjavík", price: 269, hue: 190 },
{ tag: "Weekend", from: "SEA", to: "YVR", city: "Vancouver", price: 158, hue: 160 },
{ tag: "Last seats", from: "ATL", to: "FCO", city: "Rome", price: 452, hue: 28 }
];
function gradient(hue) {
return "linear-gradient(135deg, hsl(" + hue + ",62%,52%), hsl(" + ((hue + 38) % 360) + ",58%,40%))";
}
var track = document.getElementById("dealTrack");
if (track) {
deals.forEach(function (d) {
var card = document.createElement("article");
card.className = "deal";
card.setAttribute("role", "listitem");
card.innerHTML =
'<div class="deal-img" style="background:' + gradient(d.hue) + '">' +
'<span class="deal-tag">' + d.tag + '</span>' +
'</div>' +
'<div class="deal-body">' +
'<div class="deal-route tnum"><span>' + d.from + '</span><span class="arr">✈</span><span>' + d.to + '</span></div>' +
'<div class="deal-city">' + d.city + '</div>' +
'<div class="deal-foot">' +
'<div class="deal-price"><small>round trip from</small><strong class="tnum">$' + d.price + '</strong></div>' +
'<button class="deal-btn" type="button">View</button>' +
'</div>' +
'</div>';
card.querySelector(".deal-btn").addEventListener("click", function () {
toast(d.from + " → " + d.to + " from $" + d.price + " — fictional fare.");
});
track.appendChild(card);
});
}
var dealIndex = 0;
var prevBtn = document.getElementById("dealPrev");
var nextBtn = document.getElementById("dealNext");
function perView() {
var w = window.innerWidth;
if (w <= 520) return 1;
if (w <= 900) return 2;
return 3;
}
function maxIndex() { return Math.max(0, deals.length - perView()); }
function updateCarousel() {
if (!track) return;
if (dealIndex > maxIndex()) dealIndex = maxIndex();
var first = track.querySelector(".deal");
var step = first ? first.getBoundingClientRect().width + 16 : 0;
track.style.transform = "translateX(" + (-dealIndex * step) + "px)";
if (prevBtn) prevBtn.disabled = dealIndex <= 0;
if (nextBtn) nextBtn.disabled = dealIndex >= maxIndex();
}
if (prevBtn) prevBtn.addEventListener("click", function () { dealIndex = Math.max(0, dealIndex - 1); updateCarousel(); });
if (nextBtn) nextBtn.addEventListener("click", function () { dealIndex = Math.min(maxIndex(), dealIndex + 1); updateCarousel(); });
var resizeT;
window.addEventListener("resize", function () {
clearTimeout(resizeT);
resizeT = setTimeout(updateCarousel, 120);
});
updateCarousel();
/* ---------- Destinations grid ---------- */
var destinations = [
{ code: "LIS", name: "Lisbon", from: 312, hue: 32, big: true },
{ code: "SIN", name: "Singapore", from: 689, hue: 200 },
{ code: "MEX", name: "Mexico City", from: 224, hue: 145 },
{ code: "AKL", name: "Auckland", from: 798, hue: 175 },
{ code: "IST", name: "Istanbul", from: 437, hue: 14 },
{ code: "CPT", name: "Cape Town", from: 612, hue: 38 },
{ code: "BKK", name: "Bangkok", from: 555, hue: 50 }
];
var destGrid = document.getElementById("destGrid");
if (destGrid) {
destinations.forEach(function (d) {
var el = document.createElement("button");
el.className = "dest" + (d.big ? " big" : "");
el.type = "button";
el.setAttribute("aria-label", "Explore flights to " + d.name + " from $" + d.from);
el.style.background = gradient(d.hue);
el.innerHTML =
'<div class="dest-info">' +
'<div class="code tnum">' + d.code + '</div>' +
'<h3>' + d.name + '</h3>' +
'<div class="from">from <b class="tnum">$' + d.from + '</b></div>' +
'</div>';
el.addEventListener("click", function () {
toast("Exploring " + d.name + " (" + d.code + ") — from $" + d.from + ", demo only.");
});
destGrid.appendChild(el);
});
}
/* ---------- Reveal on scroll ---------- */
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 });
reveals.forEach(function (r) { io.observe(r); });
} else {
reveals.forEach(function (r) { r.classList.add("in"); });
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Skyloom Airlines — Fly Beyond the Horizon</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=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip" href="#main">Skip to content</a>
<!-- Header -->
<header class="site-head" id="top">
<div class="wrap head-inner">
<a class="brand" href="#top" aria-label="Skyloom Airlines home">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none"><path d="M21 16.5 13 12V4.5a1.5 1.5 0 0 0-3 0V12l-8 4.5V18l8-2.5V20l-2 1.5V23l3.5-1L15 23v-1.5L13 20v-4.5l8 2.5v-1.5Z" fill="currentColor"/></svg>
</span>
Skyloom
</a>
<nav class="nav" id="nav" aria-label="Primary">
<a href="#deals">Deals</a>
<a href="#destinations">Destinations</a>
<a href="#why">Why fly us</a>
<a href="#loyalty">SkyMiles</a>
<a href="#app">App</a>
</nav>
<div class="head-actions">
<button class="btn ghost" type="button" data-toast="Opening sign in…">Sign in</button>
<button class="btn primary" type="button" data-toast="Booking flow is illustrative only.">Book now</button>
<button class="nav-toggle" id="navToggle" aria-expanded="false" aria-controls="nav" aria-label="Toggle navigation">
<span></span><span></span><span></span>
</button>
</div>
</div>
</header>
<main id="main">
<!-- Hero -->
<section class="hero">
<div class="wrap hero-inner">
<div class="hero-copy reveal">
<span class="eyebrow">★ Voted #2 for on-time arrivals, 2026</span>
<h1>Fly beyond the<br><span class="hl">horizon.</span></h1>
<p class="lede">Smooth booking, generous legroom, and 140+ destinations across five continents. Find your next escape in seconds.</p>
<div class="hero-stats" role="list">
<div role="listitem"><strong>140+</strong><span>Destinations</span></div>
<div role="listitem"><strong>92%</strong><span>On-time rate</span></div>
<div role="listitem"><strong>4.7★</strong><span>Passenger rating</span></div>
</div>
</div>
<!-- Search widget -->
<div class="search-card reveal" aria-label="Flight search">
<div class="trip-toggle" role="tablist" aria-label="Trip type">
<button role="tab" aria-selected="true" class="trip-opt active" data-trip="round">Round trip</button>
<button role="tab" aria-selected="false" class="trip-opt" data-trip="oneway">One way</button>
</div>
<form id="searchForm" novalidate>
<div class="field-row">
<label class="field">
<span>From</span>
<input type="text" id="from" value="JFK · New York" autocomplete="off" />
</label>
<button class="swap" type="button" id="swap" aria-label="Swap origin and destination">⇄</button>
<label class="field">
<span>To</span>
<input type="text" id="to" value="LHR · London" autocomplete="off" />
</label>
</div>
<div class="field-row">
<label class="field">
<span>Depart</span>
<input type="date" id="depart" />
</label>
<label class="field return-field">
<span>Return</span>
<input type="date" id="return" />
</label>
<label class="field pax-field">
<span>Passengers</span>
<select id="pax">
<option>1 adult</option>
<option selected>2 adults</option>
<option>2 adults · 1 child</option>
<option>4 adults</option>
</select>
</label>
</div>
<button class="btn primary block" type="submit">Search flights</button>
<p class="search-note" id="searchNote" aria-live="polite">Lowest fares are typically found 6–8 weeks out.</p>
</form>
</div>
</div>
</section>
<!-- Deals carousel -->
<section class="section" id="deals">
<div class="wrap">
<div class="sec-head">
<div>
<h2>This week's fare deals</h2>
<p class="sub">Round-trip economy, taxes included. Fictional fares.</p>
</div>
<div class="carousel-ctrls">
<button class="ctrl" id="dealPrev" aria-label="Previous deals">‹</button>
<button class="ctrl" id="dealNext" aria-label="Next deals">›</button>
</div>
</div>
<div class="carousel" id="dealCarousel">
<div class="track" id="dealTrack" role="list"></div>
</div>
</div>
</section>
<!-- Destinations grid -->
<section class="section alt" id="destinations">
<div class="wrap">
<div class="sec-head">
<div>
<h2>Trending destinations</h2>
<p class="sub">Where Skyloom travelers are heading this season.</p>
</div>
</div>
<div class="dest-grid" id="destGrid"></div>
</div>
</section>
<!-- Why fly us -->
<section class="section" id="why">
<div class="wrap">
<div class="sec-head center">
<div>
<h2>Why fly with Skyloom</h2>
<p class="sub">Little things that make a long flight feel short.</p>
</div>
</div>
<div class="feat-grid">
<article class="feat reveal">
<span class="feat-ic" aria-hidden="true">🛋️</span>
<h3>32-inch legroom</h3>
<p>The most generous economy pitch in our class — stretch out on every route.</p>
</article>
<article class="feat reveal">
<span class="feat-ic" aria-hidden="true">🧳</span>
<h3>First bag flies free</h3>
<p>Check your first 23kg bag at no extra charge on all international fares.</p>
</article>
<article class="feat reveal">
<span class="feat-ic" aria-hidden="true">📶</span>
<h3>Wi-Fi in the sky</h3>
<p>Stream, message, and work with complimentary high-speed connectivity.</p>
</article>
<article class="feat reveal">
<span class="feat-ic" aria-hidden="true">🌱</span>
<h3>Cleaner skies</h3>
<p>Offset every ticket and fly on one of the youngest fleets in the air.</p>
</article>
</div>
</div>
</section>
<!-- Loyalty teaser -->
<section class="section" id="loyalty">
<div class="wrap">
<div class="loyalty reveal">
<div class="loyalty-copy">
<span class="eyebrow light">SkyMiles rewards</span>
<h2>Earn miles. Unlock the lounge.</h2>
<p>Join SkyMiles free and start earning from your first flight. Reach Silver in 25,000 miles for priority boarding, free seat selection, and lounge access at 60+ airports.</p>
<div class="tier-bar" aria-label="Tier progress example">
<div class="tier-fill" style="width:62%"></div>
<span class="tier-label">15,500 / 25,000 miles to Silver</span>
</div>
<button class="btn light" type="button" data-toast="Welcome to SkyMiles! (demo)">Join free</button>
</div>
<div class="loyalty-card" aria-hidden="true">
<div class="mcard">
<div class="mcard-top">
<span>SkyMiles</span><span class="chip">SILVER</span>
</div>
<div class="mcard-num">5821 0049 7732</div>
<div class="mcard-foot">
<div><small>Member</small><strong>A. RIVERA</strong></div>
<div><small>Miles</small><strong class="tnum">15,500</strong></div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- App download -->
<section class="section alt" id="app">
<div class="wrap app-inner">
<div class="app-copy reveal">
<h2>Your boarding pass, in your pocket</h2>
<p class="sub">Check in, get live gate alerts, and store your boarding pass offline. Manage your whole trip from the Skyloom app.</p>
<ul class="app-points">
<li>Live departure & gate notifications</li>
<li>Mobile boarding passes & bag tracking</li>
<li>Change seats and meals on the go</li>
</ul>
<div class="store-btns">
<button class="store" type="button" data-toast="App Store link is illustrative.">App Store</button>
<button class="store" type="button" data-toast="Google Play link is illustrative.">Google Play</button>
</div>
</div>
<div class="app-mock reveal" aria-hidden="true">
<div class="phone">
<div class="phone-head">
<span class="flightno tnum">SL 482</span>
<span class="pill boarding">Boarding</span>
</div>
<div class="phone-route">
<div><strong class="tnum">JFK</strong><small>10:45</small></div>
<div class="plane-line"><span>✈</span></div>
<div><strong class="tnum">LHR</strong><small>22:30</small></div>
</div>
<div class="phone-meta">
<div><small>Gate</small><strong>B12</strong></div>
<div><small>Seat</small><strong>14C</strong></div>
<div><small>Group</small><strong>2</strong></div>
</div>
</div>
</div>
</div>
</section>
</main>
<!-- Footer -->
<footer class="site-foot">
<div class="wrap foot-inner">
<div class="foot-brand">
<a class="brand" href="#top">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none"><path d="M21 16.5 13 12V4.5a1.5 1.5 0 0 0-3 0V12l-8 4.5V18l8-2.5V20l-2 1.5V23l3.5-1L15 23v-1.5L13 20v-4.5l8 2.5v-1.5Z" fill="currentColor"/></svg>
</span>
Skyloom
</a>
<p>Fly beyond the horizon. A fictional airline for demonstration.</p>
</div>
<nav class="foot-col" aria-label="Book">
<h4>Book</h4>
<a href="#deals">Flights</a><a href="#deals">Deals</a><a href="#destinations">Destinations</a><a href="#loyalty">SkyMiles</a>
</nav>
<nav class="foot-col" aria-label="Help">
<h4>Help</h4>
<a href="#">Manage booking</a><a href="#">Check-in</a><a href="#">Baggage</a><a href="#">Contact</a>
</nav>
<nav class="foot-col" aria-label="Company">
<h4>Company</h4>
<a href="#">About</a><a href="#">Careers</a><a href="#">Sustainability</a><a href="#">Press</a>
</nav>
</div>
<div class="wrap foot-bottom">
<span>© 2026 Skyloom Airlines (fictional). All rights reserved.</span>
<span class="foot-links"><a href="#">Privacy</a> · <a href="#">Terms</a> · <a href="#">Cookies</a></span>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Airline Landing
A complete marketing landing page for Skyloom, a fictional airline. The hero leads with a horizon headline and a sticky, glassy header, then drops a fully interactive flight-search widget right into the fold — toggle between round-trip and one-way, swap origin and destination, and submit to see a simulated results count. Departure and return dates are pre-filled to sensible defaults, and times, flight numbers, and prices use tabular figures so columns line up the way they would on a real departures board.
Below the fold, a fare-deals carousel scrolls through eight round-trip offers with prev/next controls that disable at the ends and adapt to one, two, or three cards per view. A trending-destinations grid renders airport codes, city names, and from-prices over generated gradient tiles, and a why-fly-us row highlights legroom, free bags, in-flight Wi-Fi, and sustainability. The SkyMiles section shows a tier-progress bar and a membership card, while the app block features a boarding-pass mockup complete with a Boarding status pill, gate, seat, and group.
Everything is self-contained vanilla JS — a small toast() helper surfaces feedback, an IntersectionObserver drives scroll reveals, and the layout collapses to a mobile nav and single-column stacks down to 360px.
Illustrative UI only — fictional airline, not a real booking or flight system.