News — Long-form Feature
An immersive editorial long-read for the fictional Meridian Review, opening on a full-bleed cinematic cover with an oversized Playfair masthead, byline and reading time, then a chaptered scroll body set in a strict column with hairline rules, a drop cap, captioned duotone press photos, full-bleed pull-quote breaks and a parallax night scene. A sticky chapter rail highlights the active section, a top progress bar tracks reading, and a slim masthead reveals on scroll, all driven by IntersectionObserver and vanilla JS.
MCP
Код
:root {
--cream: #f4efe4;
--paper: #faf7f0;
--white: #ffffff;
--newsprint: #efe9da;
--ink: #16130f;
--ink-2: #2b2620;
--ink-3: #4a443b;
--muted: #7a7164;
--red: #b4291f;
--red-d: #8f1f17;
--red-50: #f3dcd9;
--rule: rgba(22, 19, 15, 0.16);
--rule-2: rgba(22, 19, 15, 0.30);
--rule-hair: rgba(22, 19, 15, 0.10);
--ok: #2f7d4f;
--warn: #b67a18;
--danger: #b4291f;
--r-sm: 4px;
--r-md: 8px;
--r-lg: 12px;
--serif: "Playfair Display", "Times New Roman", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
--measure: 38rem;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--cream);
color: var(--ink);
font-family: var(--sans);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
h1, h2, h3 { margin: 0; }
p { margin: 0; }
a { color: inherit; }
/* ---------- Reading progress ---------- */
.progress {
position: fixed;
inset: 0 0 auto 0;
height: 3px;
background: transparent;
z-index: 60;
}
.progress__bar {
display: block;
height: 100%;
width: 0%;
background: var(--red);
transition: width 0.08s linear;
}
/* ---------- Slim top bar ---------- */
.topbar {
position: fixed;
top: 3px;
left: 0;
right: 0;
z-index: 50;
background: rgba(244, 239, 228, 0.86);
backdrop-filter: blur(8px);
border-bottom: 1px solid transparent;
transform: translateY(-110%);
transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1), border-color 0.35s;
}
.topbar.is-visible {
transform: translateY(0);
border-bottom-color: var(--rule);
}
.topbar__inner {
max-width: 1180px;
margin: 0 auto;
padding: 0.6rem 1.5rem;
display: flex;
align-items: center;
gap: 0.6rem;
}
.topbar__brand {
font-family: var(--serif);
font-weight: 800;
font-size: 1.05rem;
letter-spacing: 0.01em;
text-decoration: none;
color: var(--ink);
}
.topbar__sep { color: var(--rule-2); }
.topbar__kicker {
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.18em;
font-weight: 600;
color: var(--muted);
}
.topbar__share {
margin-left: auto;
font-family: var(--sans);
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.14em;
font-weight: 600;
color: var(--red);
background: none;
border: 1px solid var(--rule);
border-radius: var(--r-sm);
padding: 0.4rem 0.8rem;
cursor: pointer;
transition: background 0.2s, border-color 0.2s;
}
.topbar__share:hover { background: var(--red-50); border-color: var(--red); }
.topbar__share:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
/* ---------- Cover ---------- */
.cover {
position: relative;
min-height: 100vh;
min-height: 100svh;
display: flex;
align-items: flex-end;
overflow: hidden;
color: var(--paper);
}
.cover__art {
position: absolute;
inset: -12% 0 -12% 0;
background:
radial-gradient(120% 90% at 78% 18%, rgba(217, 142, 74, 0.55), transparent 55%),
radial-gradient(90% 70% at 18% 8%, rgba(180, 41, 31, 0.30), transparent 60%),
radial-gradient(140% 120% at 50% 120%, rgba(8, 9, 14, 0.92), transparent 60%),
linear-gradient(180deg, #1a1d2a 0%, #20202b 30%, #15110d 78%, #0c0a08 100%);
will-change: transform;
}
.cover__grain {
position: absolute;
inset: 0;
background-image:
repeating-linear-gradient(115deg, rgba(255, 220, 170, 0.05) 0 2px, transparent 2px 5px),
radial-gradient(2px 2px at 60% 30%, rgba(255, 200, 130, 0.5), transparent 60%),
radial-gradient(1.5px 1.5px at 72% 24%, rgba(255, 220, 160, 0.45), transparent 60%),
radial-gradient(2px 2px at 66% 40%, rgba(255, 190, 120, 0.35), transparent 60%);
opacity: 0.6;
mix-blend-mode: screen;
}
.cover__scrim {
position: absolute;
inset: 0;
background: linear-gradient(0deg, rgba(8, 7, 6, 0.78) 0%, rgba(8, 7, 6, 0.25) 45%, transparent 70%);
}
.cover__inner {
position: relative;
max-width: 1180px;
width: 100%;
margin: 0 auto;
padding: 0 1.5rem 5rem;
}
.cover__kicker {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.24em;
font-weight: 600;
color: #f0c9a0;
margin-bottom: 1.1rem;
display: inline-block;
border-bottom: 2px solid var(--red);
padding-bottom: 0.35rem;
}
.cover__title {
font-family: var(--serif);
font-weight: 900;
font-size: clamp(2.6rem, 8vw, 6rem);
line-height: 0.98;
letter-spacing: -0.015em;
max-width: 16ch;
margin-bottom: 1.4rem;
text-shadow: 0 2px 30px rgba(0, 0, 0, 0.4);
}
.cover__dek {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
font-size: clamp(1.05rem, 2.4vw, 1.5rem);
line-height: 1.45;
max-width: 46ch;
color: #ece3d4;
margin-bottom: 1.8rem;
}
.cover__meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.55rem;
font-size: 0.82rem;
letter-spacing: 0.02em;
color: #d8cdba;
}
.cover__byline strong { color: var(--paper); font-weight: 600; }
.cover__dot { color: rgba(255, 255, 255, 0.4); }
.cover__scroll {
margin-top: 2.6rem;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.22em;
color: #c9bda9;
animation: bob 2.4s ease-in-out infinite;
}
@keyframes bob {
0%, 100% { transform: translateY(0); opacity: 0.7; }
50% { transform: translateY(5px); opacity: 1; }
}
/* ---------- Shell layout ---------- */
.shell {
max-width: 1180px;
margin: 0 auto;
padding: 0 1.5rem;
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
gap: 3.5rem;
align-items: start;
}
/* ---------- Chapter rail ---------- */
.rail {
position: sticky;
top: 5.5rem;
padding-top: 4rem;
}
.rail__label {
font-size: 0.66rem;
text-transform: uppercase;
letter-spacing: 0.2em;
font-weight: 700;
color: var(--muted);
padding-bottom: 0.7rem;
border-bottom: 1px solid var(--rule);
margin-bottom: 0.4rem;
}
.rail__nav { display: flex; flex-direction: column; }
.rail__link {
display: flex;
align-items: baseline;
gap: 0.55rem;
padding: 0.6rem 0;
font-size: 0.86rem;
font-weight: 500;
color: var(--ink-3);
text-decoration: none;
border-bottom: 1px solid var(--rule-hair);
transition: color 0.2s, padding-left 0.2s;
}
.rail__num {
font-family: var(--serif);
font-weight: 700;
font-size: 0.78rem;
color: var(--muted);
transition: color 0.2s;
}
.rail__link:hover { color: var(--ink); padding-left: 0.25rem; }
.rail__link.is-active {
color: var(--red);
font-weight: 600;
padding-left: 0.25rem;
}
.rail__link.is-active .rail__num { color: var(--red); }
.rail__link:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
/* ---------- Article ---------- */
.article {
padding: 4rem 0 5rem;
max-width: 44rem;
}
.dateline {
font-family: var(--serif);
font-weight: 700;
font-size: 0.82rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--ink-2);
margin-bottom: 2rem;
}
.chapter { padding-top: 1rem; }
.chapter + .chapter { padding-top: 2rem; }
.chapter__head {
margin-bottom: 1.6rem;
padding-top: 1.5rem;
border-top: 1px solid var(--rule);
}
.chapter:first-of-type .chapter__head { border-top: none; padding-top: 0; }
.chapter__kicker {
display: block;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.2em;
font-weight: 600;
color: var(--red);
margin-bottom: 0.6rem;
}
.chapter__title {
font-family: var(--serif);
font-weight: 800;
font-size: clamp(1.7rem, 4vw, 2.5rem);
line-height: 1.05;
letter-spacing: -0.01em;
}
.article p {
font-size: 1.12rem;
line-height: 1.74;
color: var(--ink-2);
margin-bottom: 1.5rem;
text-align: justify;
hyphens: auto;
}
.article .lead {
font-size: 1.18rem;
}
.lead::first-letter {
font-family: var(--serif);
font-weight: 800;
font-size: 4.4rem;
line-height: 0.8;
float: left;
margin: 0.42rem 0.7rem 0 0;
color: var(--ink);
}
.endmark {
font-family: var(--serif);
font-style: italic;
color: var(--ink-3);
}
.endmark__sq {
display: inline-block;
width: 0.6rem;
height: 0.6rem;
background: var(--red);
margin-left: 0.5rem;
vertical-align: baseline;
transform: translateY(1px);
}
/* ---------- Figures ---------- */
.fig { margin: 2.5rem 0; }
.fig__img {
aspect-ratio: 16 / 10;
border-radius: var(--r-sm);
background-size: cover;
background-position: center;
position: relative;
overflow: hidden;
}
.fig__img::after {
content: "";
position: absolute;
inset: 0;
background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0 1px, transparent 1px 3px);
mix-blend-mode: multiply;
opacity: 0.5;
}
.fig--wide { margin: 3rem -2rem; }
.fig--wide .fig__img { aspect-ratio: 16 / 9; }
.fig__img--lamp {
background:
radial-gradient(40% 55% at 64% 34%, rgba(255, 196, 110, 0.85), rgba(255, 150, 60, 0.2) 40%, transparent 62%),
radial-gradient(90% 80% at 50% 110%, rgba(10, 12, 18, 0.95), transparent 65%),
linear-gradient(180deg, #232634 0%, #2a2620 55%, #120f0c 100%);
}
.fig__img--harbour {
background:
radial-gradient(80% 60% at 30% 25%, rgba(140, 165, 185, 0.55), transparent 60%),
linear-gradient(180deg, #5b6b78 0%, #45525d 38%, #2e3940 70%, #1d2429 100%);
}
.fig__img--pole {
background:
linear-gradient(105deg, rgba(214, 168, 92, 0.65) 0%, transparent 55%),
radial-gradient(70% 90% at 50% 50%, rgba(70, 58, 40, 0.4), transparent 70%),
linear-gradient(180deg, #3a3327 0%, #241f17 60%, #14110c 100%);
}
.fig__img--meeting {
background:
radial-gradient(50% 60% at 38% 42%, rgba(232, 156, 80, 0.7), rgba(176, 70, 30, 0.25) 45%, transparent 68%),
radial-gradient(90% 90% at 70% 100%, rgba(12, 9, 7, 0.9), transparent 60%),
linear-gradient(180deg, #3a2a1d 0%, #2a1d13 55%, #15100b 100%);
}
.fig__cap {
margin-top: 0.7rem;
padding-left: 0.9rem;
border-left: 2px solid var(--red);
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.fig--wide .fig__cap { margin-left: 2rem; }
.fig__cap-text {
font-family: var(--serif);
font-style: italic;
font-size: 0.95rem;
line-height: 1.4;
color: var(--ink-3);
}
.fig__credit {
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--muted);
font-weight: 500;
}
.grid2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin: 2.5rem 0;
}
.grid2 .fig { margin: 0; }
.grid2 .fig__img { aspect-ratio: 4 / 5; }
/* ---------- Pull quote break (full bleed) ---------- */
.pullbreak {
position: relative;
margin: 4rem calc(50% - 50vw);
width: 100vw;
padding: 5rem 1.5rem;
text-align: center;
color: var(--paper);
overflow: hidden;
background:
radial-gradient(80% 120% at 80% 20%, rgba(180, 41, 31, 0.35), transparent 55%),
linear-gradient(135deg, #1c1814 0%, #241d16 50%, #14100c 100%);
}
.pullbreak__quote {
position: relative;
font-family: var(--serif);
font-weight: 600;
font-style: italic;
font-size: clamp(1.5rem, 4.2vw, 2.8rem);
line-height: 1.28;
max-width: 22ch;
margin: 0 auto;
letter-spacing: -0.01em;
}
.pullbreak__attr {
position: relative;
margin-top: 1.6rem;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.2em;
font-weight: 600;
color: #e0a784;
}
/* ---------- Parallax scene ---------- */
.scene {
position: relative;
margin: 4rem calc(50% - 50vw);
width: 100vw;
min-height: 78vh;
display: flex;
align-items: flex-end;
overflow: hidden;
background:
radial-gradient(28% 40% at 22% 30%, rgba(255, 196, 110, 0.9), transparent 55%),
radial-gradient(24% 36% at 50% 22%, rgba(255, 184, 96, 0.7), transparent 55%),
radial-gradient(26% 40% at 78% 34%, rgba(255, 200, 120, 0.8), transparent 55%),
radial-gradient(120% 100% at 50% 120%, rgba(6, 8, 12, 0.95), transparent 60%),
linear-gradient(180deg, #1a1d2b 0%, #241d15 55%, #0c0a08 100%);
background-size: cover;
background-attachment: fixed;
}
.scene__overlay {
max-width: 1180px;
margin: 0 auto;
padding: 0 1.5rem 4rem;
width: 100%;
}
.scene__caption {
font-family: var(--serif);
font-style: italic;
font-weight: 500;
font-size: clamp(1.1rem, 2.6vw, 1.7rem);
line-height: 1.4;
color: #f1e7d6;
max-width: 40ch;
text-shadow: 0 2px 24px rgba(0, 0, 0, 0.5);
}
/* ---------- Colophon ---------- */
.colophon { margin-top: 4rem; }
.colophon__rule {
height: 0;
border-top: 3px double var(--rule-2);
margin-bottom: 1.6rem;
}
.colophon__line {
font-size: 0.95rem !important;
line-height: 1.6 !important;
color: var(--ink-3) !important;
text-align: left !important;
margin-bottom: 0.8rem !important;
}
.colophon__line strong { color: var(--ink); }
.colophon__meta {
font-size: 0.74rem !important;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--muted) !important;
text-align: left !important;
margin-bottom: 1.6rem !important;
}
.colophon__actions { display: flex; gap: 0.8rem; flex-wrap: wrap; }
.btn {
font-family: var(--sans);
font-size: 0.74rem;
text-transform: uppercase;
letter-spacing: 0.14em;
font-weight: 600;
padding: 0.7rem 1.3rem;
border-radius: var(--r-sm);
border: 1px solid var(--ink);
background: var(--ink);
color: var(--paper);
cursor: pointer;
transition: background 0.2s, color 0.2s;
}
.btn:hover { background: var(--red); border-color: var(--red); }
.btn:focus-visible { outline: 2px solid var(--red); outline-offset: 2px; }
.btn--ghost { background: none; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 2rem;
transform: translate(-50%, 1.5rem);
background: var(--ink);
color: var(--paper);
font-size: 0.85rem;
font-weight: 500;
letter-spacing: 0.01em;
padding: 0.8rem 1.3rem;
border-radius: var(--r-md);
border-left: 3px solid var(--red);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
opacity: 0;
pointer-events: none;
z-index: 70;
transition: opacity 0.3s, transform 0.3s;
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- Reveal ---------- */
[data-reveal] {
opacity: 0;
transform: translateY(22px);
transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
}
[data-reveal].is-in { opacity: 1; transform: none; }
/* ---------- Responsive ---------- */
@media (max-width: 980px) {
.shell { grid-template-columns: 1fr; gap: 0; }
.rail {
position: static;
padding-top: 2.5rem;
margin-bottom: 1rem;
}
.rail__nav { flex-flow: row wrap; gap: 0.4rem; }
.rail__link { border: 1px solid var(--rule); border-radius: 999px; padding: 0.4rem 0.85rem; }
.rail__link.is-active { background: var(--red-50); border-color: var(--red); padding-left: 0.85rem; }
.article { padding-top: 1.5rem; max-width: none; }
.fig--wide { margin: 2.5rem 0; }
.fig--wide .fig__cap { margin-left: 0; }
}
@media (max-width: 720px) {
.cover__inner { padding-bottom: 3rem; }
.grid2 { grid-template-columns: 1fr; }
.scene { background-attachment: scroll; min-height: 60vh; }
.article p { text-align: left; }
}
@media (max-width: 380px) {
.shell { padding: 0 1.1rem; }
.cover__inner { padding-left: 1.1rem; padding-right: 1.1rem; }
.lead::first-letter { font-size: 3.4rem; }
.article p { font-size: 1.05rem; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.cover__scroll { animation: none; }
[data-reveal] { transition: none; opacity: 1; transform: none; }
.scene { background-attachment: scroll; }
}(function () {
"use strict";
var prefersReduced = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2600);
}
/* ---------- Reading progress + top bar ---------- */
var progressBar = document.getElementById("progressBar");
var progressWrap = document.querySelector(".progress");
var topbar = document.getElementById("topbar");
var cover = document.getElementById("cover");
var ticking = false;
function onScroll() {
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
var docH =
document.documentElement.scrollHeight - window.innerHeight;
var pct = docH > 0 ? Math.min(1, Math.max(0, scrollTop / docH)) : 0;
if (progressBar) progressBar.style.width = (pct * 100).toFixed(2) + "%";
if (progressWrap)
progressWrap.setAttribute("aria-valuenow", Math.round(pct * 100));
// Reveal slim top bar once cover is mostly scrolled past
var coverH = cover ? cover.offsetHeight : window.innerHeight;
if (topbar) {
if (scrollTop > coverH * 0.65) topbar.classList.add("is-visible");
else topbar.classList.remove("is-visible");
}
// Parallax
if (!prefersReduced) applyParallax(scrollTop);
ticking = false;
}
function requestTick() {
if (!ticking) {
window.requestAnimationFrame(onScroll);
ticking = true;
}
}
/* ---------- Parallax ---------- */
var parallaxEls = Array.prototype.slice.call(
document.querySelectorAll("[data-parallax]")
);
function applyParallax(scrollTop) {
var vh = window.innerHeight;
for (var i = 0; i < parallaxEls.length; i++) {
var el = parallaxEls[i];
var speed = parseFloat(el.getAttribute("data-parallax")) || 0.15;
var rect = el.getBoundingClientRect();
// Distance of element center from viewport center
var center = rect.top + rect.height / 2;
var offset = (center - vh / 2) * speed * -1;
el.style.transform = "translate3d(0," + offset.toFixed(1) + "px,0)";
}
}
window.addEventListener("scroll", requestTick, { passive: true });
window.addEventListener("resize", requestTick);
/* ---------- Active-chapter tracking ---------- */
var railLinks = Array.prototype.slice.call(
document.querySelectorAll(".rail__link")
);
var chapters = Array.prototype.slice.call(
document.querySelectorAll(".chapter[data-chapter]")
);
var linkById = {};
railLinks.forEach(function (l) {
linkById[l.getAttribute("data-chapter")] = l;
});
function setActive(id) {
railLinks.forEach(function (l) {
l.classList.toggle(
"is-active",
l.getAttribute("data-chapter") === id
);
});
}
if ("IntersectionObserver" in window && chapters.length) {
var visible = {};
var chapterObserver = new IntersectionObserver(
function (entries) {
entries.forEach(function (e) {
visible[e.target.id] = e.isIntersecting
? e.intersectionRatio
: 0;
});
// pick the chapter with highest visibility
var best = null;
var bestRatio = 0;
chapters.forEach(function (c) {
var r = visible[c.id] || 0;
if (r > bestRatio) {
bestRatio = r;
best = c.id;
}
});
if (best) setActive(best);
},
{
rootMargin: "-30% 0px -45% 0px",
threshold: [0, 0.2, 0.5, 0.8, 1],
}
);
chapters.forEach(function (c) {
chapterObserver.observe(c);
});
} else if (chapters.length) {
setActive(chapters[0].id);
}
// Smooth-scroll + immediate highlight on rail click
railLinks.forEach(function (link) {
link.addEventListener("click", function () {
setActive(link.getAttribute("data-chapter"));
});
});
/* ---------- Reveal on scroll ---------- */
var revealTargets = [].slice.call(
document.querySelectorAll(".fig, .grid2, .pullbreak, .chapter__head")
);
revealTargets.forEach(function (el) {
el.setAttribute("data-reveal", "");
});
if ("IntersectionObserver" in window && !prefersReduced) {
var revealObserver = new IntersectionObserver(
function (entries, obs) {
entries.forEach(function (e) {
if (e.isIntersecting) {
e.target.classList.add("is-in");
obs.unobserve(e.target);
}
});
},
{ rootMargin: "0px 0px -10% 0px", threshold: 0.12 }
);
revealTargets.forEach(function (el) {
revealObserver.observe(el);
});
} else {
revealTargets.forEach(function (el) {
el.classList.add("is-in");
});
}
/* ---------- Share ---------- */
function share() {
var data = {
title: document.title,
text: "The Last Lamp Lighter of Vellmark — The Meridian Review",
url: location.href,
};
if (navigator.share) {
navigator.share(data).catch(function () {});
} else if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard
.writeText(location.href)
.then(function () {
toast("Link copied to clipboard");
})
.catch(function () {
toast("Share this story");
});
} else {
toast("Share this story");
}
}
["shareTop", "shareBottom"].forEach(function (id) {
var b = document.getElementById(id);
if (b) b.addEventListener("click", share);
});
var toTopBtn = document.getElementById("toTop");
if (toTopBtn) {
toTopBtn.addEventListener("click", function () {
window.scrollTo({
top: 0,
behavior: prefersReduced ? "auto" : "smooth",
});
});
}
// Initial paint
requestTick();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>The Meridian Review — The Last Lamp Lighter of Vellmark</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,600;0,700;0,800;0,900;1,500;1,700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Reading progress -->
<div class="progress" role="progressbar" aria-label="Reading progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<span class="progress__bar" id="progressBar"></span>
</div>
<!-- Slim masthead bar -->
<div class="topbar" id="topbar">
<div class="topbar__inner">
<a class="topbar__brand" href="#cover">The Meridian Review</a>
<span class="topbar__sep" aria-hidden="true">·</span>
<span class="topbar__kicker">The Long Read</span>
<button class="topbar__share" id="shareTop" type="button">Share</button>
</div>
</div>
<!-- COVER -->
<header class="cover" id="cover">
<div class="cover__art" data-parallax="0.25" aria-hidden="true">
<span class="cover__grain"></span>
</div>
<div class="cover__scrim" aria-hidden="true"></div>
<div class="cover__inner">
<p class="cover__kicker">Dispatch · Vellmark Coast</p>
<h1 class="cover__title">The Last Lamp Lighter of Vellmark</h1>
<p class="cover__dek">For ninety years a single family kept the harbour burning by hand. Now the
old gas mains are going dark — and Ines Calloway is deciding what is worth carrying into the
electric age.</p>
<div class="cover__meta">
<span class="cover__byline">By <strong>Marisol Vane</strong></span>
<span class="cover__dot" aria-hidden="true">·</span>
<span>Photographs by Ezra Holt</span>
<span class="cover__dot" aria-hidden="true">·</span>
<span>18 min read</span>
</div>
<p class="cover__scroll" aria-hidden="true">Scroll to begin</p>
</div>
</header>
<!-- LAYOUT: sidebar + article -->
<div class="shell">
<!-- Chapter rail -->
<aside class="rail" aria-label="Chapters">
<p class="rail__label">Chapters</p>
<nav class="rail__nav" id="rail">
<a class="rail__link" href="#ch-1" data-chapter="ch-1"><span class="rail__num">01</span>The dark mile</a>
<a class="rail__link" href="#ch-2" data-chapter="ch-2"><span class="rail__num">02</span>A trade by hand</a>
<a class="rail__link" href="#ch-3" data-chapter="ch-3"><span class="rail__num">03</span>The vote on Pier Road</a>
<a class="rail__link" href="#ch-4" data-chapter="ch-4"><span class="rail__num">04</span>What the light was for</a>
</nav>
</aside>
<article class="article">
<!-- Dateline + lead -->
<p class="dateline">VELLMARK, on the northern coast —</p>
<section class="chapter" id="ch-1" data-chapter="ch-1">
<header class="chapter__head">
<span class="chapter__kicker">Chapter One</span>
<h2 class="chapter__title">The dark mile</h2>
</header>
<p class="lead">Every evening at the turn of dusk, Ines Calloway lifts a brass pole nearly
twice her height, walks the length of Harbour Crescent, and brings light to a town that the
rest of the country forgot how to illuminate by hand. There are thirty-one lamps between the
customs house and the breakwater. She knows each by its temperament — which one sputters in a
westerly, which one she must coax twice before it holds.</p>
<p>The Calloways have lit Vellmark since 1934, when the gasworks first ran a main beneath the
cobbles and the borough council hired Ines's great-grandfather to keep the flames true. The
job passed from his hands to his daughter's, then to her son's, and finally — three winters
ago, after the funeral — to Ines, who was twenty-six and had only ever meant to stay a
season. "I told myself one year," she says, threading a taper through the lamp's small glass
door. "Then the council sent the letter, and one year became the point of the whole thing."</p>
<figure class="fig fig--wide">
<div class="fig__img fig__img--lamp" data-parallax="0.12" aria-hidden="true"></div>
<figcaption class="fig__cap">
<span class="fig__cap-text">Ines Calloway lights the first lamp on Harbour Crescent at the
turn of dusk, a ritual her family has kept for four generations.</span>
<span class="fig__credit">Ezra Holt for The Meridian Review</span>
</figcaption>
</figure>
<p>The letter she means arrived in a council envelope last autumn. The regional utility, citing
the cost of maintaining a gas network for a single mile of decorative lighting, had set a
date to cap the mains. Vellmark's lamps would be retrofitted with sealed LED heads — efficient,
weatherproof, and entirely automatic. There would be nothing left to light.</p>
</section>
<!-- PULL QUOTE BREAK (full bleed) -->
<aside class="pullbreak" data-parallax="0.18">
<blockquote class="pullbreak__quote">
“A lamp that lights itself is a fine thing. But it asks nothing of the town, and a town
that is asked nothing slowly forgets what it owns.”
</blockquote>
<p class="pullbreak__attr">— Ines Calloway</p>
</aside>
<section class="chapter" id="ch-2" data-chapter="ch-2">
<header class="chapter__head">
<span class="chapter__kicker">Chapter Two</span>
<h2 class="chapter__title">A trade by hand</h2>
</header>
<p>The work is older than the gas. Before the mains, the Calloways carried whale oil in a tin
slung at the hip and a smouldering punk to catch the wick. The brass pole Ines uses tonight is
the same one her great-grandfather carried, its grip worn pale and smooth where four sets of
hands have closed around it at the same height, in the same place, ten thousand evenings
running.</p>
<p>She is precise about the order. South side first, working seaward, because the wind comes off
the water and a lit lamp behind her shoulders the gust. Then back along the north terrace,
where the houses lean close and the glow pools warm against the brick. The whole circuit takes
fifty-one minutes. She has done it in the rain, in fog so thick the harbour bell sounded like
it came from underwater, and once, memorably, in a gale that snapped the pole and sent her
home to splint it with a chair leg and twine.</p>
<div class="grid2">
<figure class="fig">
<div class="fig__img fig__img--harbour" aria-hidden="true"></div>
<figcaption class="fig__cap">
<span class="fig__cap-text">The breakwater at low tide, where the circuit ends.</span>
<span class="fig__credit">Ezra Holt</span>
</figcaption>
</figure>
<figure class="fig">
<div class="fig__img fig__img--pole" aria-hidden="true"></div>
<figcaption class="fig__cap">
<span class="fig__cap-text">The brass pole, carried by four generations of the family.</span>
<span class="fig__credit">Ezra Holt</span>
</figcaption>
</figure>
</div>
<p>What strikes you, walking the circuit beside her, is how much of the town arranges itself
around her passage. The baker on Pier Road leaves the shutters up an extra ten minutes so the
window light meets the lamp light. An old man named Doyle, who has not left his flat in a year,
opens his curtains the moment the lamp below him catches. "He waves," Ines says, not looking up.
"I never see him, but I know he waves."</p>
</section>
<!-- PARALLAX FIGURE SECTION -->
<section class="scene" data-parallax="0.3" aria-label="Night on Harbour Crescent">
<div class="scene__overlay">
<p class="scene__caption">By nine o'clock the crescent holds a colour the engineers have a
number for and the town has a name for. The number is 1,800 kelvin. The name is “the
old gold.”</p>
</div>
</section>
<section class="chapter" id="ch-3" data-chapter="ch-3">
<header class="chapter__head">
<span class="chapter__kicker">Chapter Three</span>
<h2 class="chapter__title">The vote on Pier Road</h2>
</header>
<p>The council met in March in the upstairs room of the Anchor, because the chamber's heating had
failed and the Anchor had a fire. Forty-one residents came, which in Vellmark is a landslide of
attendance. The motion was simple: accept the utility's retrofit and the small annual saving it
promised, or pay — out of a borough that counts every pound — to keep one mile of gas alive and
one lamplighter employed.</p>
<p>The arithmetic favoured the LEDs and everyone in the room knew it. What the arithmetic could
not price was the thing Doyle's wave stood for, and so the meeting went long. A retired ferry
captain argued that the lamps were the last working object in town older than the road. A
schoolteacher pointed out, gently, that romance is a poor line item. Ines did not speak. "It
wasn't mine to win," she told me afterward. "If they kept the gas only to keep me, that's a
charity, not a town. I'd rather lose it honest."</p>
<figure class="fig fig--wide">
<div class="fig__img fig__img--meeting" data-parallax="0.1" aria-hidden="true"></div>
<figcaption class="fig__cap">
<span class="fig__cap-text">The upstairs room of the Anchor, where forty-one residents debated
the future of the harbour lamps by firelight.</span>
<span class="fig__credit">Ezra Holt for The Meridian Review</span>
</figcaption>
</figure>
<p>The vote, when it came, was twenty-two to nineteen — to keep the gas, for now, on a five-year
trial, funded by a levy of eleven pounds a household and a grant the captain had quietly secured
from a maritime trust. It is not a victory so much as a stay. In five years the room will fill
again, and the arithmetic will not have changed.</p>
</section>
<section class="chapter" id="ch-4" data-chapter="ch-4">
<header class="chapter__head">
<span class="chapter__kicker">Chapter Four</span>
<h2 class="chapter__title">What the light was for</h2>
</header>
<p>On my last evening, the fog came in early and the circuit took an hour and ten. Ines did not
hurry. At the breakwater she lit the final lamp, the thirty-first, the one that faces open water,
and stood a moment with the pole resting against her shoulder while the beam stretched out over
the grey and lost itself.</p>
<p>I asked her what she thought the light was for, now that the harbour has radar and the boats
have GPS and nothing out there is steering by a gas flame on a pole. She considered it for a
long time, the way she considers a lamp that won't hold.</p>
<p>"It's not for the boats," she said finally. "It never really was. It's for the town to see
itself by. So that when you come home over the hill in the dark, there's a string of small fires
someone lit on purpose, for you, by hand. You don't need it. You'd just miss it." She shouldered
the pole and started back. "And missing a thing," she said, "is how a town remembers it was loved."</p>
<p class="endmark">The five-year trial begins this autumn. Ines Calloway will light the harbour
again at dusk on the first of September, as her family has since 1934.<span class="endmark__sq" aria-hidden="true"></span></p>
</section>
<!-- Footer / colophon -->
<footer class="colophon">
<p class="colophon__rule"></p>
<p class="colophon__line"><strong>Marisol Vane</strong> is a contributing writer for The Meridian
Review covering coastal communities. <strong>Ezra Holt</strong> is a staff photographer.</p>
<p class="colophon__meta">The Meridian Review · The Long Read · This story is a work of fiction.</p>
<div class="colophon__actions">
<button class="btn" id="shareBottom" type="button">Share this story</button>
<button class="btn btn--ghost" id="toTop" type="button">Back to top</button>
</div>
</footer>
</article>
</div>
<!-- Toast -->
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Long-form Feature
A cinematic magazine long-read for The Meridian Review, a fictional paper. The piece opens on a full-bleed cover — a duotone gradient “press photo” of a harbour at dusk, a huge Playfair Display title, an italic deck, and a byline with photographer credit and an eighteen-minute reading estimate. As you scroll past the cover, a thin progress bar tracks how far you’ve read and a slim masthead bar slides down to keep the paper’s name in reach.
The body is set in a single editorial column with hairline rules between chapters, a drop cap on the lead paragraph, justified text with hyphenation, captioned figures with red caption rules and credit lines, and oversized full-bleed pull-quote breaks. A fixed parallax night scene shifts beneath the text, and a sticky chapter rail on the left highlights whichever chapter is currently in view. The whole story — masthead, headlines, bylines and prose — is original, clearly-fictional editorial copy.
Interactions are pure vanilla JS: a requestAnimationFrame scroll loop drives the progress bar,
parallax transforms and the reveal-on-scroll masthead; an IntersectionObserver tracks the active
chapter for the rail; a second observer reveals figures and quote breaks as they enter; and Share /
Back-to-top controls use the Web Share API with a clipboard fallback and a small toast() helper.
Everything degrades gracefully and respects prefers-reduced-motion.
Illustrative UI only — masthead, headlines, bylines, and articles are fictional; not a real news publication.