Travel — National-Geographic-style Landing
A documentary travel landing styled after a National-Geographic cover: black, signature yellow and white, bold Playfair serif headlines, and the iconic yellow-border framing motif. A full-bleed CSS-and-SVG horizon hero opens onto feature dispatches with strong captions and save-to-reading-list hearts, an interactive expedition map with keyboard-reachable waypoint pins, a count-up stat band, and an austere bordered call-to-action. High contrast, restrained, epic in mood and fully self-contained.
MCP
Code
/* ===================================================================
Terra Expedition — National-Geographic-style documentary landing
Black + signature yellow + white. Serif display, restrained, epic.
=================================================================== */
:root {
--black: #0c0c0c;
--ink: #141414;
--paper: #ffffff;
--bone: #f4f1ea;
--muted: #6f6a62;
--muted-light: #b8b2a6;
--yellow: #ffd200; /* signature yellow */
--yellow-deep: #e6bd00;
--line: rgba(255, 255, 255, 0.16);
--line-dark: rgba(12, 12, 12, 0.14);
--shadow: 0 24px 60px -28px rgba(0, 0, 0, 0.55);
--serif: "Playfair Display", Georgia, "Times New Roman", serif;
--cond: "Oswald", "Arial Narrow", system-ui, sans-serif;
--sans: "Work Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--maxw: 1200px;
--pad: clamp(1.1rem, 4vw, 3rem);
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--black);
color: var(--paper);
font-family: var(--sans);
font-size: clamp(15px, 1.05vw, 17px);
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}
img, svg { display: block; max-width: 100%; }
.sr-only {
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.skip-link {
position: absolute; left: 50%; top: -60px; transform: translateX(-50%);
background: var(--yellow); color: var(--black); padding: 0.6rem 1.2rem;
font: 700 0.85rem/1 var(--cond); letter-spacing: 0.08em; text-transform: uppercase;
z-index: 200; border-radius: 0 0 4px 4px; transition: top 0.2s ease; text-decoration: none;
}
.skip-link:focus { top: 0; }
:focus-visible {
outline: 3px solid var(--yellow);
outline-offset: 2px;
}
/* ===================== BUTTONS ===================== */
.btn {
font: 600 0.82rem/1 var(--cond);
letter-spacing: 0.12em;
text-transform: uppercase;
border: 0;
border-radius: 2px;
padding: 0.85rem 1.5rem;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 0.5rem;
transition: transform 0.15s ease, background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}
.btn--lg { padding: 1.05rem 1.9rem; font-size: 0.9rem; }
.btn--yellow { background: var(--yellow); color: var(--black); }
.btn--yellow:hover { background: var(--paper); transform: translateY(-2px); }
.btn--yellow:active { transform: translateY(0); }
.btn--ghost {
background: transparent; color: var(--paper);
border: 2px solid rgba(255,255,255,0.45);
}
.btn--ghost:hover { border-color: var(--yellow); color: var(--yellow); transform: translateY(-2px); }
.btn .play { font-size: 0.7em; }
.icon-btn {
background: transparent; border: 0; color: inherit; cursor: pointer;
width: 42px; height: 42px; display: grid; place-items: center;
border-radius: 4px; transition: background 0.15s ease, color 0.15s ease;
}
.icon-btn:hover { background: rgba(255,255,255,0.08); color: var(--yellow); }
/* ===================== BRAND ===================== */
.brand {
display: inline-flex; align-items: center; gap: 0.7rem;
text-decoration: none; color: inherit;
}
.brand__mark {
width: 30px; height: 30px; flex: none;
border: 3px solid var(--yellow);
border-radius: 2px;
position: relative;
}
.brand__mark::after {
content: ""; position: absolute; inset: 5px;
background: var(--yellow); border-radius: 1px;
clip-path: polygon(0 100%, 35% 35%, 55% 60%, 80% 15%, 100% 100%);
}
.brand__name {
font: 700 1.05rem/0.95 var(--cond);
letter-spacing: 0.22em;
display: inline-flex; flex-direction: column;
}
.brand__sub {
font-size: 0.5rem; letter-spacing: 0.42em; color: var(--yellow);
font-weight: 600; margin-top: 2px;
}
/* ===================== MASTHEAD ===================== */
.masthead {
position: sticky; top: 0; z-index: 100;
background: rgba(8,8,8,0.86);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--line);
}
.masthead__inner {
max-width: var(--maxw); margin: 0 auto;
padding: 0.85rem var(--pad);
display: flex; align-items: center; gap: 1.5rem;
}
.nav {
display: flex; gap: 1.6rem; margin-left: auto;
}
.nav a {
color: var(--bone); text-decoration: none;
font: 600 0.78rem/1 var(--cond); letter-spacing: 0.12em; text-transform: uppercase;
padding: 0.4rem 0; position: relative;
}
.nav a::after {
content: ""; position: absolute; left: 0; bottom: -2px;
width: 0; height: 2px; background: var(--yellow); transition: width 0.2s ease;
}
.nav a:hover::after, .nav a:focus-visible::after { width: 100%; }
.nav a.is-current { color: var(--yellow); }
.nav a.is-current::after { width: 100%; }
.masthead__actions { display: flex; align-items: center; gap: 0.4rem; }
.masthead__actions .nav { display: none; }
.menu-btn { display: none; }
/* search panel */
.search-panel {
border-top: 1px solid var(--line);
background: rgba(10,10,10,0.96);
padding: 1.1rem var(--pad);
animation: dropIn 0.2s ease;
}
@keyframes dropIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
.search-panel form {
max-width: var(--maxw); margin: 0 auto;
display: flex; align-items: center; gap: 0.6rem;
border-bottom: 2px solid var(--yellow); padding-bottom: 0.5rem;
}
.search-panel__icon { color: var(--yellow); display: grid; place-items: center; }
.search-panel input {
flex: 1; background: transparent; border: 0; color: var(--paper);
font: 500 1.05rem/1.4 var(--serif); padding: 0.4rem 0;
}
.search-panel input::placeholder { color: var(--muted-light); }
.search-panel input:focus { outline: none; }
.search-panel__hint {
max-width: var(--maxw); margin: 0.6rem auto 0; color: var(--muted-light);
font-size: 0.8rem;
}
.mobile-nav { display: none; }
/* ===================== HERO ===================== */
.hero {
position: relative; isolation: isolate;
min-height: min(88vh, 760px);
display: flex; align-items: flex-end;
overflow: hidden;
}
.hero__scene { position: absolute; inset: 0; z-index: -2; }
.hero__svg { width: 100%; height: 100%; object-fit: cover; }
.hero::after {
/* darkening + vignette so text reads */
content: ""; position: absolute; inset: 0; z-index: -1;
background:
linear-gradient(180deg, rgba(8,8,8,0.55) 0%, rgba(8,8,8,0.05) 35%, rgba(8,8,8,0.78) 100%),
radial-gradient(120% 80% at 20% 90%, rgba(8,8,8,0.7), transparent 60%);
}
.hero__frame {
max-width: var(--maxw); margin: 0 auto; width: 100%;
padding: 2.5rem var(--pad) 3.5rem;
position: relative;
}
/* iconic yellow border framing motif */
.hero__frame::before {
content: ""; position: absolute;
left: var(--pad); right: var(--pad); top: 0; bottom: 1.8rem;
border: 0 solid var(--yellow);
border-left-width: 8px;
pointer-events: none;
}
.hero__content { max-width: 760px; padding-left: clamp(1rem, 3vw, 2rem); }
.kicker {
display: inline-flex; align-items: center; gap: 0.55rem;
font: 600 0.78rem/1 var(--cond); letter-spacing: 0.2em; text-transform: uppercase;
color: var(--yellow); margin: 0 0 1rem;
}
.kicker--dark { color: var(--yellow-deep); }
.kicker__dot { width: 9px; height: 9px; background: var(--yellow); border-radius: 1px; }
.kicker--dark .kicker__dot { background: var(--ink); }
#hero-title, .hero h1 {
font-family: var(--serif);
font-weight: 800;
font-size: clamp(2.7rem, 8.5vw, 6.3rem);
line-height: 0.96;
letter-spacing: -0.01em;
margin: 0 0 1.1rem;
text-shadow: 0 4px 30px rgba(0,0,0,0.5);
}
.hero__lead {
max-width: 50ch; color: #efeae0; font-size: clamp(1rem, 1.6vw, 1.18rem);
margin: 0 0 1.8rem; text-shadow: 0 2px 14px rgba(0,0,0,0.5);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-bottom: 2.2rem; }
.hero__meta {
display: flex; flex-wrap: wrap; gap: 2.2rem;
margin: 0; padding-top: 1.4rem;
border-top: 1px solid rgba(255,255,255,0.2);
max-width: 640px;
}
.hero__meta div { margin: 0; }
.hero__meta dt {
font: 600 0.66rem/1 var(--cond); letter-spacing: 0.18em; text-transform: uppercase;
color: var(--yellow); margin-bottom: 0.35rem;
}
.hero__meta dd { margin: 0; font-family: var(--serif); font-size: 1.05rem; }
.hero__scroll {
position: absolute; right: var(--pad); bottom: 1.6rem; z-index: 2;
font: 600 0.66rem/1 var(--cond); letter-spacing: 0.28em; color: var(--bone);
display: flex; align-items: center; gap: 0.5rem; writing-mode: vertical-rl;
}
.hero__scroll span { animation: bob 1.8s ease-in-out infinite; }
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(6px); } }
/* ===================== SECTION SHELLS ===================== */
.section-head { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad); }
.section-title {
font-family: var(--serif); font-weight: 800;
font-size: clamp(1.9rem, 4.5vw, 3.1rem); line-height: 1.02;
margin: 0 0 0.5rem; letter-spacing: -0.01em;
}
.section-sub { color: var(--muted-light); max-width: 52ch; margin: 0; }
/* ===================== STORIES ===================== */
.stories { padding: clamp(3rem, 8vw, 6rem) 0; }
.story-grid {
max-width: var(--maxw); margin: 2.6rem auto 0; padding: 0 var(--pad);
display: grid; gap: 1.4rem;
grid-template-columns: repeat(3, 1fr);
}
.story {
position: relative; display: flex; flex-direction: column;
background: #111; border: 1px solid var(--line);
border-radius: 4px; overflow: hidden;
transition: transform 0.25s ease, border-color 0.25s ease;
}
.story:hover { transform: translateY(-5px); border-color: rgba(255,210,0,0.45); }
.story--lead { grid-column: span 2; grid-row: span 2; }
.story__media {
position: relative; flex: 1; min-height: 190px;
background:
radial-gradient(120% 90% at 70% 20%, var(--g3, #ccc) 0%, transparent 55%),
linear-gradient(150deg, var(--g1, #222) 0%, var(--g2, #444) 100%);
}
.story--lead .story__media { min-height: 320px; }
.story__media::after {
/* subtle topo-line texture */
content: ""; position: absolute; inset: 0; opacity: 0.18;
background-image:
repeating-linear-gradient(135deg, rgba(255,255,255,0.25) 0 1px, transparent 1px 14px);
mix-blend-mode: overlay;
}
.story__cat {
position: absolute; top: 0; left: 0; z-index: 2;
background: var(--yellow); color: var(--black);
font: 700 0.66rem/1 var(--cond); letter-spacing: 0.16em; text-transform: uppercase;
padding: 0.45rem 0.8rem;
}
.story__body { padding: 1.3rem 1.4rem 1.5rem; }
.story--lead .story__body { padding: 1.8rem 2rem 2rem; }
.story__eyebrow {
font: 600 0.7rem/1 var(--cond); letter-spacing: 0.16em; text-transform: uppercase;
color: var(--yellow); margin: 0 0 0.6rem;
}
.story__title {
font-family: var(--serif); font-weight: 700;
font-size: 1.35rem; line-height: 1.1; margin: 0 0 0.6rem;
}
.story--lead .story__title { font-size: clamp(1.7rem, 3.5vw, 2.5rem); }
.story__excerpt { color: var(--muted-light); font-size: 0.94rem; margin: 0 0 1.1rem; }
.story--lead .story__excerpt { font-size: 1.05rem; max-width: 46ch; }
.save-btn {
display: inline-flex; align-items: center; gap: 0.5rem;
background: transparent; border: 1px solid var(--line);
color: var(--bone); border-radius: 2px;
font: 600 0.72rem/1 var(--cond); letter-spacing: 0.1em; text-transform: uppercase;
padding: 0.55rem 0.9rem; cursor: pointer;
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.save-btn:hover { border-color: var(--yellow); color: var(--yellow); }
.save-btn__ico { font-size: 1rem; line-height: 1; transition: transform 0.2s ease; }
.save-btn[aria-pressed="true"] {
background: var(--yellow); color: var(--black); border-color: var(--yellow);
}
.save-btn[aria-pressed="true"] .save-btn__ico { transform: scale(1.15); }
/* ===================== EXPEDITION MAP ===================== */
.expedition {
background: var(--bone); color: var(--ink);
padding: clamp(3rem, 8vw, 6rem) var(--pad);
}
.expedition__intro, .map {
max-width: var(--maxw); margin: 0 auto;
}
.expedition .section-title { color: var(--ink); }
.expedition .section-sub { color: var(--muted); }
.expedition__legend {
list-style: none; display: flex; gap: 1.4rem; padding: 0; margin: 1.2rem 0 0;
font: 600 0.74rem/1 var(--cond); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
}
.expedition__legend li { display: inline-flex; align-items: center; gap: 0.5rem; }
.dot { width: 11px; height: 11px; border-radius: 50%; flex: none; }
.dot--leg { background: var(--ink); }
.dot--active { background: var(--yellow-deep); box-shadow: 0 0 0 4px rgba(230,189,0,0.25); }
.map {
position: relative; margin-top: 2rem;
border: 4px solid var(--yellow);
border-radius: 6px;
overflow: hidden;
box-shadow: var(--shadow);
}
.map__svg { width: 100%; height: auto; aspect-ratio: 600 / 420; }
.pin {
position: absolute; left: var(--x); top: var(--y);
transform: translate(-50%, -50%);
width: 28px; height: 28px; border-radius: 50%;
border: 0; padding: 0; cursor: pointer; background: transparent;
}
.pin span {
position: absolute; inset: 7px; border-radius: 50%;
background: var(--paper); border: 2px solid var(--ink);
transition: transform 0.18s ease, background 0.18s ease;
}
.pin::before {
content: ""; position: absolute; inset: 0; border-radius: 50%;
border: 2px solid rgba(255,210,0,0.7); opacity: 0;
}
.pin:hover span { transform: scale(1.25); background: var(--yellow); }
.pin--active span { background: var(--yellow); border-color: var(--ink); }
.pin--active::before { opacity: 1; animation: ping 1.8s ease-out infinite; }
@keyframes ping { 0% { transform: scale(0.6); opacity: 0.8; } 100% { transform: scale(2.2); opacity: 0; } }
.pin[aria-current="true"] span { background: var(--yellow); transform: scale(1.3); }
.map__card {
position: absolute; left: 1rem; bottom: 1rem; right: auto;
width: min(290px, calc(100% - 2rem));
background: rgba(12,12,12,0.92); color: var(--paper);
border-left: 5px solid var(--yellow);
padding: 1.1rem 1.2rem; border-radius: 3px;
backdrop-filter: blur(4px);
}
.map__card-region { font-family: var(--serif); font-weight: 700; font-size: 1.4rem; margin: 0; }
.map__card-meta {
font: 600 0.72rem/1.3 var(--cond); letter-spacing: 0.1em; text-transform: uppercase;
color: var(--yellow); margin: 0.3rem 0 0.9rem;
}
.map__stats { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem 1rem; margin: 0; }
.map__stats div:first-child { grid-column: 1 / -1; }
.map__stats dt {
font: 600 0.62rem/1 var(--cond); letter-spacing: 0.14em; text-transform: uppercase;
color: var(--muted-light); margin-bottom: 0.25rem;
}
.map__stats dd { margin: 0; font-size: 0.95rem; font-weight: 500; }
/* ===================== STAT BAND ===================== */
.band {
background: var(--yellow); color: var(--black);
padding: clamp(2.6rem, 6vw, 4.2rem) var(--pad);
}
.band__inner { max-width: var(--maxw); margin: 0 auto; }
.band__title {
font-family: var(--serif); font-weight: 800;
font-size: clamp(1.6rem, 3.5vw, 2.4rem); margin: 0 0 1.8rem; text-align: center;
}
.band__stats {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem;
}
.stat { text-align: center; border-top: 3px solid var(--black); padding-top: 1rem; }
.stat__num {
display: block; font-family: var(--serif); font-weight: 900;
font-size: clamp(2rem, 5vw, 3.4rem); line-height: 1; font-variant-numeric: tabular-nums;
}
.stat__label {
display: block; margin-top: 0.5rem;
font: 600 0.72rem/1.3 var(--cond); letter-spacing: 0.12em; text-transform: uppercase;
}
/* ===================== CTA ===================== */
.cta {
background:
radial-gradient(80% 120% at 80% 0%, rgba(255,210,0,0.12), transparent 55%),
var(--black);
padding: clamp(3.5rem, 9vw, 7rem) var(--pad);
}
.cta__frame {
max-width: 760px; margin: 0 auto; text-align: center;
padding: clamp(2rem, 5vw, 3.5rem) clamp(1.2rem, 5vw, 3rem);
border: 3px solid var(--yellow); border-radius: 6px;
position: relative;
}
.cta__frame .kicker { justify-content: center; }
#cta-title {
font-family: var(--serif); font-weight: 800;
font-size: clamp(2rem, 5.5vw, 3.6rem); line-height: 1.02; margin: 0 0 1rem;
}
.cta__lead { color: var(--muted-light); max-width: 50ch; margin: 0 auto 2rem; }
.cta__form {
display: flex; flex-wrap: wrap; gap: 0.7rem; justify-content: center;
max-width: 520px; margin: 0 auto;
}
.cta__form input {
flex: 1 1 240px; min-width: 0;
background: rgba(255,255,255,0.06); border: 2px solid rgba(255,255,255,0.25);
color: var(--paper); border-radius: 2px; padding: 1rem 1.1rem;
font: 500 1rem/1 var(--sans);
}
.cta__form input::placeholder { color: var(--muted-light); }
.cta__form input:focus { outline: none; border-color: var(--yellow); }
.cta__form input.is-invalid { border-color: var(--yellow); background: rgba(255,210,0,0.08); }
.cta__error { color: var(--yellow); margin: 0.9rem 0 0; font-size: 0.88rem; font-weight: 600; }
.cta__fine { color: var(--muted); font-size: 0.78rem; margin: 1.4rem 0 0; }
/* ===================== FOOTER ===================== */
.footer { border-top: 1px solid var(--line); padding: 2.5rem var(--pad); }
.footer__inner {
max-width: var(--maxw); margin: 0 auto;
display: flex; flex-wrap: wrap; align-items: center; gap: 1.4rem;
}
.brand--footer { margin-right: auto; }
.footer__note { color: var(--muted); font-size: 0.82rem; max-width: 42ch; margin: 0; flex: 1 1 280px; }
.footer__links { display: flex; gap: 1.3rem; }
.footer__links a {
color: var(--bone); text-decoration: none;
font: 600 0.74rem/1 var(--cond); letter-spacing: 0.1em; text-transform: uppercase;
}
.footer__links a:hover { color: var(--yellow); }
/* ===================== TOAST ===================== */
.toast {
position: fixed; left: 50%; bottom: 1.6rem; transform: translate(-50%, 140%);
background: var(--paper); color: var(--black);
border-left: 5px solid var(--yellow);
padding: 0.85rem 1.3rem; border-radius: 3px;
font: 600 0.85rem/1.3 var(--sans); box-shadow: var(--shadow);
z-index: 300; max-width: min(90vw, 380px);
transition: transform 0.32s cubic-bezier(0.2,0.9,0.3,1.2);
}
.toast.is-visible { transform: translate(-50%, 0); }
/* ===================== RESPONSIVE ===================== */
@media (max-width: 900px) {
.nav { display: none; }
.menu-btn { display: grid; }
.story-grid { grid-template-columns: repeat(2, 1fr); }
.story--lead { grid-column: span 2; grid-row: auto; }
.story--lead .story__media { min-height: 220px; }
.band__stats { grid-template-columns: repeat(2, 1fr); }
.mobile-nav[hidden] { display: none; }
.mobile-nav {
display: flex; flex-direction: column;
border-top: 1px solid var(--line); background: rgba(10,10,10,0.98);
padding: 0.6rem var(--pad) 1rem;
}
.mobile-nav a {
color: var(--bone); text-decoration: none; padding: 0.85rem 0;
border-bottom: 1px solid var(--line);
font: 600 0.9rem/1 var(--cond); letter-spacing: 0.1em; text-transform: uppercase;
}
.mobile-nav a:last-child { border-bottom: 0; }
}
@media (max-width: 600px) {
.story-grid { grid-template-columns: 1fr; }
.story--lead { grid-column: auto; }
.hero__meta { gap: 1.4rem; }
.hero__scroll { display: none; }
.map__card { position: static; width: auto; margin: 0; border-radius: 0; }
.map { border-width: 3px; }
.footer__inner { flex-direction: column; align-items: flex-start; }
.brand--footer { margin-right: 0; }
}
@media (max-width: 380px) {
.hero__cta .btn { width: 100%; justify-content: center; }
.band__stats { grid-template-columns: 1fr 1fr; gap: 1rem; }
}/* ===================================================================
Terra Expedition — documentary travel landing
Vanilla JS only. Every interaction works.
=================================================================== */
(function () {
"use strict";
var doc = document;
var prefersReduced = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
/* ---------------- toast helper ---------------- */
var toastEl = doc.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-visible");
window.clearTimeout(toastTimer);
toastTimer = window.setTimeout(function () {
toastEl.classList.remove("is-visible");
}, 2600);
}
/* ---------------- search panel ---------------- */
var searchToggle = doc.getElementById("searchToggle");
var searchPanel = doc.getElementById("searchPanel");
var searchForm = doc.getElementById("searchForm");
var searchInput = doc.getElementById("searchInput");
function setSearch(open) {
if (!searchPanel || !searchToggle) return;
searchPanel.hidden = !open;
searchToggle.setAttribute("aria-expanded", String(open));
if (open && searchInput) {
window.setTimeout(function () {
searchInput.focus();
}, 30);
}
}
if (searchToggle) {
searchToggle.addEventListener("click", function () {
setSearch(searchPanel.hidden);
});
}
if (searchForm) {
searchForm.addEventListener("submit", function (e) {
e.preventDefault();
var q = (searchInput && searchInput.value.trim()) || "";
if (!q) {
toast("Type a region or expedition to search.");
if (searchInput) searchInput.focus();
return;
}
toast('No live results — "' + q + '" is a fictional search.');
setSearch(false);
});
}
/* ---------------- mobile nav ---------------- */
var menuToggle = doc.getElementById("menuToggle");
var mobileNav = doc.getElementById("mobileNav");
function setMenu(open) {
if (!mobileNav || !menuToggle) return;
mobileNav.hidden = !open;
menuToggle.setAttribute("aria-expanded", String(open));
}
if (menuToggle) {
menuToggle.addEventListener("click", function () {
setMenu(mobileNav.hidden);
});
}
if (mobileNav) {
Array.prototype.forEach.call(
mobileNav.querySelectorAll("a"),
function (a) {
a.addEventListener("click", function () {
setMenu(false);
});
}
);
}
// Close overlays on Escape
doc.addEventListener("keydown", function (e) {
if (e.key === "Escape") {
if (searchPanel && !searchPanel.hidden) {
setSearch(false);
if (searchToggle) searchToggle.focus();
}
if (mobileNav && !mobileNav.hidden) {
setMenu(false);
if (menuToggle) menuToggle.focus();
}
}
});
/* ---------------- hero / header buttons ---------------- */
function scrollToId(id) {
var el = doc.getElementById(id);
if (!el) return;
el.scrollIntoView({
behavior: prefersReduced ? "auto" : "smooth",
block: "start"
});
}
var joinBtn = doc.getElementById("joinBtn");
if (joinBtn) {
joinBtn.addEventListener("click", function () {
scrollToId("subscribe");
var email = doc.getElementById("email");
if (email)
window.setTimeout(
function () {
email.focus();
},
prefersReduced ? 0 : 500
);
});
}
var readStory = doc.getElementById("readStory");
if (readStory) {
readStory.addEventListener("click", function () {
scrollToId("stories");
});
}
var watchFilm = doc.getElementById("watchFilm");
if (watchFilm) {
watchFilm.addEventListener("click", function () {
toast("Field film reel is fictional — enjoy the still frames.");
});
}
/* ---------------- save / wishlist stories ---------------- */
var savedCount = 0;
Array.prototype.forEach.call(
doc.querySelectorAll(".save-btn"),
function (btn) {
btn.addEventListener("click", function () {
var pressed = btn.getAttribute("aria-pressed") === "true";
var next = !pressed;
btn.setAttribute("aria-pressed", String(next));
var ico = btn.querySelector(".save-btn__ico");
var label = btn.querySelector(".save-btn__label");
var title = btn.getAttribute("data-title") || "Story";
if (next) {
savedCount++;
if (ico) ico.textContent = "♥"; // filled heart
if (label) label.textContent = "Saved";
toast("Saved “" + title + "” to your reading list.");
} else {
savedCount = Math.max(0, savedCount - 1);
if (ico) ico.textContent = "♡"; // outline heart
if (label) label.textContent = "Save story";
toast("Removed “" + title + "” from your list.");
}
});
}
);
/* ---------------- expedition map waypoints ---------------- */
var WAYPOINTS = [
{
region: "Patagonia Coast",
meta: "Andes & Fjords, Chile · Leg 1 of 5",
terrain: "Wind-scoured fjordland",
dist: "0 km",
team: "6 in the field"
},
{
region: "Mid-Pacific",
meta: "Open ocean · Leg 2 of 5",
terrain: "Abyssal dive site",
dist: "9,820 km",
team: "4 aboard, 2 submersible"
},
{
region: "Upper Mustang",
meta: "Himalaya, Nepal · Leg 3 of 5",
terrain: "High alpine desert",
dist: "24,560 km",
team: "5 trekking"
},
{
region: "Erg Chebbi",
meta: "Sahara, Morocco · Leg 4 of 5",
terrain: "Active dune field",
dist: "38,140 km",
team: "6 in the field"
},
{
region: "Western Amazon",
meta: "Rainforest, Peru · Leg 5 of 5",
terrain: "Flooded canopy",
dist: "48,230 km",
team: "7 at canopy camp"
}
];
var pins = Array.prototype.slice.call(doc.querySelectorAll(".pin"));
var mapCard = doc.getElementById("mapCard");
var els = {
region: doc.getElementById("mapRegion"),
meta: doc.getElementById("mapMeta"),
terrain: doc.getElementById("mapTerrain"),
dist: doc.getElementById("mapDist"),
team: doc.getElementById("mapTeam")
};
var activeWp = 3; // Erg Chebbi starts active (matches markup)
function selectWaypoint(index, announce) {
var wp = WAYPOINTS[index];
if (!wp) return;
activeWp = index;
pins.forEach(function (pin) {
var i = parseInt(pin.getAttribute("data-wp"), 10);
var isActive = i === index;
pin.classList.toggle("pin--active", isActive);
if (isActive) {
pin.setAttribute("aria-current", "true");
} else {
pin.removeAttribute("aria-current");
}
});
if (els.region) els.region.textContent = wp.region;
if (els.meta) els.meta.textContent = wp.meta;
if (els.terrain) els.terrain.textContent = wp.terrain;
if (els.dist) els.dist.textContent = wp.dist;
if (els.team) els.team.textContent = wp.team;
// brief flash to draw the eye
if (mapCard && !prefersReduced) {
mapCard.style.transition = "none";
mapCard.style.opacity = "0.4";
window.requestAnimationFrame(function () {
mapCard.style.transition = "opacity 0.3s ease";
mapCard.style.opacity = "1";
});
}
if (announce) toast("Waypoint → " + wp.region);
}
pins.forEach(function (pin) {
pin.addEventListener("click", function () {
var i = parseInt(pin.getAttribute("data-wp"), 10);
selectWaypoint(i, true);
});
pin.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
var i = parseInt(pin.getAttribute("data-wp"), 10);
selectWaypoint(i, true);
} else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
e.preventDefault();
var next = pins[(parseInt(pin.getAttribute("data-wp"), 10) + 1) % pins.length];
if (next) next.focus();
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
e.preventDefault();
var cur = parseInt(pin.getAttribute("data-wp"), 10);
var prev = pins[(cur - 1 + pins.length) % pins.length];
if (prev) prev.focus();
}
});
});
// sync initial state without toast
selectWaypoint(activeWp, false);
/* ---------------- count-up stat band ---------------- */
function formatNum(n, suffix) {
var s = Math.round(n).toLocaleString("en-US");
return s + (suffix || "");
}
function runCount(el) {
var target = parseFloat(el.getAttribute("data-target")) || 0;
var suffix = el.getAttribute("data-suffix") || "";
if (prefersReduced) {
el.textContent = formatNum(target, suffix);
return;
}
var dur = 1400;
var start = null;
function step(ts) {
if (start === null) start = ts;
var p = Math.min(1, (ts - start) / dur);
var eased = 1 - Math.pow(1 - p, 3); // easeOutCubic
el.textContent = formatNum(target * eased, suffix);
if (p < 1) {
window.requestAnimationFrame(step);
} else {
el.textContent = formatNum(target, suffix);
}
}
window.requestAnimationFrame(step);
}
var statNums = Array.prototype.slice.call(
doc.querySelectorAll(".stat__num")
);
if ("IntersectionObserver" in window && statNums.length) {
var statObserver = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
runCount(entry.target);
statObserver.unobserve(entry.target);
}
});
},
{ threshold: 0.5 }
);
statNums.forEach(function (el) {
statObserver.observe(el);
});
} else {
statNums.forEach(runCount);
}
/* ---------------- reveal on scroll ---------------- */
var revealTargets = Array.prototype.slice.call(
doc.querySelectorAll(".story, .map__card, .section-head, .band__title")
);
if ("IntersectionObserver" in window && !prefersReduced) {
revealTargets.forEach(function (el) {
el.style.opacity = "0";
el.style.transform = "translateY(22px)";
el.style.transition =
"opacity 0.6s ease, transform 0.6s cubic-bezier(0.2,0.8,0.2,1)";
});
var revealObserver = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry, i) {
if (entry.isIntersecting) {
var el = entry.target;
window.setTimeout(function () {
el.style.opacity = "1";
el.style.transform = "none";
}, Math.min(i * 60, 240));
revealObserver.unobserve(el);
}
});
},
{ threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
);
revealTargets.forEach(function (el) {
revealObserver.observe(el);
});
}
/* ---------------- scroll-spy nav highlight ---------------- */
var navLinks = Array.prototype.slice.call(doc.querySelectorAll(".nav a"));
var sections = navLinks
.map(function (a) {
var id = a.getAttribute("href").replace("#", "");
return doc.getElementById(id);
})
.filter(Boolean);
if ("IntersectionObserver" in window && sections.length) {
var spyObserver = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
var id = entry.target.id;
navLinks.forEach(function (a) {
var match = a.getAttribute("href") === "#" + id;
a.classList.toggle("is-current", match);
if (match) {
a.setAttribute("aria-current", "true");
} else {
a.removeAttribute("aria-current");
}
});
}
});
},
{ rootMargin: "-45% 0px -50% 0px" }
);
sections.forEach(function (s) {
spyObserver.observe(s);
});
}
/* ---------------- subscribe form ---------------- */
var subForm = doc.getElementById("subForm");
var subError = doc.getElementById("subError");
var emailInput = doc.getElementById("email");
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
function showError(msg) {
if (!subError) return;
subError.textContent = msg;
subError.hidden = false;
if (emailInput) emailInput.classList.add("is-invalid");
}
function clearError() {
if (subError) subError.hidden = true;
if (emailInput) emailInput.classList.remove("is-invalid");
}
if (subForm) {
subForm.addEventListener("submit", function (e) {
e.preventDefault();
var val = (emailInput && emailInput.value.trim()) || "";
if (!val) {
showError("Please enter your email to join the Society.");
if (emailInput) emailInput.focus();
return;
}
if (!EMAIL_RE.test(val)) {
showError("That doesn’t look like a valid email address.");
if (emailInput) emailInput.focus();
return;
}
clearError();
subForm.reset();
toast("Welcome aboard — your first dispatch is on its way.");
});
}
if (emailInput) {
emailInput.addEventListener("input", clearError);
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Terra Expedition — Documentary Travel</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=Playfair+Display:ital,wght@0,500;0,700;0,800;0,900;1,600&family=Oswald:wght@500;600;700&family=Work+Sans:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<!-- ===================== HEADER ===================== -->
<header class="masthead" role="banner">
<div class="masthead__inner">
<a class="brand" href="#main" aria-label="Terra Expedition home">
<span class="brand__mark" aria-hidden="true"></span>
<span class="brand__name">TERRA<span class="brand__sub">EXPEDITION</span></span>
</a>
<nav class="nav" aria-label="Primary">
<a href="#stories">Stories</a>
<a href="#expedition">Expeditions</a>
<a href="#band">Field Notes</a>
<a href="#subscribe">Subscribe</a>
</nav>
<div class="masthead__actions">
<button class="icon-btn" id="searchToggle" aria-label="Search" aria-expanded="false" aria-controls="searchPanel">
<svg viewBox="0 0 24 24" aria-hidden="true" width="20" height="20"><path d="M21 21l-4.3-4.3M11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<button class="btn btn--yellow" id="joinBtn">Join</button>
<button class="icon-btn menu-btn" id="menuToggle" aria-label="Menu" aria-expanded="false" aria-controls="mobileNav">
<svg viewBox="0 0 24 24" aria-hidden="true" width="22" height="22"><path d="M3 6h18M3 12h18M3 18h18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</button>
</div>
</div>
<div class="search-panel" id="searchPanel" hidden>
<form id="searchForm" role="search">
<span class="search-panel__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18"><path d="M21 21l-4.3-4.3M11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
</span>
<input type="search" id="searchInput" placeholder="Search expeditions, regions, species…" aria-label="Search expeditions" autocomplete="off" />
<button class="btn btn--yellow" type="submit">Go</button>
</form>
<p class="search-panel__hint">Try “Patagonia”, “snow leopard”, or “deep ocean”.</p>
</div>
<nav class="mobile-nav" id="mobileNav" aria-label="Mobile" hidden>
<a href="#stories">Stories</a>
<a href="#expedition">Expeditions</a>
<a href="#band">Field Notes</a>
<a href="#subscribe">Subscribe</a>
</nav>
</header>
<main id="main">
<!-- ===================== HERO ===================== -->
<section class="hero" aria-labelledby="hero-title">
<div class="hero__scene" aria-hidden="true">
<svg class="hero__svg" viewBox="0 0 1440 900" preserveAspectRatio="xMidYMid slice" role="img">
<defs>
<linearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#0a1722"/>
<stop offset="0.45" stop-color="#163243"/>
<stop offset="0.75" stop-color="#3a5a4f"/>
<stop offset="1" stop-color="#caa24a"/>
</linearGradient>
<linearGradient id="ridge1" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#1c3b42"/>
<stop offset="1" stop-color="#0c2027"/>
</linearGradient>
<linearGradient id="ridge2" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#2d5650"/>
<stop offset="1" stop-color="#16302f"/>
</linearGradient>
<radialGradient id="sun" cx="0.74" cy="0.62" r="0.4">
<stop offset="0" stop-color="#ffd34d" stop-opacity="0.9"/>
<stop offset="1" stop-color="#ffd34d" stop-opacity="0"/>
</radialGradient>
</defs>
<rect width="1440" height="900" fill="url(#sky)"/>
<circle cx="1070" cy="560" r="380" fill="url(#sun)"/>
<circle cx="1070" cy="560" r="78" fill="#ffe08a" opacity="0.85"/>
<!-- far ridge -->
<path d="M0 640 L160 560 L320 600 L520 500 L720 560 L920 470 L1140 540 L1320 480 L1440 520 L1440 900 L0 900 Z" fill="url(#ridge2)" opacity="0.7"/>
<!-- near ridge -->
<path d="M0 720 L140 650 L300 700 L480 600 L640 680 L820 590 L1020 660 L1220 580 L1440 650 L1440 900 L0 900 Z" fill="url(#ridge1)"/>
<!-- foreground mountain -->
<path d="M0 900 L0 760 L220 600 L360 700 L520 540 L700 720 L860 560 L1040 760 L1240 620 L1440 780 L1440 900 Z" fill="#08161b"/>
<!-- birds -->
<path d="M360 300 q14 -12 28 0 q14 -12 28 0" stroke="#e9e3d6" stroke-width="3" fill="none" opacity="0.7"/>
<path d="M430 250 q11 -9 22 0 q11 -9 22 0" stroke="#e9e3d6" stroke-width="2.5" fill="none" opacity="0.6"/>
<path d="M300 340 q9 -8 18 0 q9 -8 18 0" stroke="#e9e3d6" stroke-width="2.5" fill="none" opacity="0.55"/>
</svg>
</div>
<div class="hero__frame">
<div class="hero__content">
<p class="kicker"><span class="kicker__dot"></span>Issue 214 · The Wild Edges</p>
<h1 id="hero-title">Where the<br/>map runs out.</h1>
<p class="hero__lead">A year tracing the planet's last untamed frontiers — from the wind-scoured fjords of Patagonia to the bioluminescent deep. Stories told the hard way: on foot, by sea, in silence.</p>
<div class="hero__cta">
<button class="btn btn--yellow btn--lg" id="readStory">Read the cover story</button>
<button class="btn btn--ghost btn--lg" id="watchFilm">
<span class="play" aria-hidden="true">▶</span> Watch the field film
</button>
</div>
<dl class="hero__meta">
<div><dt>Photographer</dt><dd>Lena Okafor</dd></div>
<div><dt>Region</dt><dd>Southern Patagonia</dd></div>
<div><dt>Reading time</dt><dd>18 min</dd></div>
</dl>
</div>
</div>
<span class="hero__scroll" aria-hidden="true">SCROLL <span>↓</span></span>
</section>
<!-- ===================== FEATURE STORIES ===================== -->
<section class="stories" id="stories" aria-labelledby="stories-title">
<div class="section-head">
<h2 id="stories-title" class="section-title">Feature dispatches</h2>
<p class="section-sub">Six frontiers, six teams, one season in the field.</p>
</div>
<div class="story-grid" id="storyGrid">
<!-- Lead story -->
<article class="story story--lead" data-region="patagonia" data-tags="patagonia ice glacier south america">
<div class="story__media" style="--g1:#1d3b4a;--g2:#3a7a6f;--g3:#d9b25a;" aria-hidden="true">
<span class="story__cat">Climate</span>
</div>
<div class="story__body">
<p class="story__eyebrow">Patagonia · Field log 04</p>
<h3 class="story__title">The glacier that breathes</h3>
<p class="story__excerpt">For nine days the team camped beneath a wall of ancient ice, listening to it crack like distant thunder — a record of a climate rewriting itself in real time.</p>
<button class="save-btn" type="button" aria-pressed="false" data-title="The glacier that breathes">
<span class="save-btn__ico" aria-hidden="true">♡</span><span class="save-btn__label">Save story</span>
</button>
</div>
</article>
<article class="story" data-region="ocean" data-tags="ocean deep sea bioluminescence pacific">
<div class="story__media" style="--g1:#0a1f3a;--g2:#143a6b;--g3:#2bd1c4;" aria-hidden="true">
<span class="story__cat">Ocean</span>
</div>
<div class="story__body">
<p class="story__eyebrow">Mid-Pacific · Dive 22</p>
<h3 class="story__title">Light in the deep dark</h3>
<p class="story__excerpt">Two kilometres down, life invents its own dawn.</p>
<button class="save-btn" type="button" aria-pressed="false" data-title="Light in the deep dark">
<span class="save-btn__ico" aria-hidden="true">♡</span><span class="save-btn__label">Save story</span>
</button>
</div>
</article>
<article class="story" data-region="himalaya" data-tags="snow leopard himalaya mountain asia wildlife">
<div class="story__media" style="--g1:#2a2433;--g2:#5a4e63;--g3:#cbb9c9;" aria-hidden="true">
<span class="story__cat">Wildlife</span>
</div>
<div class="story__body">
<p class="story__eyebrow">Upper Mustang · Camera trap 11</p>
<h3 class="story__title">Ghost of the high passes</h3>
<p class="story__excerpt">Forty-one nights for a single frame of a snow leopard.</p>
<button class="save-btn" type="button" aria-pressed="false" data-title="Ghost of the high passes">
<span class="save-btn__ico" aria-hidden="true">♡</span><span class="save-btn__label">Save story</span>
</button>
</div>
</article>
<article class="story" data-region="sahara" data-tags="sahara desert dunes africa sand">
<div class="story__media" style="--g1:#3a2410;--g2:#9a6a2a;--g3:#e8c264;" aria-hidden="true">
<span class="story__cat">Desert</span>
</div>
<div class="story__body">
<p class="story__eyebrow">Erg Chebbi · Day 7</p>
<h3 class="story__title">Reading the moving sand</h3>
<p class="story__excerpt">How nomad guides navigate dunes that erase every path by dusk.</p>
<button class="save-btn" type="button" aria-pressed="false" data-title="Reading the moving sand">
<span class="save-btn__ico" aria-hidden="true">♡</span><span class="save-btn__label">Save story</span>
</button>
</div>
</article>
<article class="story" data-region="amazon" data-tags="amazon rainforest canopy birds south america">
<div class="story__media" style="--g1:#0f2a16;--g2:#2f6b34;--g3:#9fd16a;" aria-hidden="true">
<span class="story__cat">Forest</span>
</div>
<div class="story__body">
<p class="story__eyebrow">Western Amazon · Canopy 03</p>
<h3 class="story__title">A city in the treetops</h3>
<p class="story__excerpt">Forty metres up, a hidden ecosystem hums after rain.</p>
<button class="save-btn" type="button" aria-pressed="false" data-title="A city in the treetops">
<span class="save-btn__ico" aria-hidden="true">♡</span><span class="save-btn__label">Save story</span>
</button>
</div>
</article>
</div>
</section>
<!-- ===================== EXPEDITION MAP ===================== -->
<section class="expedition" id="expedition" aria-labelledby="exp-title">
<div class="expedition__intro">
<p class="kicker kicker--dark"><span class="kicker__dot"></span>The 2026 route</p>
<h2 id="exp-title" class="section-title">One season. Five frontiers.</h2>
<p class="section-sub">Tap a waypoint to follow the expedition across the southern hemisphere — terrain, distance, and the team in the field.</p>
<ul class="expedition__legend" aria-hidden="true">
<li><span class="dot dot--leg"></span>Leg complete</li>
<li><span class="dot dot--active"></span>Current waypoint</li>
</ul>
</div>
<div class="map" role="group" aria-label="Interactive expedition map">
<svg class="map__svg" viewBox="0 0 600 420" aria-hidden="true">
<defs>
<linearGradient id="sea" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#0e2630"/>
<stop offset="1" stop-color="#143845"/>
</linearGradient>
</defs>
<rect width="600" height="420" fill="url(#sea)"/>
<g class="map__grid" stroke="#3a5560" stroke-width="0.6" opacity="0.35">
<line x1="0" y1="105" x2="600" y2="105"/><line x1="0" y1="210" x2="600" y2="210"/><line x1="0" y1="315" x2="600" y2="315"/>
<line x1="150" y1="0" x2="150" y2="420"/><line x1="300" y1="0" x2="300" y2="420"/><line x1="450" y1="0" x2="450" y2="420"/>
</g>
<!-- abstract landmasses -->
<path d="M60 120 q40 -40 110 -20 q60 18 50 70 q-10 60 -80 70 q-90 12 -100 -50 q-8 -45 20 -70 Z" fill="#274a44" opacity="0.85"/>
<path d="M330 70 q70 -20 120 20 q40 36 10 90 q-40 64 -120 50 q-60 -12 -50 -80 q8 -56 40 -80 Z" fill="#2f5a4d" opacity="0.85"/>
<path d="M200 280 q60 -30 130 0 q50 26 20 80 q-44 50 -130 36 q-70 -16 -60 -70 q6 -34 20 -46 Z" fill="#33614f" opacity="0.85"/>
<!-- route -->
<path id="routePath" d="M120 150 L390 130 L470 220 L300 320 L150 300" fill="none" stroke="#ffd24a" stroke-width="2.5" stroke-dasharray="7 6" stroke-linecap="round"/>
</svg>
<button class="pin" style="--x:20%;--y:35%;" data-wp="0" aria-label="Waypoint: Patagonia coast"><span></span></button>
<button class="pin" style="--x:65%;--y:31%;" data-wp="1" aria-label="Waypoint: Mid-Pacific dive site"><span></span></button>
<button class="pin" style="--x:78%;--y:52%;" data-wp="2" aria-label="Waypoint: Upper Mustang"><span></span></button>
<button class="pin pin--active" style="--x:50%;--y:76%;" data-wp="3" aria-label="Waypoint: Erg Chebbi dunes"><span></span></button>
<button class="pin" style="--x:25%;--y:71%;" data-wp="4" aria-label="Waypoint: Western Amazon"><span></span></button>
<div class="map__card" id="mapCard" role="status" aria-live="polite">
<p class="map__card-region" id="mapRegion">Erg Chebbi</p>
<p class="map__card-meta" id="mapMeta">Sahara, Morocco · Leg 4 of 5</p>
<dl class="map__stats">
<div><dt>Terrain</dt><dd id="mapTerrain">Active dune field</dd></div>
<div><dt>Distance</dt><dd id="mapDist">1,240 km</dd></div>
<div><dt>Team</dt><dd id="mapTeam">6 in the field</dd></div>
</dl>
</div>
</div>
</section>
<!-- ===================== EXPEDITION STAT BAND ===================== -->
<section class="band" id="band" aria-labelledby="band-title">
<div class="band__inner">
<h2 id="band-title" class="band__title">The season, in numbers</h2>
<div class="band__stats">
<div class="stat"><span class="stat__num" data-target="48230" data-suffix=" km">0</span><span class="stat__label">Distance travelled</span></div>
<div class="stat"><span class="stat__num" data-target="217">0</span><span class="stat__label">Days in the field</span></div>
<div class="stat"><span class="stat__num" data-target="34">0</span><span class="stat__label">Species documented</span></div>
<div class="stat"><span class="stat__num" data-target="9" data-suffix=" frontiers">0</span><span class="stat__label">Frontiers crossed</span></div>
</div>
</div>
</section>
<!-- ===================== CTA ===================== -->
<section class="cta" id="subscribe" aria-labelledby="cta-title">
<div class="cta__frame">
<p class="kicker"><span class="kicker__dot"></span>The Society</p>
<h2 id="cta-title">Go further than the photograph.</h2>
<p class="cta__lead">Field dispatches, expedition films, and the maps we draw in the dark — delivered the moment they come back from the wild.</p>
<form class="cta__form" id="subForm" novalidate>
<label class="sr-only" for="email">Email address</label>
<input type="email" id="email" name="email" placeholder="you@expedition.org" required />
<button class="btn btn--yellow btn--lg" type="submit">Become a member</button>
</form>
<p class="cta__error" id="subError" role="alert" hidden></p>
<p class="cta__fine">Fictional newsletter · no email is ever sent.</p>
</div>
</section>
</main>
<footer class="footer" role="contentinfo">
<div class="footer__inner">
<span class="brand brand--footer">
<span class="brand__mark" aria-hidden="true"></span>
<span class="brand__name">TERRA<span class="brand__sub">EXPEDITION</span></span>
</span>
<p class="footer__note">A fictional documentary-travel concept. Destinations, prices, and maps are illustrative only.</p>
<nav class="footer__links" aria-label="Footer">
<a href="#stories">Stories</a>
<a href="#expedition">Expeditions</a>
<a href="#subscribe">Membership</a>
</nav>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>National-Geographic-style Landing
A landing page for the fictional Terra Expedition journal, built in the documentary register of a National-Geographic cover: black ground, signature chrome-yellow accents, and crisp white type. Bold Playfair Display headlines carry the gravitas while a condensed Oswald sets the kickers and labels. The hero is a full-bleed horizon scene drawn entirely with CSS gradients and inline SVG — layered ridgelines, a low sun, and a flock of birds — framed by the iconic yellow border motif and overlaid with photographer, region, and reading-time metadata.
Below the fold, a feature-story grid leads with a tall cover dispatch and supporting cards, each with a category flag and a save-to-reading-list heart that toggles between outline and filled. An interactive expedition map lets you click or keyboard-arrow between five waypoints — from a Patagonian fjord to the western Amazon — updating a live field card with terrain, distance, and team size. A yellow stat band counts up the season in numbers as it scrolls into view, and an austere bordered call-to-action validates an email before confirming membership.
Everything runs on vanilla JS: a slide-down search panel, an accessible mobile menu, scroll-spy
nav highlighting, reveal-on-scroll cascades, count-up stats, and a small toast() helper that
confirms every action. Controls are keyboard-usable with visible focus rings, contrast meets
WCAG AA, motion respects prefers-reduced-motion, and the layout reflows cleanly down to ~360px.
Illustrative travel UI only — fictional destinations, prices, and maps.