/* =============================================================================
   COLLECTION SECTIONS
   The vocabulary every collection route is assembled from. A collection is not
   a new design — it is the same tokens, the same cards and the same type scale
   arranged for a different subject — so the sections live here, once, and each
   collection adds only what is genuinely its own.

   Every value is a token. No hex, no px outside a hairline, no new primitive.

   `col-` is shared: travel, blog and anything after them use these.
   A collection's own extras take its name (`trv-`, `blg-`). Anything that
   turns out to be useful twice graduates the other way.

   Requires 1-foundation through 6-utilities.
   ========================================================================== */


/* ── The hero ────────────────────────────────────────────────────────────────
   A collection index has to say what the collection is before it starts
   listing. This one is a night sky with a globe in it and a flight arcing
   away — the picture does the saying, so the copy can be short.
   ------------------------------------------------------------------------- */

.col-hero {
	position: relative;
	overflow: hidden;
	background: var(--ink-1000);
	color: var(--ink-50);
	color-scheme: dark;
	border-radius: var(--radius-sheet, 1.5rem);
	isolation: isolate;
}

.col-hero__art {
	position: absolute;
	inset: 0;
	z-index: -1;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* A photograph is not a scrim. The drawn art is dark by construction, but the
   moment the art is a picture somebody uploaded, the headline is legible only
   over whichever half of it happens to be dark. This puts the contrast back
   without dimming the whole image. */
.col-hero:has(> img.col-hero__art)::before {
	content: '';
	position: absolute;
	inset: 0;
	/* Zero, not -1: two negative children paint in DOM order, and the art
	   comes second — a scrim behind it would be a scrim under the picture. */
	z-index: 0;
	background: linear-gradient(100deg,
		rgb(0 0 0 / 0.88) 0%,
		rgb(0 0 0 / 0.72) 42%,
		rgb(0 0 0 / 0.35) 78%,
		rgb(0 0 0 / 0.2) 100%);
}

.col-hero__in {
	position: relative;
	display: grid;
	gap: var(--space-6);
	padding: var(--section-md, var(--space-16)) var(--space-8);
	max-width: 46rem;
}

.col-hero__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: rgb(255 255 255 / 0.6);
}

.col-hero__title {
	font-family: var(--font-display);
	font-size: clamp(2.25rem, 1.4rem + 3.2vw, 3.75rem);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tighter);
	line-height: var(--leading-flat);
	text-wrap: balance;
	margin: 0;
}

.col-hero__title em { font-style: normal; color: var(--accent); }

.col-hero__lead {
	font-size: var(--text-lg);
	color: rgb(255 255 255 / 0.72);
	max-width: var(--measure-lead);
	margin: 0;
}

/* ── Search and the call ─────────────────────────────────────────────────────
   One field and one button. A collection index is a place people arrive at
   knowing roughly what they want, so search leads and browsing follows.
   ------------------------------------------------------------------------- */

.col-search {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	align-items: center;
}

.col-search__field {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	flex: 1 1 18rem;
	min-width: 0;
	height: var(--control-md, 2.75rem);
	padding-inline: var(--space-4);
	border: var(--border-hair) solid rgb(255 255 255 / 0.18);
	border-radius: var(--radius-pill);
	background: rgb(255 255 255 / 0.08);
	backdrop-filter: blur(8px);
	transition: var(--t-colors);
}

.col-search__field:focus-within {
	border-color: var(--accent);
	background: rgb(255 255 255 / 0.12);
}

.col-search__field .icon { width: 1.1rem; height: 1.1rem; opacity: 0.6; flex: none; }

.col-search__field input {
	flex: 1;
	min-width: 0;
	border: 0;
	background: none;
	color: inherit;
	font: inherit;
	font-size: var(--text-sm);
}

.col-search__field input::placeholder { color: rgb(255 255 255 / 0.45); }
.col-search__field input:focus { outline: none; }

/* ── The meta strip ──────────────────────────────────────────────────────────
   The numbers that tell you the size of what you are looking at. Under the
   hero, because "how much is here" is the second question after "what is it".
   ------------------------------------------------------------------------- */

.col-meta {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
	gap: var(--space-4) var(--space-6);
	padding-top: var(--space-6);
	border-top: var(--border-hair) solid rgb(255 255 255 / 0.14);
}

.col-meta__n {
	display: block;
	font-family: var(--font-display);
	font-size: var(--text-2xl);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tight);
	font-variant-numeric: tabular-nums;
}

.col-meta__l {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: rgb(255 255 255 / 0.55);
}

/* On a light surface the strip inverts with everything else. */
.col-meta-paper { border-top-color: var(--line-default); }
.col-meta-paper .col-meta__l { color: var(--fg-faint); }

/* One row, always — for a hero's stat strip beside a CTA, where wrapping to
   a second row reads as a layout accident rather than a design. */
.col-meta-inline {
	display: flex;
	flex-wrap: nowrap;
	justify-content: flex-start;
	gap: var(--space-6);
	overflow-x: auto;
}

/* ── Groups — the regions ────────────────────────────────────────────────────
   The widest cut through the collection, so it comes first and stays small:
   an icon, a name, a count. Anything more and it competes with the places.
   ------------------------------------------------------------------------- */

.col-groups {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
	gap: var(--space-4);
}

.col-group {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	padding: var(--space-4);
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-surface);
	color: var(--fg-default);
	text-decoration: none;
	transition: var(--t-colors), var(--t-transform);
	cursor: pointer;
	text-align: left;
	font: inherit;
	width: 100%;
}

.col-group:hover {
	border-color: var(--line-strong);
	background: var(--bg-sunken);
}

.col-group__ico {
	display: inline-grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	flex: none;
	border-radius: var(--radius-md);
	background: var(--bg-sunken);
	color: var(--fg-subtle);
	transition: var(--t-colors);
}

.col-group__ico .icon { width: 1.35rem; height: 1.35rem; }
.col-group:hover .col-group__ico { background: var(--accent-soft); color: var(--accent-soft-fg); }

.col-group__name { display: block; font-weight: var(--weight-semibold); }

.col-group__n {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

/* Selected — the accent marks the filter that is doing something. */
.col-group[aria-pressed='true'] {
	border-color: var(--accent);
	background: var(--accent-soft);
}

.col-group[aria-pressed='true'] .col-group__ico {
	background: var(--accent);
	color: var(--fg-on-accent, #fff);
}

/* ── Places — the countries ──────────────────────────────────────────────────
   A picture, a name, a sentence. This is a .card with a travel-shaped body,
   not a new component: the media, the title and the excerpt are the same
   three parts every collection card has.
   ------------------------------------------------------------------------- */

.col-places {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
	gap: var(--space-5);
}

.col-place {
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-surface);
	text-decoration: none;
	color: var(--fg-default);
	transition: var(--t-colors), var(--t-shadow);
	cursor: pointer;
	text-align: left;
	font: inherit;
	padding: 0;
}

.col-place:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); }

.col-place__media {
	position: relative;
	aspect-ratio: 4 / 3;
	background: var(--bg-media, var(--ink-900));
	overflow: hidden;
}

/* The picture fills the box — but NOT the chip riding on top of it, which is
   absolutely positioned and would be stretched to the full 100%/100% into a
   pill the size of the card. */
.col-place__media > :not(.col-place__tag) {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform var(--dur-4) var(--ease-out);
}

.col-place:hover .col-place__media > :not(.col-place__tag) { transform: scale(1.03); }

/* The flag chip rides the corner, so the picture never has to carry the name. */
.col-place__tag {
	position: absolute;
	left: var(--space-3);
	bottom: var(--space-3);
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding: 3px var(--space-3);
	border-radius: var(--radius-pill);
	background: rgb(0 0 0 / 0.55);
	backdrop-filter: blur(6px);
	color: #fff;
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
}

.col-place__body { padding: var(--space-4); display: grid; gap: var(--space-2); }

.col-place__name {
	display: block;
	font-family: var(--font-display);
	font-size: var(--text-lg);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tight);
}

.col-place__note {
	display: block;
	font-size: var(--text-sm);
	color: var(--fg-subtle);
	line-height: var(--leading-snug, 1.4);
}

.col-place__foot {
	margin-top: auto;
	padding: var(--space-3) var(--space-4);
	border-top: var(--border-hair) solid var(--line-subtle);
	display: flex;
	flex-wrap: nowrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

/* The count+duration text and the level chip share one row on purpose — a
   card's footer is the one place both facts belong side by side. Neither is
   allowed to wrap into a second line; the text ellipses before that happens. */
.col-place__foot > span:first-child {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	min-width: 0;
}

.col-place__foot > .crs-level { flex: none; }

.col-place[aria-pressed='true'] { border-color: var(--accent); box-shadow: var(--shadow-2); }

/* ── Spots — the cities ──────────────────────────────────────────────────────
   The narrowest cut, so the smallest shape: a chip. Dozens of these can sit
   in a row without the page becoming a grid of pictures nobody reads.
   ------------------------------------------------------------------------- */

.col-spots { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.col-spot {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-2) var(--space-4);
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-pill);
	background: var(--bg-surface);
	color: var(--fg-default);
	font-size: var(--text-sm);
	text-decoration: none;
	transition: var(--t-colors);
}

.col-spot:hover { border-color: var(--line-strong); background: var(--bg-sunken); }

.col-spot__n {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
}

.col-spot[aria-current] {
	border-color: var(--accent);
	background: var(--accent-soft);
	color: var(--accent-soft-fg);
}

/* Nothing matched. Says so, rather than leaving a hole. */
.col-empty {
	padding: var(--space-6);
	border: var(--border-hair) dashed var(--line-default);
	border-radius: var(--radius-card);
	text-align: center;
	color: var(--fg-faint);
	font-size: var(--text-sm);
}

/* ── The facet sidebar ───────────────────────────────────────────────────────
   Destination type — beach, mountains, party. Checkboxes, because more than
   one can be true at once, and a native input so the keyboard works.
   ------------------------------------------------------------------------- */

.col-layout {
	display: grid;
	gap: var(--space-8);
	align-items: start;
}

@media (min-width: 64rem) {
	.col-layout { grid-template-columns: 15rem minmax(0, 1fr); }
	.col-layout__side { position: sticky; top: var(--space-6); }
}

.col-facets { display: grid; gap: var(--space-5); }

.col-facets__group { display: grid; gap: var(--space-2); }

.col-facets__title {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
	padding-bottom: var(--space-2);
	border-bottom: var(--border-hair) solid var(--line-subtle);
}

.col-facet {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-2);
	border-radius: var(--radius-sm);
	font-size: var(--text-sm);
	color: var(--fg-muted);
	cursor: pointer;
	transition: var(--t-colors);
}

.col-facet:hover { background: var(--bg-sunken); color: var(--fg-default); }
.col-facet input { accent-color: var(--accent); flex: none; }
.col-facet .icon { width: 1rem; height: 1rem; opacity: 0.55; flex: none; }
.col-facet__n { margin-left: auto; font-family: var(--font-slate); font-size: var(--text-2xs); color: var(--fg-faint); }
.col-facet:has(input:checked) { color: var(--fg-default); }
.col-facet:has(input:checked) .icon { opacity: 1; color: var(--accent); }

/* ── A series — the trip ─────────────────────────────────────────────────────
   A trip is an ordered body of work, so its card shows the shape of the whole
   thing: how many parts, over how long, and where it went.
   ------------------------------------------------------------------------- */

.col-series {
	display: grid;
	gap: 0;
	overflow: hidden;
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-surface);
	text-decoration: none;
	color: inherit;
}

@media (min-width: 48rem) {
	.col-series { grid-template-columns: 1.15fr 1fr; }
}

.col-series__media {
	position: relative;
	min-height: 14rem;
	background: var(--bg-media, var(--ink-900));
	overflow: hidden;
}

.col-series__media > * { width: 100%; height: 100%; object-fit: cover; display: block; }

.col-series__body { padding: var(--space-6); display: grid; gap: var(--space-4); align-content: center; }

.col-series__title {
	display: block;
	font-family: var(--font-display);
	font-size: var(--text-2xl);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tight);
	line-height: var(--leading-snug, 1.25);
	text-wrap: balance;
}

.col-series__stats {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-4);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

.col-series__stats > span { display: inline-flex; align-items: center; gap: var(--space-2); }
.col-series__stats .icon { width: 0.9rem; height: 0.9rem; }

/* ── The order — a trip, laid out ────────────────────────────────────────────
   The series route's spine. A rule runs down the left and every part hangs off
   it, because the one thing a series has that a group does not is sequence.
   ------------------------------------------------------------------------- */

.col-order { display: grid; gap: 0; position: relative; }

.col-order__item {
	display: grid;
	grid-template-columns: 3rem minmax(0, 1fr);
	gap: var(--space-5);
	padding-block: var(--space-5);
	border-bottom: var(--border-hair) solid var(--line-subtle);
	text-decoration: none;
	color: inherit;
	transition: var(--t-colors);
}

.col-order__item:last-child { border-bottom: 0; }
.col-order__item:hover { background: var(--bg-sunken); }

.col-order__num {
	position: relative;
	display: grid;
	place-items: start center;
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
}

/* The spine. It stops at the last item rather than trailing into nothing. */
.col-order__num::before {
	content: '';
	position: absolute;
	top: 1.6rem;
	bottom: calc(var(--space-5) * -1 - 1.2rem);
	width: var(--border-hair);
	background: var(--line-default);
}

.col-order__item:last-child .col-order__num::before { display: none; }

.col-order__dot {
	width: 0.55rem;
	height: 0.55rem;
	border-radius: var(--radius-full);
	background: var(--line-strong);
	margin-bottom: var(--space-2);
	position: relative;
	z-index: 1;
}

.col-order__item[aria-current] .col-order__dot { background: var(--accent); }
.col-order__item[aria-current] .col-order__title { color: var(--accent); }

.col-order__body { display: grid; gap: var(--space-2); }

.col-order__title {
	display: block;
	font-family: var(--font-display);
	font-size: var(--text-lg);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tight);
}

.col-order__note { display: block; font-size: var(--text-sm); color: var(--fg-subtle); }

.col-order__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

/* ── Post rows ───────────────────────────────────────────────────────────────
   The list every route ends with. A row rather than a card, because by this
   point the reader is scanning titles, not looking at pictures.
   ------------------------------------------------------------------------- */

.col-posts { display: grid; }

.col-post-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--space-2);
	padding-block: var(--space-5);
	border-bottom: var(--border-hair) solid var(--line-subtle);
	text-decoration: none;
	color: inherit;
	transition: var(--t-colors);
}

@media (min-width: 40rem) {
	.col-post-row { grid-template-columns: 7rem minmax(0, 1fr) auto; gap: var(--space-5); align-items: center; }
}

.col-post-row:hover { background: var(--bg-sunken); }

.col-post-row__thumb {
	aspect-ratio: 4 / 3;
	border-radius: var(--radius-md);
	overflow: hidden;
	background: var(--bg-media, var(--ink-900));
}

.col-post-row__thumb > * { width: 100%; height: 100%; object-fit: cover; display: block; min-height: 0; }

.col-post-row__body { display: grid; gap: 2px; min-width: 0; }

.col-post-row__title {
	display: block;
	font-family: var(--font-display);
	font-size: var(--text-lg);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tight);
	text-wrap: balance;
}

.col-post-row__note { display: block; font-size: var(--text-sm); color: var(--fg-subtle); }

.col-post-row__meta {
	display: flex;
	gap: var(--space-3);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
	white-space: nowrap;
}

/* ── The post route ──────────────────────────────────────────────────────── */

.col-post {
	display: grid;
	gap: var(--space-8);
	align-items: start;
}

@media (min-width: 64rem) {
	.col-post { grid-template-columns: minmax(0, 1fr) 15rem; }
	.col-post__rail { position: sticky; top: var(--space-6); }
}

.col-post__head { display: grid; gap: var(--space-4); margin-bottom: var(--space-8); }

.col-post__crumbs {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

.col-post__crumbs a { color: inherit; text-decoration: none; }
.col-post__crumbs a:hover { color: var(--fg-default); }

.col-post__rail-card {
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-surface);
	padding: var(--space-5);
	display: grid;
	gap: var(--space-3);
}

/* ── Next in series ──────────────────────────────────────────────────────── */

.col-next {
	display: grid;
	gap: var(--space-4);
	padding: var(--space-6);
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-sunken);
	text-decoration: none;
	color: inherit;
	transition: var(--t-colors);
}

.col-next:hover { border-color: var(--accent); }

.col-next__label {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

/* ── Filtering ───────────────────────────────────────────────────────────────
   Hidden by attribute rather than by class, so the JavaScript sets one thing
   and the CSS decides what that means.
   ------------------------------------------------------------------------- */

[data-filtered='out'] { display: none; }

/* ── Placeholders ────────────────────────────────────────────────────────────
   Stand-in art. A demo that ships with stock photography teaches the wrong
   lesson — that the design needs a good photograph to work. Each place gets a
   hue off one ladder so the grid still reads as a set, and nothing can 404.
   ------------------------------------------------------------------------- */

.col-ph {
	display: block;
	width: 100%;
	height: 100%;
	min-height: 8rem;
	background:
		linear-gradient(200deg,
			hsl(var(--h, 220) 42% 46%) 0%,
			hsl(var(--h, 220) 40% 30%) 45%,
			hsl(var(--h, 220) 46% 14%) 100%),
		hsl(var(--h, 220) 40% 24%);
	transition: transform var(--dur-4) var(--ease-out);
}

.col-ph[data-tall] { min-height: 16rem; }

/* ── Widgets ─────────────────────────────────────────────────────────────────
   The rail beside a post. Every widget is the same object — a label, a body,
   sometimes a footer — so a rail of six of them reads as one column rather
   than six competing boxes. A blog needs them most, but a course rail and a
   trip rail want exactly the same shape, so they live here.
   ------------------------------------------------------------------------- */

.col-rail { display: grid; gap: var(--space-5); align-content: start; }

@media (min-width: 64rem) {
	/* Below the floating island, not behind it — the nav is itself sticky at
	   top: space-3, so a rail stuck at the same offset sits under its shadow.
	   Derived from --nav-gap (24-nav.css) so the clearance under the island is
	   the same number everywhere rather than three approximations of it. */
	.col-rail-sticky {
		position: sticky;
		top: calc(var(--nav-h) + var(--space-3) + var(--nav-gap));
	}

	/* A sticky rail TALLER than the viewport has its bottom cut off and
	   unreachable: the page cannot scroll it, because the rail is not moving.
	   This lets it scroll itself, so a rail carrying a long list — a build log,
	   a chapter list — stays sticky without losing its own end.

	   Opt-in rather than folded into .col-rail-sticky because the overflow
	   clips shadows, which is only worth paying for when the rail is long. */
	.col-rail-scroll {
		max-height: calc(100dvh - var(--nav-h) - var(--space-3) - var(--nav-gap) - var(--space-6));
		overflow-y: auto;
		overscroll-behavior-y: contain;
		scrollbar-width: thin;
		/* Room for the scrollbar and for the widgets' own shadows. */
		padding-right: var(--space-2);
		margin-right: calc(-1 * var(--space-2));
	}
}

.col-widget {
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-surface);
	padding: var(--space-5);
	display: grid;
	gap: var(--space-3);
}

.col-widget__title {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
	padding-bottom: var(--space-3);
	border-bottom: var(--border-hair) solid var(--line-subtle);
}

.col-widget__foot {
	padding-top: var(--space-3);
	border-top: var(--border-hair) solid var(--line-subtle);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

/* A widget that is the point of the page rather than a note beside it. */
.col-widget-accent {
	border-color: var(--accent);
	background: var(--accent-soft);
	color: var(--accent-soft-fg);
}

.col-widget-accent .col-widget__title { color: inherit; opacity: 0.7; border-bottom-color: currentcolor; }

/* Author — the one widget with a face in it. */
.col-author { display: flex; align-items: center; gap: var(--space-4); }

.col-author__face {
	width: 3rem;
	height: 3rem;
	flex: none;
	border-radius: var(--radius-full);
	overflow: hidden;
	background: var(--bg-sunken);
}

.col-author__face > * { width: 100%; height: 100%; object-fit: cover; display: block; min-height: 0; }
.col-author__name { display: block; font-weight: var(--weight-semibold); }

.col-author__who {
	display: block;
	font-size: var(--text-sm);
	color: var(--fg-subtle);
}

/* A numbered list of posts — recent, popular, next. Numbers rather than
   bullets, because the order in these lists is the information. */
.col-mini { display: grid; gap: var(--space-1); }

.col-mini__item {
	display: grid;
	grid-template-columns: 1.5rem minmax(0, 1fr);
	gap: var(--space-3);
	padding: var(--space-2);
	margin-inline: calc(var(--space-2) * -1);
	border-radius: var(--radius-sm);
	text-decoration: none;
	color: inherit;
	transition: var(--t-colors);
}

.col-mini__item:hover { background: var(--bg-sunken); }

.col-mini__n {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
	padding-top: 2px;
}

.col-mini__title {
	display: block;
	font-size: var(--text-sm);
	font-weight: var(--weight-medium);
	line-height: var(--leading-snug, 1.35);
}

.col-mini__meta {
	display: block;
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	margin-top: 2px;
}

/* Tag cloud. Weight carries the count, so the shape of the cloud is the data. */
.col-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.col-tag {
	display: inline-flex;
	align-items: baseline;
	gap: var(--space-2);
	padding: 3px var(--space-3);
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-pill);
	font-size: var(--text-xs);
	color: var(--fg-muted);
	text-decoration: none;
	transition: var(--t-colors);
}

.col-tag:hover { border-color: var(--line-strong); color: var(--fg-default); }
.col-tag__n { font-family: var(--font-slate); font-size: var(--text-2xs); color: var(--fg-faint); }
.col-tag[aria-current] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-soft-fg); }

/* The subscribe widget. One field, one button, one promise. */
.col-sub__form { display: grid; gap: var(--space-2); }

.col-sub__form input {
	width: 100%;
	height: var(--control-sm);
	padding-inline: var(--space-3);
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-md);
	background: var(--bg-canvas);
	color: inherit;
	font: inherit;
	font-size: var(--text-sm);
}

.col-sub__form input:focus-visible { outline: var(--border-2) solid var(--accent); outline-offset: 1px; }

/* Reading progress for a long post — the same idea as the navbar's hairline. */
.col-progress {
	position: sticky;
	top: 0;
	height: var(--border-2);
	background: var(--line-subtle);
	z-index: var(--z-nav);
}

.col-progress__bar {
	height: 100%;
	width: var(--value, 0%);
	background: var(--accent);
	transition: width var(--dur-2) linear;
}

/* A contents list that knows where the reader is. */
.col-toc { display: grid; gap: 1px; }

.col-toc a {
	font-size: var(--text-sm);
	color: var(--fg-subtle);
	text-decoration: none;
	padding: 4px var(--space-3);
	border-left: var(--border-hair) solid var(--line-subtle);
	transition: var(--t-colors);
	line-height: var(--leading-snug, 1.35);
}

.col-toc a:hover { color: var(--fg-default); border-left-color: var(--line-strong); }

.col-toc a[aria-current] {
	color: var(--fg-default);
	font-weight: var(--weight-medium);
	border-left-color: var(--accent);
}

/* ── The stage ───────────────────────────────────────────────────────────────
   A post whose body is a video rather than prose. The media leads and the rest
   of the series sits beside it, because the second question after "play this"
   is always "what is after it".

   Course was the collection that needed this first, but nothing here knows
   about courses: a podcast season, a video series and a live archive all want
   a player with the rest of the run next to it.
   ------------------------------------------------------------------------- */

.col-stage {
	display: grid;
	gap: var(--space-6);
	align-items: start;
}

@media (min-width: 68rem) {
	.col-stage { grid-template-columns: minmax(0, 1fr) 22rem; }
	.col-stage__side { position: sticky; top: calc(var(--nav-h) + var(--space-6)); }
}

.col-stage__main { display: grid; gap: var(--space-4); min-width: 0; }

/* The frame is the system's .player. This only says how it sits in the stage:
   corners off at narrow widths, because a video pinned to both gutters reads
   as the page rather than as an object on it. */
.col-stage .player { border-radius: var(--radius-card); overflow: hidden; }

@media (max-width: 40rem) {
	.col-stage .player { border-radius: 0; margin-inline: calc(var(--gutter) * -1); }
}

/* ── The stage bar ───────────────────────────────────────────────────────────
   Under the player: where you are, and the two ways out of it. Previous and
   next are the whole navigation of an ordered collection, so they get the
   width and everything else gets out of the way.
   ------------------------------------------------------------------------- */

.col-stagebar {
	display: grid;
	gap: var(--space-3);
	grid-template-columns: minmax(0, 1fr);
	padding: var(--space-4) 0;
	border-bottom: var(--border-hair) solid var(--line-subtle);
}

@media (min-width: 48rem) {
	.col-stagebar { grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-5); }
}

.col-stagebar__where { display: grid; gap: var(--space-2); min-width: 0; }

.col-stagebar__pos {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
}

/* A disabled step is still in the layout — the first lesson has no previous,
   and the bar must not change shape between lessons because of it. */
.col-stagebar .btn[aria-disabled='true'] { opacity: 0.45; pointer-events: none; }

/* ── The playlist ────────────────────────────────────────────────────────────
   The syllabus, beside a player. It IS `.curriculum` — the same modules, the
   same lesson rows, the same tick — because a course's contents list should
   not become a different component the moment it moves next to a video. All
   this adds is a body that scrolls, since it now has to fit beside something
   rather than run the width of a page.
   ------------------------------------------------------------------------- */

.col-playlist { display: flex; flex-direction: column; max-height: 34rem; }
.col-playlist__scroll { overflow-y: auto; overscroll-behavior: contain; min-height: 0; }

.col-playlist__foot {
	flex: none;
	padding: var(--space-3) var(--space-5);
	border-top: var(--border-hair) solid var(--line-default);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
	display: flex;
	justify-content: space-between;
	gap: var(--space-3);
}

/* Locked — the lesson exists and is named, which is the point of showing it.
   Dimmed rather than hidden: hiding it would misdescribe the course. */
.col-lock {
	display: inline-grid;
	place-items: center;
	width: 1rem;
	height: 1rem;
	flex: none;
	color: var(--fg-faint);
}

.col-lock .icon { width: 0.9rem; height: 0.9rem; }
.lesson-row[data-locked] { color: var(--fg-faint); }
.lesson-row[data-locked] .lesson-row__tick { border-style: dashed; }

/* ── Panels ──────────────────────────────────────────────────────────────────
   The tabs under a player: overview, transcript, resources, notes. They are
   the system's `.tabs`; this is only the panel beneath them.

   With the script blocked every panel shows, stacked, each under its own
   heading — which is the honest fallback for four blocks of content that all
   belong to the lesson. The script sets `data-tabs="ready"`, and only then
   does the stylesheet start hiding the headings and the inactive panels.
   ------------------------------------------------------------------------- */

.col-panel { padding-top: var(--space-6); }

.col-panel__label {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
	display: block;
	margin-bottom: var(--space-4);
}

[data-tabs='ready'] .col-panel__label { display: none; }

/* ── The transcript ──────────────────────────────────────────────────────────
   Timestamps down the left, so the column of times is scannable and the line
   the player is on can be marked without the text moving.
   ------------------------------------------------------------------------- */

.col-transcript {
	display: grid;
	gap: 1px;
	max-height: 24rem;
	overflow-y: auto;
	overscroll-behavior: contain;
}

.col-transcript__line {
	display: grid;
	grid-template-columns: 3.5rem minmax(0, 1fr);
	gap: var(--space-4);
	padding: var(--space-2) var(--space-3);
	border-radius: var(--radius-sm);
	text-decoration: none;
	color: var(--fg-muted);
	font-size: var(--text-sm);
	line-height: var(--leading-snug, 1.45);
	transition: var(--t-colors);
}

.col-transcript__line:hover { background: var(--bg-sunken); color: var(--fg-default); }

.col-transcript__time {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
	padding-top: 3px;
}

.col-transcript__line[aria-current] {
	background: var(--accent-soft);
	color: var(--accent-soft-fg);
}

.col-transcript__line[aria-current] .col-transcript__time { color: inherit; opacity: 0.7; }

/* ── Outcomes ────────────────────────────────────────────────────────────────
   What you will be able to do afterwards. Two columns of ticked lines, because
   a promise reads as a promise in a list and as marketing in a paragraph.
   ------------------------------------------------------------------------- */

.col-checks {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
	gap: var(--space-3) var(--space-8);
}

.col-check {
	display: grid;
	grid-template-columns: 1.15rem minmax(0, 1fr);
	gap: var(--space-3);
	font-size: var(--text-sm);
	color: var(--fg-muted);
	line-height: var(--leading-snug, 1.45);
}

.col-check__tick {
	width: 1.15rem;
	height: 1.15rem;
	border-radius: var(--radius-full);
	background: var(--accent-soft);
	color: var(--accent-soft-fg);
	display: grid;
	place-items: center;
	margin-top: 1px;
}

.col-check__tick .icon { width: 0.75rem; height: 0.75rem; }

/* ── The offer ───────────────────────────────────────────────────────────────
   The one card on the page that is asking for something. It is a widget, so it
   sits in a rail with the others — but it carries the accent, because there is
   exactly one thing to do here and pretending otherwise helps nobody.
   ------------------------------------------------------------------------- */

.col-offer { display: grid; gap: var(--space-4); }

.col-offer__price { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-3); }

.col-offer__now {
	font-family: var(--font-display);
	font-size: var(--text-3xl);
	font-weight: var(--weight-bold);
	letter-spacing: var(--tracking-tight);
	line-height: var(--leading-flat);
}

.col-offer__was { color: var(--fg-faint); text-decoration: line-through; }

.col-offer__list { display: grid; gap: var(--space-2); font-size: var(--text-sm); }

.col-offer__list > * {
	display: grid;
	grid-template-columns: 1rem minmax(0, 1fr);
	gap: var(--space-3);
	color: var(--fg-muted);
}

.col-offer__list .icon { width: 1rem; height: 1rem; color: var(--fg-faint); margin-top: 2px; }

/* ── Files ───────────────────────────────────────────────────────────────────
   What comes with the thing: the starter files, the slides, the transcript.
   Rows, because a download is an action and actions read as a list.
   ------------------------------------------------------------------------- */

.col-files { display: grid; }

.col-file {
	display: grid;
	grid-template-columns: 2.5rem minmax(0, 1fr) auto;
	gap: var(--space-4);
	align-items: center;
	padding: var(--space-3) 0;
	border-bottom: var(--border-hair) solid var(--line-subtle);
	text-decoration: none;
	color: inherit;
	transition: var(--t-colors);
}

.col-file:last-child { border-bottom: 0; }
.col-file:hover { background: var(--bg-sunken); }

.col-file__ext {
	display: grid;
	place-items: center;
	height: 2.5rem;
	border-radius: var(--radius-md);
	background: var(--bg-sunken);
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-subtle);
}

.col-file__name { display: block; font-size: var(--text-sm); font-weight: var(--weight-medium); }
.col-file__note { display: block; font-size: var(--text-xs); color: var(--fg-faint); }

.col-file__size {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/* ── Keys ────────────────────────────────────────────────────────────────────
   A player has shortcuts whether or not it advertises them. Advertising them
   is cheaper than a help page and it uses the `.kbd` element the system
   already has.
   ------------------------------------------------------------------------- */

.col-keys { display: grid; gap: var(--space-2); }

.col-key {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-4);
	font-size: var(--text-sm);
	color: var(--fg-muted);
}

.col-key__combo { display: flex; gap: var(--space-1); flex: none; }

/* ── Notes ───────────────────────────────────────────────────────────────────
   A box beside the player that keeps nothing. It is here because the shape of
   the page is wrong without it — the reader has somewhere to put a thought —
   and because a textarea in a rail is a component either way.
   ------------------------------------------------------------------------- */

.col-note { display: grid; gap: var(--space-3); }

.col-note textarea {
	min-height: 6rem;
	resize: vertical;
	font-size: var(--text-sm);
	line-height: var(--leading-snug, 1.5);
}

.col-note__foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
}

.col-note__stamp {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	color: var(--fg-faint);
	font-variant-numeric: tabular-nums;
}

/* ── Resume ──────────────────────────────────────────────────────────────────
   The strip at the top of an index for someone who has been here before. It
   outranks the hero's call to action, because "carry on" beats "start" for
   everyone it applies to and is invisible to everyone it does not.
   ------------------------------------------------------------------------- */

.col-resume {
	display: grid;
	gap: var(--space-4);
	align-items: center;
	padding: var(--space-4);
	border: var(--border-hair) solid var(--line-default);
	border-radius: var(--radius-card);
	background: var(--bg-surface);
	text-decoration: none;
	color: inherit;
	transition: var(--t-colors);
}

@media (min-width: 48rem) {
	.col-resume { grid-template-columns: 9rem minmax(0, 1fr) auto; gap: var(--space-5); }
}

.col-resume:hover { border-color: var(--accent); }

.col-resume__thumb {
	position: relative;
	aspect-ratio: var(--ratio-video, 16 / 9);
	border-radius: var(--radius-md);
	overflow: hidden;
	background: var(--bg-media, var(--ink-900));
}

.col-resume__thumb > * { width: 100%; height: 100%; object-fit: cover; display: block; min-height: 0; }

.col-resume__body { display: grid; gap: var(--space-2); min-width: 0; }

.col-resume__label {
	font-family: var(--font-slate);
	font-size: var(--text-2xs);
	letter-spacing: var(--tracking-slate);
	text-transform: uppercase;
	color: var(--fg-faint);
}

.col-resume__title {
	font-family: var(--font-display);
	font-size: var(--text-lg);
	font-weight: var(--weight-semibold);
	letter-spacing: var(--tracking-tight);
}
