News — Magazine Table of Contents
A print-grade magazine table of contents for an editorial issue, built with strict column grids and hairline rules. An issue masthead carries the logo, number, and date above a featured on-the-cover hero with a duotone press photo, drop cap, and pull quote. Categorized listings for Features, Departments, and Columns pair page numbers, deks, and contributors, while category tabs, a live title search, and a floating hover thumbnail make the page feel alive.
MCP
Código
: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.3);
--rule-hair: rgba(22, 19, 15, 0.1);
--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;
--maxw: 1180px;
}
* {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
font-family: var(--sans);
font-size: 16px;
line-height: 1.5;
color: var(--ink);
background: var(--cream);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-image:
radial-gradient(rgba(22, 19, 15, 0.015) 1px, transparent 1px);
background-size: 4px 4px;
}
.skip-link {
position: absolute;
left: -999px;
top: 0;
background: var(--ink);
color: var(--paper);
padding: 10px 16px;
z-index: 50;
text-decoration: none;
border-radius: 0 0 var(--r-sm) 0;
}
.skip-link:focus {
left: 0;
}
.paper {
max-width: var(--maxw);
margin: 0 auto;
background: var(--paper);
padding: 28px clamp(18px, 4vw, 56px) 40px;
border-left: 1px solid var(--rule-hair);
border-right: 1px solid var(--rule-hair);
min-height: 100vh;
}
/* ---------- Rules ---------- */
.rule {
height: 1px;
background: var(--rule);
margin: 18px 0;
}
.rule--thick {
height: 3px;
background: var(--ink);
position: relative;
margin: 16px 0;
}
.rule--thick::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -4px;
height: 1px;
background: var(--rule);
}
/* ---------- Masthead / Issue header ---------- */
.issue-head {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
gap: 12px;
padding-bottom: 8px;
}
.issue-meta {
font-size: 12px;
letter-spacing: 0.04em;
color: var(--ink-3);
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.issue-meta--right {
justify-content: flex-end;
}
.issue-meta__no {
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.12em;
}
.issue-meta__sep {
color: var(--rule-2);
}
.issue-meta__theme {
color: var(--red);
font-weight: 600;
font-style: italic;
}
.masthead {
text-align: center;
text-decoration: none;
color: inherit;
display: grid;
justify-items: center;
gap: 2px;
}
.masthead__kicker {
font-family: var(--serif);
font-style: italic;
font-size: 14px;
color: var(--ink-3);
}
.masthead__name {
font-family: var(--serif);
font-weight: 900;
font-size: clamp(28px, 6vw, 56px);
line-height: 0.95;
letter-spacing: -0.01em;
white-space: nowrap;
}
.masthead__rule {
width: 64px;
height: 2px;
background: var(--red);
margin: 6px 0 4px;
}
.masthead__tag {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.22em;
color: var(--muted);
}
/* ---------- Toolbar ---------- */
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
}
.search {
display: flex;
align-items: center;
gap: 8px;
background: var(--white);
border: 1px solid var(--rule);
border-radius: var(--r-sm);
padding: 8px 12px;
min-width: 240px;
flex: 1 1 260px;
max-width: 360px;
}
.search:focus-within {
border-color: var(--ink);
box-shadow: 0 0 0 3px var(--red-50);
}
.search__icon {
width: 18px;
height: 18px;
color: var(--muted);
flex: none;
}
.search input {
border: 0;
outline: 0;
background: transparent;
font-family: var(--sans);
font-size: 14px;
color: var(--ink);
width: 100%;
}
.search input::placeholder {
color: var(--muted);
}
.tabs {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.tab {
font-family: var(--sans);
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--ink-3);
background: transparent;
border: 1px solid transparent;
padding: 7px 13px;
border-radius: var(--r-sm);
cursor: pointer;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.tab:hover {
background: var(--newsprint);
color: var(--ink);
}
.tab:focus-visible {
outline: 2px solid var(--red);
outline-offset: 2px;
}
.tab.is-active {
background: var(--ink);
color: var(--paper);
}
/* ---------- Press photos (simulated) ---------- */
.press-photo {
width: 100%;
height: 100%;
border-radius: var(--r-sm);
position: relative;
overflow: hidden;
filter: contrast(1.04) saturate(0.9);
box-shadow: inset 0 0 0 1px rgba(22, 19, 15, 0.18);
}
.press-photo::after {
content: "";
position: absolute;
inset: 0;
background-image: radial-gradient(rgba(0, 0, 0, 0.16) 1px, transparent 1px);
background-size: 3px 3px;
mix-blend-mode: multiply;
opacity: 0.5;
}
.press-photo--cover {
background:
radial-gradient(120% 80% at 78% 12%, rgba(244, 222, 178, 0.95) 0%, rgba(212, 168, 96, 0.55) 26%, transparent 55%),
linear-gradient(178deg, #cdb98f 0%, #9c8a6a 24%, #6f6450 46%, #43403a 70%, #23211d 100%),
linear-gradient(90deg, rgba(180, 41, 31, 0.18), transparent 60%);
}
/* Thumbnail palettes — duotone-ink/red press feel */
.thumb {
background-color: #6f6450;
box-shadow: inset 0 0 0 1px rgba(22, 19, 15, 0.2);
}
.thumb-g1 { background: radial-gradient(110% 80% at 70% 18%, #e6cfa0 0, #8a7a5c 40%, #2a2722 100%); }
.thumb-g2 { background: linear-gradient(160deg, #4a5a63 0%, #2b3a42 50%, #14181b 100%); }
.thumb-g3 { background: radial-gradient(120% 90% at 30% 20%, #d9c1a0 0, #b4291f 70%, #5a1812 100%); }
.thumb-g4 { background: linear-gradient(180deg, #93a3a8 0%, #5d6f74 40%, #1e2629 100%); }
.thumb-g5 { background: linear-gradient(150deg, #c9b48f 0%, #7a6b50 55%, #2c281f 100%); }
.thumb-g6 { background: radial-gradient(120% 90% at 80% 20%, #e8d6b3 0, #9a6f3a 60%, #3a2a17 100%); }
.thumb-g7 { background: linear-gradient(160deg, #7f8c5e 0%, #4d5638 50%, #1c2014 100%); }
.thumb-g8 { background: radial-gradient(120% 90% at 25% 25%, #e3c9b0 0, #a8543a 65%, #3d1c12 100%); }
.thumb-g9 { background: linear-gradient(155deg, #b8ada0 0%, #6c6358 50%, #211f1b 100%); }
.thumb-g10 { background: radial-gradient(120% 90% at 70% 25%, #cdd9d6 0, #5e7370 60%, #1c2624 100%); }
.thumb-g11 { background: linear-gradient(165deg, #c2a98a 0%, #6e5b44 55%, #261f17 100%); }
.thumb-g12 { background: radial-gradient(110% 90% at 35% 30%, #e0d2b6 0, #b4291f 75%, #561610 100%); }
/* ---------- Kicker / shared editorial type ---------- */
.kicker {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.2em;
color: var(--ink-3);
margin: 0 0 12px;
}
.kicker--red {
color: var(--red);
}
.folio {
display: inline-block;
font-family: var(--sans);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.1em;
color: var(--red);
margin-bottom: 8px;
}
/* ---------- Cover feature ---------- */
.cover-feature {
padding: 22px 0 4px;
}
.cover-feature__grid {
display: grid;
grid-template-columns: 0.85fr 1.15fr;
gap: clamp(20px, 4vw, 44px);
align-items: start;
}
.cover-feature__fig {
margin: 0;
}
.cover-feature__fig .press-photo {
aspect-ratio: 4 / 5;
}
figcaption {
font-family: var(--serif);
font-style: italic;
font-size: 13px;
color: var(--ink-3);
margin-top: 8px;
line-height: 1.45;
}
.credit {
display: block;
font-family: var(--sans);
font-style: normal;
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.14em;
color: var(--muted);
margin-top: 4px;
}
.cover-feature__title {
font-family: var(--serif);
font-weight: 800;
font-size: clamp(30px, 5.2vw, 52px);
line-height: 1.02;
letter-spacing: -0.015em;
margin: 2px 0 14px;
}
.dek {
font-size: 17px;
line-height: 1.6;
color: var(--ink-2);
text-align: justify;
hyphens: auto;
margin: 0 0 14px;
}
.dropcap {
float: left;
font-family: var(--serif);
font-weight: 800;
font-size: 4.4em;
line-height: 0.78;
padding: 4px 10px 0 0;
color: var(--red);
}
.byline {
font-size: 13px;
color: var(--ink-3);
margin: 0;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.byline strong {
color: var(--ink);
}
.byline__sep {
color: var(--rule-2);
}
.readtime {
font-variant: small-caps;
letter-spacing: 0.04em;
}
.pullquote {
margin: 24px 0 0;
padding: 18px 0;
border-top: 1px solid var(--rule);
border-bottom: 1px solid var(--rule);
text-align: center;
}
.pullquote p {
font-family: var(--serif);
font-style: italic;
font-weight: 600;
font-size: clamp(20px, 3.4vw, 30px);
line-height: 1.25;
color: var(--ink);
margin: 0 auto;
max-width: 22ch;
}
/* ---------- Listings ---------- */
.listings {
columns: 2;
column-gap: clamp(28px, 5vw, 56px);
margin-top: 22px;
}
.block {
break-inside: avoid;
-webkit-column-break-inside: avoid;
margin-bottom: 26px;
}
.block__head {
display: flex;
align-items: baseline;
justify-content: space-between;
border-bottom: 2px solid var(--ink);
padding-bottom: 6px;
margin-bottom: 6px;
}
.block__title {
font-family: var(--serif);
font-weight: 700;
font-size: 22px;
margin: 0;
letter-spacing: -0.01em;
}
.block__count {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.16em;
color: var(--muted);
}
.entries {
list-style: none;
margin: 0;
padding: 0;
}
.entry {
display: grid;
grid-template-columns: 34px 1fr;
grid-template-areas:
"folio main"
"folio author";
gap: 0 12px;
padding: 11px 6px 11px 0;
border-bottom: 1px solid var(--rule-hair);
cursor: default;
transition: background 0.12s, padding 0.12s;
position: relative;
}
.entry:last-child {
border-bottom: 0;
}
.entry:hover,
.entry:focus-visible {
background: var(--newsprint);
outline: none;
padding-left: 8px;
}
.entry:focus-visible {
box-shadow: inset 3px 0 0 var(--red);
}
.entry__folio {
grid-area: folio;
font-family: var(--sans);
font-size: 13px;
font-weight: 700;
color: var(--red);
letter-spacing: 0.02em;
padding-top: 2px;
}
.entry__main {
grid-area: main;
}
.entry__title {
font-family: var(--serif);
font-weight: 600;
font-size: 17px;
line-height: 1.2;
margin: 0 0 3px;
}
.entry:hover .entry__title {
text-decoration: underline;
text-decoration-color: var(--red);
text-underline-offset: 3px;
}
.entry__dek {
font-size: 13px;
line-height: 1.45;
color: var(--ink-3);
margin: 0;
}
.entry__author {
grid-area: author;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted);
margin-top: 5px;
}
.entry__author::before {
content: "— ";
}
.entry[hidden] {
display: none;
}
.block.is-empty {
display: none;
}
.no-results {
font-family: var(--serif);
font-style: italic;
font-size: 18px;
color: var(--ink-3);
text-align: center;
padding: 30px 0;
}
.no-results__term {
color: var(--red);
font-style: normal;
}
/* ---------- Hover preview ---------- */
.preview {
position: fixed;
z-index: 40;
width: 168px;
pointer-events: none;
background: var(--white);
border: 1px solid var(--ink);
border-radius: var(--r-sm);
padding: 6px;
box-shadow: 6px 6px 0 rgba(22, 19, 15, 0.12);
transform: translateY(-50%);
transition: opacity 0.1s ease;
}
.preview[hidden] {
display: none;
}
.preview__thumb {
width: 100%;
aspect-ratio: 4 / 3;
border-radius: 2px;
}
.preview__label {
font-family: var(--serif);
font-style: italic;
font-size: 12px;
color: var(--ink-2);
margin: 6px 2px 2px;
line-height: 1.25;
}
/* ---------- Contributors ---------- */
.contributors {
margin-top: 26px;
}
.contributors__title {
font-family: var(--serif);
font-weight: 700;
font-size: 20px;
margin: 0 0 14px;
letter-spacing: -0.01em;
}
.contributors__list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: clamp(16px, 3vw, 32px);
}
.contributor {
display: grid;
grid-template-columns: 40px 1fr;
gap: 12px;
align-items: start;
border-top: 1px solid var(--rule);
padding-top: 12px;
}
.contributor p {
margin: 0;
font-size: 13px;
line-height: 1.45;
color: var(--ink-3);
}
.contributor p strong {
color: var(--ink);
}
.contributor__avatar {
width: 40px;
height: 40px;
border-radius: 50%;
display: grid;
place-items: center;
font-family: var(--serif);
font-weight: 700;
font-size: 15px;
color: var(--paper);
background: linear-gradient(150deg, var(--ink-3), var(--ink));
box-shadow: inset 0 0 0 2px var(--red);
}
.colophon {
text-align: center;
font-size: 11px;
letter-spacing: 0.08em;
color: var(--muted);
text-transform: uppercase;
margin: 14px 0 0;
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 16px);
background: var(--ink);
color: var(--paper);
font-size: 13px;
font-weight: 500;
padding: 11px 18px;
border-radius: var(--r-sm);
box-shadow: 0 8px 24px rgba(22, 19, 15, 0.28);
border-left: 3px solid var(--red);
opacity: 0;
transition: opacity 0.2s, transform 0.2s;
z-index: 60;
max-width: 90vw;
}
.toast.is-visible {
opacity: 1;
transform: translate(-50%, 0);
}
/* ---------- Responsive ---------- */
@media (max-width: 920px) {
.contributors__list {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 720px) {
.issue-head {
grid-template-columns: 1fr;
gap: 8px;
text-align: center;
}
.issue-meta,
.issue-meta--right {
justify-content: center;
}
.cover-feature__grid {
grid-template-columns: 1fr;
}
.cover-feature__fig .press-photo {
aspect-ratio: 16 / 10;
}
.listings {
columns: 1;
}
.preview {
display: none !important;
}
}
@media (max-width: 420px) {
.paper {
padding: 22px 16px 32px;
}
.toolbar {
flex-direction: column;
align-items: stretch;
}
.search {
max-width: none;
}
.tabs {
justify-content: space-between;
}
.contributors__list {
grid-template-columns: 1fr;
}
.masthead__name {
white-space: normal;
}
}
@media (prefers-reduced-motion: reduce) {
* {
transition: none !important;
}
}(function () {
"use strict";
var doc = document;
/* ---------- Toast helper ---------- */
var toastEl = doc.querySelector(".toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.hidden = false;
// force reflow so transition runs
void toastEl.offsetWidth;
toastEl.classList.add("is-visible");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-visible");
setTimeout(function () {
toastEl.hidden = true;
}, 220);
}, 2200);
}
/* ---------- State ---------- */
var currentFilter = "all";
var currentQuery = "";
var blocks = Array.prototype.slice.call(doc.querySelectorAll(".block"));
var entries = Array.prototype.slice.call(doc.querySelectorAll(".entry"));
var coverFeature = doc.querySelector(".cover-feature");
var noResults = doc.querySelector(".no-results");
var noResultsTerm = noResults ? noResults.querySelector(".no-results__term") : null;
function entryText(entry) {
var title = entry.querySelector(".entry__title");
var dek = entry.querySelector(".entry__dek");
var author = entry.querySelector(".entry__author");
return [
title ? title.textContent : "",
dek ? dek.textContent : "",
author ? author.textContent : ""
]
.join(" ")
.toLowerCase();
}
function applyState() {
var q = currentQuery.trim().toLowerCase();
var totalVisible = 0;
blocks.forEach(function (block) {
var section = block.getAttribute("data-section");
var sectionMatch = currentFilter === "all" || currentFilter === section;
var visibleInBlock = 0;
var blockEntries = block.querySelectorAll(".entry");
Array.prototype.forEach.call(blockEntries, function (entry) {
var queryMatch = q === "" || entryText(entry).indexOf(q) !== -1;
var show = sectionMatch && queryMatch;
entry.hidden = !show;
if (show) {
visibleInBlock++;
totalVisible++;
}
});
block.classList.toggle("is-empty", visibleInBlock === 0);
});
// Cover feature only shows under "all" or "features", and respects search.
if (coverFeature) {
var section = coverFeature.getAttribute("data-section");
var sectionMatch = currentFilter === "all" || currentFilter === section;
var coverTitle = coverFeature.querySelector(".cover-feature__title");
var coverText = (coverTitle ? coverTitle.textContent : "").toLowerCase();
var queryMatch = q === "" || coverText.indexOf(q) !== -1;
coverFeature.hidden = !(sectionMatch && queryMatch);
if (sectionMatch && queryMatch) totalVisible++;
}
if (noResults) {
var none = totalVisible === 0;
noResults.hidden = !none;
if (none && noResultsTerm) {
noResultsTerm.textContent = q ? "“" + currentQuery.trim() + "”" : "this filter";
}
}
}
/* ---------- Tabs ---------- */
var tabs = Array.prototype.slice.call(doc.querySelectorAll(".tab"));
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("is-active");
t.setAttribute("aria-pressed", "false");
});
tab.classList.add("is-active");
tab.setAttribute("aria-pressed", "true");
currentFilter = tab.getAttribute("data-filter") || "all";
applyState();
var label = tab.textContent.trim();
toast(currentFilter === "all" ? "Showing the full issue" : "Filtered to " + label);
});
});
/* ---------- Search ---------- */
var searchInput = doc.getElementById("toc-search");
if (searchInput) {
var debounce = null;
searchInput.addEventListener("input", function () {
currentQuery = searchInput.value;
clearTimeout(debounce);
debounce = setTimeout(applyState, 90);
});
searchInput.addEventListener("keydown", function (e) {
if (e.key === "Escape") {
searchInput.value = "";
currentQuery = "";
applyState();
}
});
}
/* ---------- Hover preview ---------- */
var preview = doc.querySelector(".preview");
var previewThumb = preview ? preview.querySelector("[data-thumb-target]") : null;
var previewLabel = preview ? preview.querySelector("[data-label-target]") : null;
var lastThumbClass = "";
function showPreview(entry, x, y) {
if (!preview || !previewThumb) return;
var thumbKey = entry.getAttribute("data-thumb");
var title = entry.getAttribute("data-title") || "";
if (lastThumbClass) previewThumb.classList.remove(lastThumbClass);
previewThumb.classList.remove("press-photo");
previewThumb.classList.add("press-photo");
lastThumbClass = "thumb-" + thumbKey;
previewThumb.classList.add(lastThumbClass);
if (previewLabel) previewLabel.textContent = title;
preview.hidden = false;
positionPreview(x, y);
}
function positionPreview(x, y) {
if (!preview || preview.hidden) return;
var w = preview.offsetWidth || 180;
var margin = 16;
var left = x + 20;
if (left + w + margin > window.innerWidth) {
left = x - w - 20;
}
if (left < margin) left = margin;
var top = Math.max(margin + 40, Math.min(y, window.innerHeight - margin));
preview.style.left = left + "px";
preview.style.top = top + "px";
}
function hidePreview() {
if (preview) preview.hidden = true;
}
entries.forEach(function (entry) {
entry.addEventListener("mouseenter", function (e) {
showPreview(entry, e.clientX, e.clientY);
});
entry.addEventListener("mousemove", function (e) {
positionPreview(e.clientX, e.clientY);
});
entry.addEventListener("mouseleave", hidePreview);
// Keyboard: open a "page" via Enter, with preview on focus
entry.addEventListener("focus", function () {
var rect = entry.getBoundingClientRect();
showPreview(entry, rect.right, rect.top + rect.height / 2);
});
entry.addEventListener("blur", hidePreview);
entry.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
var folio = entry.querySelector(".entry__folio");
var title = entry.getAttribute("data-title") || "this story";
toast("Turn to p. " + (folio ? folio.textContent : "—") + " — " + title);
}
});
entry.addEventListener("click", function () {
var folio = entry.querySelector(".entry__folio");
var title = entry.getAttribute("data-title") || "this story";
toast("Turn to p. " + (folio ? folio.textContent : "—") + " — " + title);
});
});
// Hide preview on scroll to avoid stale floating thumb
window.addEventListener("scroll", hidePreview, { passive: true });
/* ---------- Init ---------- */
applyState();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>The Meridian Review — Contents, Issue No. 214</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&family=Playfair+Display:ital,wght@0,500;0,600;0,700;0,800;0,900;1,500;1,600&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#contents">Skip to contents</a>
<div class="paper">
<!-- ===== ISSUE HEADER / MASTHEAD ===== -->
<header class="issue-head" role="banner">
<div class="issue-meta issue-meta--left">
<span class="issue-meta__no">Issue No. 214</span>
<span class="issue-meta__sep" aria-hidden="true">·</span>
<time datetime="2026-06">June 2026</time>
</div>
<a class="masthead" href="#" aria-label="The Meridian Review, home">
<span class="masthead__kicker">The</span>
<span class="masthead__name">Meridian Review</span>
<span class="masthead__rule" aria-hidden="true"></span>
<span class="masthead__tag">Reporting, essays & the long view</span>
</a>
<div class="issue-meta issue-meta--right">
<span class="issue-meta__theme">The Water Issue</span>
<span class="issue-meta__sep" aria-hidden="true">·</span>
<span>$9.00</span>
</div>
</header>
<div class="rule rule--thick" aria-hidden="true"></div>
<!-- ===== TOOLBAR: SEARCH + TABS ===== -->
<div class="toolbar" role="search">
<label class="search" for="toc-search">
<svg class="search__icon" viewBox="0 0 24 24" aria-hidden="true">
<circle cx="11" cy="11" r="7" fill="none" stroke="currentColor" stroke-width="2" />
<line x1="16.5" y1="16.5" x2="21" y2="21" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
<input
id="toc-search"
type="search"
placeholder="Search this issue…"
autocomplete="off"
aria-label="Search contents by title or contributor"
/>
</label>
<nav class="tabs" aria-label="Filter contents by section">
<button class="tab is-active" data-filter="all" aria-pressed="true">All</button>
<button class="tab" data-filter="features" aria-pressed="false">Features</button>
<button class="tab" data-filter="departments" aria-pressed="false">Departments</button>
<button class="tab" data-filter="columns" aria-pressed="false">Columns</button>
</nav>
</div>
<div class="rule" aria-hidden="true"></div>
<main id="contents" class="contents">
<!-- ===== COVER / FEATURED ENTRY ===== -->
<section class="cover-feature" data-section="features" aria-labelledby="cover-title">
<p class="kicker kicker--red">On the Cover</p>
<div class="cover-feature__grid">
<figure class="cover-feature__fig">
<div class="press-photo press-photo--cover" role="img"
aria-label="A reservoir at dawn, the waterline marked by a pale ring of exposed rock."></div>
<figcaption>
Lake Verano at first light, its waterline thirty feet below the old shore.
<span class="credit">Photograph — Daniela Ferreira</span>
</figcaption>
</figure>
<div class="cover-feature__body">
<span class="folio">p. 48</span>
<h2 id="cover-title" class="cover-feature__title">
The Year the River Ran Backward
</h2>
<p class="dek dek--lead">
<span class="dropcap">F</span>or a century the town of Verano measured its
fortunes by the river. Now the engineers measure something else — and the
people who stayed behind are learning a vocabulary nobody asked for: drawdown,
dead pool, the slow arithmetic of a basin that no longer fills. A dispatch from
the far edge of the drought.
</p>
<p class="byline">
By <strong>Marcus Halloran</strong>
<span class="byline__sep" aria-hidden="true">·</span>
Photographs by Daniela Ferreira
<span class="byline__sep" aria-hidden="true">·</span>
<span class="readtime">24 min read</span>
</p>
</div>
</div>
<blockquote class="pullquote">
<p>“You don’t notice a river leaving. You notice the silence where it used to be.”</p>
</blockquote>
</section>
<div class="rule rule--thick" aria-hidden="true"></div>
<!-- ===== LISTINGS ===== -->
<div class="listings">
<!-- FEATURES -->
<section class="block" data-section="features" aria-labelledby="sec-features">
<header class="block__head">
<h3 id="sec-features" class="block__title">Features</h3>
<span class="block__count" aria-hidden="true">04</span>
</header>
<ol class="entries">
<li class="entry" tabindex="0"
data-thumb="g1"
data-title="The Year the River Ran Backward">
<span class="entry__folio">48</span>
<div class="entry__main">
<h4 class="entry__title">The Year the River Ran Backward</h4>
<p class="entry__dek">A town learns to live in the negative space left by its vanished river.</p>
</div>
<span class="entry__author">Marcus Halloran</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g2"
data-title="The Plumbers of the Aquifer">
<span class="entry__folio">62</span>
<div class="entry__main">
<h4 class="entry__title">The Plumbers of the Aquifer</h4>
<p class="entry__dek">Underground, a quiet guild of hydrologists is rationing the water nobody can see.</p>
</div>
<span class="entry__author">Priya Anand</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g3"
data-title="Selling Rain">
<span class="entry__folio">74</span>
<div class="entry__main">
<h4 class="entry__title">Selling Rain</h4>
<p class="entry__dek">Inside the strange, lucrative business of cloud seeding — and the lawsuits it leaves behind.</p>
</div>
<span class="entry__author">Theo Brandt</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g4"
data-title="The Last Ferryman of Cole's Crossing">
<span class="entry__folio">86</span>
<div class="entry__main">
<h4 class="entry__title">The Last Ferryman of Cole’s Crossing</h4>
<p class="entry__dek">For forty years he rowed strangers across. The bridge took the river; the drought took the bridge.</p>
</div>
<span class="entry__author">Rosa Imani</span>
</li>
</ol>
</section>
<!-- DEPARTMENTS -->
<section class="block" data-section="departments" aria-labelledby="sec-departments">
<header class="block__head">
<h3 id="sec-departments" class="block__title">Departments</h3>
<span class="block__count" aria-hidden="true">05</span>
</header>
<ol class="entries">
<li class="entry" tabindex="0"
data-thumb="g5"
data-title="Dispatches">
<span class="entry__folio">09</span>
<div class="entry__main">
<h4 class="entry__title">Dispatches</h4>
<p class="entry__dek">Notes from the field: a desalination plant in Tarn, and the town that voted to disappear.</p>
</div>
<span class="entry__author">The Editors</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g6"
data-title="The Ledger">
<span class="entry__folio">14</span>
<div class="entry__main">
<h4 class="entry__title">The Ledger</h4>
<p class="entry__dek">What a gallon really costs in seven cities — and who is quietly paying the difference.</p>
</div>
<span class="entry__author">Naomi Frost</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g7"
data-title="Field Notes">
<span class="entry__folio">21</span>
<div class="entry__main">
<h4 class="entry__title">Field Notes</h4>
<p class="entry__dek">A botanist learns to read drought in the rings of a single olive tree.</p>
</div>
<span class="entry__author">Dr. Elias Vance</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g8"
data-title="The Table">
<span class="entry__folio">28</span>
<div class="entry__main">
<h4 class="entry__title">The Table</h4>
<p class="entry__dek">Cooking for a dry year: the dishes that ask the kitchen for almost nothing.</p>
</div>
<span class="entry__author">Camille Oduya</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g9"
data-title="Reviewed">
<span class="entry__folio">34</span>
<div class="entry__main">
<h4 class="entry__title">Reviewed</h4>
<p class="entry__dek">Three new books on rivers, ruin, and repair — and one that gets the hope right.</p>
</div>
<span class="entry__author">Jonah Reyes</span>
</li>
</ol>
</section>
<!-- COLUMNS -->
<section class="block" data-section="columns" aria-labelledby="sec-columns">
<header class="block__head">
<h3 id="sec-columns" class="block__title">Columns</h3>
<span class="block__count" aria-hidden="true">03</span>
</header>
<ol class="entries">
<li class="entry" tabindex="0"
data-thumb="g10"
data-title="The Common Good">
<span class="entry__folio">06</span>
<div class="entry__main">
<h4 class="entry__title">The Common Good</h4>
<p class="entry__dek">Water was the first thing we agreed to share. We may be the generation that forgets why.</p>
</div>
<span class="entry__author">Adaeze Okonkwo</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g11"
data-title="Margins">
<span class="entry__folio">42</span>
<div class="entry__main">
<h4 class="entry__title">Margins</h4>
<p class="entry__dek">On the maps that draw a basin and the politics that quietly redraw it.</p>
</div>
<span class="entry__author">Sam Castellanos</span>
</li>
<li class="entry" tabindex="0"
data-thumb="g12"
data-title="Last Word">
<span class="entry__folio">96</span>
<div class="entry__main">
<h4 class="entry__title">Last Word</h4>
<p class="entry__dek">A short, stubborn case for planting a tree you will never sit beneath.</p>
</div>
<span class="entry__author">Margaret Hsu</span>
</li>
</ol>
</section>
<p class="no-results" hidden role="status">
No entries match <span class="no-results__term"></span>.
</p>
</div>
<!-- ===== HOVER PREVIEW (floating thumbnail) ===== -->
<div class="preview" hidden aria-hidden="true">
<div class="preview__thumb" data-thumb-target></div>
<p class="preview__label" data-label-target></p>
</div>
</main>
<div class="rule rule--thick" aria-hidden="true"></div>
<!-- ===== CONTRIBUTORS STRIP ===== -->
<footer class="contributors" aria-labelledby="contrib-title">
<h3 id="contrib-title" class="contributors__title">Contributors</h3>
<ul class="contributors__list">
<li class="contributor">
<span class="contributor__avatar" data-initials="MH" aria-hidden="true">MH</span>
<p><strong>Marcus Halloran</strong> has written about water and the West for fifteen years. He lives downriver.</p>
</li>
<li class="contributor">
<span class="contributor__avatar" data-initials="DF" aria-hidden="true">DF</span>
<p><strong>Daniela Ferreira</strong> is a documentary photographer. This is her fourth issue for the Review.</p>
</li>
<li class="contributor">
<span class="contributor__avatar" data-initials="PA" aria-hidden="true">PA</span>
<p><strong>Priya Anand</strong> covers infrastructure and the people who keep it running, mostly unseen.</p>
</li>
<li class="contributor">
<span class="contributor__avatar" data-initials="AO" aria-hidden="true">AO</span>
<p><strong>Adaeze Okonkwo</strong> writes our column on the commons. She is at work on a book about shared things.</p>
</li>
</ul>
</footer>
<div class="rule" aria-hidden="true"></div>
<p class="colophon">
The Meridian Review · Issue No. 214 · Printed on paper that remembers water.
</p>
</div>
<div class="toast" role="status" aria-live="polite" hidden></div>
<script src="script.js"></script>
</body>
</html>Magazine Table of Contents
A complete front-of-book contents page for a fictional monthly, art-directed like real print. The masthead sets the issue number, date, theme, and cover price across a three-up header, then hands off to a cover feature: a 4:5 duotone “press photograph” beside an oversized Playfair headline, a drop-capped dek, a dateline byline with read time, and a centered serif pull quote. Below the thick rule, the issue is laid out in two newsprint columns and broken into Features, Departments, and Columns, each row carrying a red folio number, title, short dek, and contributor.
The page is quietly interactive. Section tabs filter the listings (and the cover) in place, an Escape-clearable search box matches titles, deks, and bylines as you type, and an empty state appears in italic serif when nothing matches. Hovering or keyboard-focusing any row raises a small floating thumbnail rendered entirely in CSS gradients, so the reader gets a glimpse of the “page” before turning to it. A contributors strip with monogram avatars closes the issue, and a toast confirms each navigation.
Everything is self-contained — two Google Fonts, semantic article/figure/figcaption markup, WCAG-AA contrast, full keyboard support, and a responsive grid that collapses to a single column on phones with no framework or build step.
Illustrative UI only — masthead, headlines, bylines, and articles are fictional; not a real news publication.