/* plugpress.co — sections. v5 "WP desktop": painting wallpapers, floating
   windows, dotted hairlines, banded rhythm. One artwork per page, one accent
   per screen. */

/* ---------- desktop hero — flat paper, painting matted behind the mock ----------
   The painting is NOT the page backdrop (cursor.com's pattern): hero text sits
   on plain --bg, and the artwork is contained to the stage as the desk the
   windows rest on. Text therefore never needs a scrim to stay legible, and the
   product's own UI — not the painting — is the hero image. */
.desktop {
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	background-color: var(--bg);
	padding-bottom: var(--space-section);
}
.desktop > * { position: relative; }

/* a link sitting inside muted prose can't be distinguished by colour alone
   (blue on --ink-soft is 1.2:1 — WCAG wants 3:1 or a non-colour cue) */
.hero__sub a { text-decoration: underline; text-underline-offset: 3px; }

/* 404 founder scrawl */
.error404 .scrawl {
	font-family: var(--font-hand);
	font-size: var(--text-h3);
	color: var(--ink-soft);
	rotate: -2deg;
	display: inline-block;
	margin-top: var(--space-4);
}

.desktop__intro {
	text-align: center;
	color: var(--ink);
	padding: var(--space-hero) clamp(1.25rem, 4vw, 2rem) 0;
}
.desktop__wordmark {
	font-family: var(--font-display);
	font-weight: 800;
	font-size: var(--text-display);
	line-height: 0.95;
	letter-spacing: -0.03em;
	margin: 0 0 var(--space-3);
	text-transform: lowercase; /* the wordmark is the logo — always lowercase */
}
.desktop__sub {
	font-size: 1.25rem; /* 20px / 400 / 1.5 — Fahim's spec, the classic hero-sub setting */
	font-weight: 400;
	line-height: 1.5;
	margin: 0 auto var(--space-6);
	max-width: 36em;
	color: var(--ink-soft);
}
.desktop__intro .btn-row { justify-content: center; }

/* the brand NAME lives here now that the header logo is icon-only — a chip,
   not a bare label: the border+bg anchor it (heyclicky's own eyebrow trick) */
.desktop__brand-chip {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	padding: 4px 12px;
	border: 1px solid var(--line);
	border-radius: 999px;
	background: var(--surface);
	font-size: var(--text-mono);
	font-weight: 600;
	color: var(--ink);
	margin-bottom: var(--space-4);
}

/* real headline (the logo lives in the header only) — size = --text-h1, same as every page hero */
.desktop__headline {
	font-weight: 700;
	max-width: 15em;
	margin-inline: auto;
	margin-bottom: var(--space-5); /* display line gets more air than eyebrow→headline (16px) */
}

/* the stage IS the desk — it carries the painting, clipped to a panel at the
   references' measured ratio (cursor's hero panel: 1300×720, aspect ~1.8; the
   old clamp(520px, 62vh, 640px) letterboxed at 2.38). padding is the visible
   mat around the windows. */
.desktop__stage {
	position: relative;
	width: 100%;
	max-width: var(--container-wide);
	margin-inline: auto;
	margin-top: var(--space-hero);
	min-height: clamp(560px, 48vw, 700px);
	padding: clamp(1.5rem, 3vw, 2.75rem) clamp(1.25rem, 4vw, 3rem);
	background-size: cover;
	background-position: center;
	background-color: var(--band); /* fallback until the painting loads */
	border-radius: var(--r-canvas);
	overflow: hidden;
}
/* the painting reads UNWASHED — cursor's does, and no text sits on it (§14.3
   moved the hero copy to flat paper). The 28% veil this replaced turned out to
   be broken CSS that never applied, so unwashed is also what every reviewed
   screenshot actually showed. */

/* konami egg: ↑↑↓↓←→←→BA — with no veil left to lift, vivid mode now leans on
   the paintings themselves (site.js toggles the class + console line) */
.pp-vivid .desktop__stage { filter: saturate(1.3) contrast(1.05); }
/* captions sit ON the painting, whose brightness varies region to region —
   so they carry their own paper chip rather than relying on the backdrop. */
.desktop__stage .admin-frame__caption {
	color: var(--ink);
	display: inline-block;
	padding: 2px 10px;
	border-radius: 999px;
	background: color-mix(in srgb, var(--bg) 88%, transparent);
}

/* three windows for three plugins — saddle leads at ~66% of the stage;
   waggle/loggle overlap IN FRONT of its edges (Fahim: the side mocks sit
   above the saddle mock — desk scatter, not tuck-behind). */
.desktop__win { position: absolute; z-index: 2; }
.desktop__win .admin-frame { width: 100%; }
.desktop__win--saddle {
	width: clamp(540px, 62%, 780px);
	left: 50%;
	translate: -50% 0;
	/* absolute children resolve against the padding box — this offset centers
	   the (caption-less, ~560px) screen in the 700px stage: ~64 mat above,
	   ~76 below, instead of pinned-top with an empty floor */
	top: var(--space-8);
	rotate: -1deg;
	z-index: 2;
}
/* peeks breathe off the stage edges (5% ≈ 62px, was 2% ≈ 25px — they read
   glued to the frame) and stagger gently: waggle high-left, loggle low-right */
.desktop__win--waggle { width: clamp(240px, 22%, 280px); left: 5%; top: 17%; rotate: var(--tilt-2); z-index: 3; }
.desktop__win--loggle { width: clamp(240px, 22%, 280px); right: 5%; top: 24%; rotate: var(--tilt-3); z-index: 3; }
/* the lead's screen fills the stage the way cursor's does (620 of 720):
   the chat scene's natural height is only ~395px here, which left a bald
   248px strip of painting under the window. 520 + title bar ≈ 565 → mats
   read ~64 above / ~70 below. */
.desktop__win--saddle .scene { min-height: 520px; }

/* peeks crop like half-visible windows instead of growing with their text.
   v5's bug: window heights were intrinsic, so the 330px-wide waggle peek
   wrapped its headline and stacked to 446px against the lead's 424px — taller
   than the thing it was meant to tuck behind. scene--compact's min-height is
   a floor; this is the ceiling. */
.desktop__win--waggle .admin-frame__win,
.desktop__win--loggle .admin-frame__win { max-height: 330px; overflow: hidden; }

/* product pages center ONE window on the same desk */
.product-hero__win {
	position: relative;
	z-index: 2;
	max-width: 880px;
	margin-inline: auto;
}
.product-hero__win .admin-frame { width: 100%; }

/* the desk is interactive: hovering any window picks it up — it comes to the
   front regardless of motion preference (functional), and with motion allowed
   it straightens its tilt and grows a touch, like grabbing a real window. */
.desktop__win:hover { z-index: 5; }

/* windows settle onto the desk once, on load */
@media (prefers-reduced-motion: no-preference) {
	.desktop__win { animation: pp-settle .7s var(--ease-out) backwards; }
	.desktop__win--waggle { animation-delay: .12s; }
	.desktop__win--loggle { animation-delay: .2s; }
	.desktop__prop { animation: pp-fade .5s ease .45s backwards; }
	.desktop__win { transition: rotate .25s var(--ease-out), scale .25s var(--ease-out); }
	.desktop__win--waggle:hover, .desktop__win--loggle:hover { rotate: 0deg; scale: 1.05; }
	.desktop__win--saddle:hover { rotate: 0deg; scale: 1.01; }
}
@keyframes pp-settle { from { opacity: 0; transform: translateY(28px) scale(.985); } }
@keyframes pp-fade { from { opacity: 0; } }

/* Liquid Glass for everything small that sits ON an image — caption chips
   and prop tiles frost over the painting like the pricing window does. Their
   88% paper stays as the no-backdrop-filter fallback. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.desktop__stage .admin-frame__caption,
	.showcase__stage .admin-frame__caption,
	.desktop__stage .prop--trash,
	.desktop__stage .prop--file,
	.pricing-desk .prop--file {
		background: color-mix(in srgb, var(--bg) 68%, transparent);
		-webkit-backdrop-filter: blur(14px) saturate(1.35);
		backdrop-filter: blur(14px) saturate(1.35);
		box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.45), inset 0 0 0 1px rgb(255 255 255 / 0.2);
	}
}

/* props scatter across the desk at heyclicky scale — every prop has its own
   clear lane; only the claude cursor may sit ON a window (it drives it) */
.desktop__prop { position: absolute; z-index: 4; }
/* trash + file sit on the painting, which is dark in places — their own
   paper tile, same trick as the caption chips. The note carries its own. */
.desktop__stage .prop--trash,
.desktop__stage .prop--file {
	padding: var(--space-2) var(--space-3);
	border-radius: var(--r-window);
	background: color-mix(in srgb, var(--bg) 88%, transparent);
}
/* the map: note top-right on the sky · trash bottom-right (macOS's corner) ·
   llms.txt bottom-left · kaomoji left mid-floor under the waggle peek ·
   claude cursor resting on the lead window's lower-right */
.desktop__prop--note { right: 2.5%; top: 4%; max-width: 120px; }
.desktop__prop--trash { right: 2.5%; bottom: var(--space-5); }
.desktop__prop--file { left: 2.5%; bottom: var(--space-5); }
.desktop__prop--kaomoji { left: 8%; bottom: 22%; }
.desktop__prop--cursor { right: 29%; bottom: 30%; }

@media (max-width: 1340px) {
	.desktop__prop--note, .desktop__prop--kaomoji { display: none; }
}
@media (max-width: 960px) {
	.desktop__stage { min-height: 0; }
	.desktop__win--waggle, .desktop__win--loggle { display: none; }
	.desktop__win--saddle { position: relative; left: auto; top: auto; translate: none; width: 100%; rotate: 0deg; }
	.desktop__prop { display: none; }
}

/* product hero — clean and centered: title, sub, buttons, ONE big mock.
   Same skeleton as the home hero (intro + stage), one window, no collage. */
.desktop--product .desktop__stage { min-height: 0; }
@media (prefers-reduced-motion: no-preference) {
	.product-hero__win { animation: pp-settle .7s var(--ease-out) backwards; }
}
/* saddle desk eggs — home vocabulary, saddle lanes: note top-right on the
   sky, trash bottom-right (macOS's corner), claude cursor resting on the
   page it just built (only the cursor may sit ON a window — it drives it) */
.product-hero__prop--note { right: 2.5%; top: 5%; max-width: 130px; }
.product-hero__prop--trash { right: 2.5%; bottom: var(--space-5); }
.product-hero__prop--cursor { right: 23%; top: 42%; }
@media (max-width: 1340px) {
	.product-hero__prop--note { display: none; }
}

/* banner variant — short washed-painting band, text only (pricing page) */
.desktop--banner { min-height: clamp(320px, 44vh, 460px); justify-content: center; }
.desktop--banner .desktop__intro { padding-bottom: var(--space-hero); }

/* ---------- hero text (pricing / blog / 404) ---------- */
.hero { padding-block: var(--space-section); text-align: center; }
.hero h1 { max-width: 15em; margin-inline: auto; }
.hero__sub {
	max-width: 34em;
	margin: var(--space-4) auto var(--space-6);
	color: var(--ink-soft);
	font-size: var(--text-lg);
}
.hero .btn-row { justify-content: center; }

/* left-aligned hero variant (blog single/archive/page headers) */
.hero.product-hero { text-align: left; }
.hero.product-hero h1, .hero.product-hero .hero__sub { margin-inline: 0; }

/* 404 shelf — plugin cards grid */
.shelf__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
@media (max-width: 820px) { .shelf__grid { grid-template-columns: 1fr; } }

/* ---------- product trio (feature cards) ---------- */
.trio { display: grid; gap: var(--space-5); }
.trio__panel { max-width: 920px; margin-inline: auto; width: 100%; overflow: hidden; }
.trio__label {
	font-family: var(--font-mono);
	font-size: var(--text-label);
	color: var(--ink-soft);
	display: flex;
	justify-content: space-between;
	padding: var(--space-4) var(--space-6);
	border-bottom: 1px solid var(--line);
	background: var(--surface-alt);
}
.trio__body {
	padding: var(--space-6);
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--space-6);
	align-items: center;
}
@media (max-width: 820px) { .trio__body { grid-template-columns: 1fr; } }
.trio__pitch h3 { font-size: var(--text-h3); margin-bottom: var(--space-3); }
.trio__pitch p { color: var(--ink-soft); font-size: var(--text-small); }
.trio__links { margin-top: var(--space-5); }
.trio__shot .placeholder-slot { min-height: 180px; }

/* ---------- demo ---------- */
.demo__caption { margin-top: var(--space-4); color: var(--ink-soft); max-width: 48em; }

/* ---------- capability grid (Saddle features) — 3×3, one voice ----------
   apple-flat bento (Fahim, 2026-07-27): no borders, no shadows — gray tiles
   on the LIGHT page (apple.com's own inversion; the gray band was fighting
   the dotted pricing desk below). One flagship tile and two wides carry live
   mini-scenes; six small tiles rank below. Clicking stamps a little "✓ ran"
   (tapback family; the roadmap card says "⏳ soon").

   v2 (Fahim, 2026-08-25): the anchor is back, and this time it is a real
   icon. The original design put a mono keycap here as "an app-icon anchor
   with zero icon assets"; the apple-flat pass deleted the keycaps and nothing
   replaced them, so six of the nine cards had been pure text on a flat tile
   ever since. Iconoir gives the theme its first icon language, and the tile
   is where a product's accent finally shows up in this grid. Two rules the
   old header promised but no longer delivered are restored below: the hover
   lift, and the --i stagger, which had been silently outranked. */
/* three labelled parts, one bento each. There was no precedent on this site
   for two heading groups inside one band — every other section runs one
   .section-head and stops — so the parts are separated the way /about/ does
   it: a contained dotted hairline, not a band change. The h3s also give the
   section a real outline under its one h2, which the markdown-friendly rule
   wants and nine flat peers never gave it. */
.cap-group + .cap-group {
	margin-top: var(--space-8);
	padding-top: var(--space-7);
	border-top: 1px dotted var(--line-strong);
}
.cap-group__head {
	font-size: var(--text-h3);
	margin-bottom: var(--space-5);
}
.cap-grid {
	display: grid;
	grid-template-columns: repeat(6, minmax(0, 1fr));
	gap: var(--space-4);
}
.cap-card {
	position: relative;
	grid-column: span 2;
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	background: var(--band);
	border-radius: 18px;
	padding: var(--space-6);
}
/* the stagger, at a specificity that actually wins. On .cap-card alone this
   is (0,1,0) and base.css's `.pp-js .reveal { transition: … }` is (0,2,0) —
   and that shorthand resets transition-delay to 0s, so every card faded in at
   the same moment and the --i emitted on all nine did nothing. Same fix
   .showcase already uses for its own choreography. */
.pp-js .cap-card.reveal {
	transition-delay: calc(var(--i, 0) * 50ms);
}
/* the bento: one tall tile carrying the mock, two small ones stacked beside
   it. 4 + 2 of six columns, and the tall one spans both rows, so the group
   closes with no hole. It has to come FIRST in the DOM or auto-placement puts
   the smalls above it (outcome.php sorts for this). */
.cap-card--lg {
	grid-column: span 4;
	grid-row: span 2;
}
/* the mock fills whatever height is left instead of a fixed 200px, so the
   tall tile ends flush with the two beside it. */
.cap-card--lg .cap-card__scene { margin-top: auto; }
.cap-card--lg .cap-card__scene .scene { min-height: 240px; }
.cap-card--wide { grid-column: span 3; }
/* flagship — the full row, above the wides. Text and scene sit SIDE BY SIDE:
   stacking them across six columns gives a 1100px-wide scene about 200px tall,
   which reads as a letterbox strip rather than a window. The 1fr/1fr split
   keeps the mock near the wides' aspect and gives the copy a readable measure
   instead of one 1100px line. */
.cap-card--flagship {
	grid-column: span 6;
	flex-direction: row;
	align-items: center;
	gap: var(--space-6);
}
.cap-card--flagship .cap-card__lede {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	flex: 1 1 0;
	min-width: 0;
}
.cap-card--flagship .cap-card__scene {
	margin-top: 0;
	flex: 1 1 0;
	min-width: 0;
}
/* flagship scene well — white inset on the gray tile, scene fills it.
   Scenes render STATIC here (finished state): the compact mocks loop on a
   10s cycle and spend part of it blank — a tile that periodically empties
   reads as broken in a calm grid. */
.cap-card__scene {
	margin-top: var(--space-4);
	border-radius: 12px;
	overflow: hidden;
	background: var(--surface);
}
.cap-card__scene .scene { min-height: 200px; }
.cap-card__scene .scene * {
	animation: none !important;
	opacity: 1 !important;
	transform: none !important;
}
/* ---------- icons (Iconoir, MIT — assets/img/icons/LICENSE) ----------
   Adopted 2026-08-25 (Fahim: "we can use iconoir icons whole site"). The
   theme had no icon system at all before this: ten brand logos, one checkmark
   duplicated by copy-paste, and three desk props hardwired into one component.
   Marks are inlined by pp_icon() rather than served as <img> because they are
   stroked in currentColor, so one file serves an --ink label and an --accent
   tile. Sized from font-size, so a card sets one number and the icon follows. */
.pp-icon {
	display: block;
	width: 1em;
	height: 1em;
	flex: none;
}
/* the card's icon tile — the first place a product accent does real work in
   this grid. Fill only, no border (one or the other, never both), and the
   accent is mixed at point of use: a var() inside a :root custom property
   would freeze against :root's accent instead of the product's. */
.cap-card__icon {
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	margin-bottom: var(--space-2);
	border-radius: var(--r-inner);
	background: color-mix(in srgb, var(--accent) 10%, transparent);
	color: var(--accent);
	font-size: 22px;
}
.cap-card__title {
	font-size: var(--text-body);
	font-weight: 600;
	color: var(--ink);
	letter-spacing: -0.01em;
}
.cap-card__desc {
	font-size: var(--text-small);
	line-height: 1.55;
	color: var(--ink-soft);
}
/* the roadmap, demoted from a card to one quiet line */
.cap-grid__soon {
	margin: var(--space-5) 0 0;
	font-size: var(--text-small);
	color: var(--ink-soft);
}
/* click egg — a stamp pops on the corner (decorative, like the FAQ tapback) */
.cap-card::after {
	content: '✓ ran' / '';
	position: absolute;
	top: -8px;
	right: 12px;
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--surface);
	border: 1px solid var(--line-strong);
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--ink);
	opacity: 0;
	transform: scale(.6);
	pointer-events: none;
}
.cap-card.is-run::after { opacity: 1; transform: scale(1); transition: transform .18s var(--ease-out), opacity .12s ease; }
/* pro-soon roadmap cards — the .placeholder-slot honest voice on the cap-card
   frame: dashed, unfilled, and the stamp says "soon" because nothing here has
   ever run. 2×2 on desktop; the existing 640px rule already takes them full. */
.cap-card--soon {
	grid-column: span 3;
	background: transparent;
	border: 1.5px dashed var(--line-strong);
}
.cap-card--soon::after { content: '⏳ soon' / ''; }
@media (pointer: fine) {
	.pp-js .cap-card { cursor: pointer; }
}
/* the lift these cards were always meant to have. The block comment above
   still promised "the site's standard lift", but the apple-flat pass deleted
   the rule with the keycaps and never replaced it, leaving a pointer cursor
   over a tile that answered nothing. Same 2px and the same shadow step as
   .trio__panel, .tier and .proof-item. */
@media (prefers-reduced-motion: no-preference) {
	.cap-card { transition: transform .15s var(--ease-out), box-shadow .15s ease; }
	.cap-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lift); }
}
@media (max-width: 1024px) {
	/* wides go full-width, smalls pair up */
	.cap-card { grid-column: span 3; }
	.cap-card--wide, .cap-card--flagship { grid-column: span 6; }
	/* the tall tile stops being tall: at this width the two beside it are
	   full-width anyway, so a row span would just strand empty grid. */
	.cap-card--lg { grid-column: span 6; grid-row: auto; }
	/* side by side stops paying once the card is the only thing on its row and
	   each half is under ~340px: the mono lines in the scene wrap mid-token. */
	.cap-card--flagship { flex-direction: column; align-items: stretch; }
	.cap-card--flagship .cap-card__scene { margin-top: var(--space-4); }
}
@media (max-width: 640px) {
	.cap-card, .cap-card--wide, .cap-card--flagship, .cap-card--lg { grid-column: span 6; }
}

/* ---------- feature bento (product pages) — every core highlighted ----------
   6-col grid: wide scene cards (span 4) zigzag against small cards (span 2);
   row 1 = wide + small, row 2 = small + wide. Scenes sit in a quiet inset
   well, not a full window — the cards stay light. */
.features-grid {
	display: grid;
	grid-template-columns: repeat(6, minmax(0, 1fr));
	gap: var(--space-5);
	align-items: stretch;
}
.feature-card {
	grid-column: span 2;
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	padding: var(--space-6);
	box-shadow: var(--shadow-window);
}
.feature-card--wide { grid-column: span 4; }
.feature-card__scene {
	border: 1px solid var(--line);
	border-radius: var(--r-inner);
	overflow: hidden;
	margin-bottom: var(--space-2);
}
.feature-card__scene .scene { min-height: 210px; }
/* kicker — one line in the plugin's own UI voice (real data → mono) */
.feature-card__kicker {
	font-family: var(--font-mono);
	font-size: var(--text-label);
	letter-spacing: 0.03em;
	color: var(--ink-soft);
}
.feature-card h3 { margin: 0; }
.feature-card p { margin: 0; color: var(--ink-soft); }
/* clients tile — small chips + one mono tail line */
.feature-card__chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.feature-card .clients__chip { padding: 6px 14px; font-size: var(--text-mono); box-shadow: none; background: var(--surface-alt); }
.feature-card__tail { font-family: var(--font-mono); font-size: var(--text-micro); color: var(--ink-soft); margin-top: auto; }
/* facts tile — the verified fact sheet, stacked */
.feature-card__facts {
	list-style: none;
	margin: 0;
	padding: 0;
	font-family: var(--font-mono);
	font-size: var(--text-mono);
	color: var(--ink);
}
.feature-card__facts li { padding-block: var(--space-2); }
.feature-card__facts li + li { border-top: 1px dotted var(--line-strong); }
@media (max-width: 820px) {
	.feature-card, .feature-card--wide { grid-column: 1 / -1; }
}

/* ---------- specs rail (product pages) — the readme fact sheet ----------
   One static mono line under the hero: dotted rails borrowed from the marquee,
   zero motion. Every item is a verified number from the plugin's source. */
.specs-rail {
	border-block: 1px dotted var(--line-strong);
	padding-block: var(--space-4);
}
.specs-rail__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	column-gap: var(--space-3);
	row-gap: var(--space-2);
	font-family: var(--font-mono);
	font-size: var(--text-mono);
	color: var(--ink-soft);
}
.specs-rail__list li + li::before { content: '·'; padding-right: var(--space-3); color: var(--line-strong); }

/* ---------- clients row (product pages, data-gated) ---------- */
.clients__chips {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-3);
}
.clients__chip {
	display: inline-flex;
	align-items: center;
	padding: 10px 20px;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 999px;
	font-size: var(--text-small);
	font-weight: 500;
	color: var(--ink);
	box-shadow: var(--shadow-window);
}
.clients__tail {
	margin-top: var(--space-5);
	text-align: center;
	font-family: var(--font-mono);
	font-size: var(--text-mono);
	color: var(--ink-soft);
}

/* ---------- proof ---------- */
.proof__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--space-5);
	align-items: start;
}
@media (max-width: 820px) { .proof__grid { grid-template-columns: 1fr; } }
.proof-item {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	padding: var(--space-5);
}
.proof-item blockquote { margin: 0 0 var(--space-3); }
.proof-item cite {
	font-style: normal;
	font-family: var(--font-mono);
	font-size: var(--text-mono);
	color: var(--ink-soft);
}
.proof-item__stars { color: var(--ink); letter-spacing: 2px; margin-bottom: var(--space-2); }
.join-strip {
	margin-top: var(--space-7);
	text-align: center;
	font-family: var(--font-mono);
	font-size: var(--text-mono);
	color: var(--ink-soft);
}

/* ---------- pricing — heyclicky window cards ----------
   Three mac-window cards (traffic-light bars, dotted separators, centered
   body, big mono price, "includes" list). Recommended tier = tinted bar +
   mono pill straddling the window edge (heyclicky) + the only filled button
   (cursor's highlight system). Accent = blue on home/pricing (:root default),
   the product accent on product pages. */
/* what One covers — the bundle made concrete: three product chips + the
   future-plugins promise (dashed = the honest-placeholder voice) */
/* ---------- the pricing desk — full-bleed painting band ----------
   heyclicky's pricing move, measured live: their section is a full-bleed sky
   photo with the tier cards sitting straight on it. Here: the page's own
   painting (Monet on /pricing/, Bierstadt crop elsewhere — one artwork per
   page), edge to edge, no radius (it's a band, not a stage panel). Heading
   and notes stay on the flat gray band — text never sits on a painting
   (§14.3). Deliberately outside pp-vivid: the konami egg belongs to the hero. */
/* the SECTION is the desk — dots as its own background, so .band's
   --space-section padding pads content INSIDE the pattern and no blank gray
   ever frames it (Fahim, v5.3). Surface: heyclicky's dotted wallpaper
   (they run rgba(0,0,0,.13) 1px dots — measured), rebuilt token-pure.
   The painting lives INSIDE the cards (framed scenes). */
.pricing-desk {
	position: relative;
	background-color: var(--band);
	background-image: radial-gradient(color-mix(in srgb, var(--ink) 13%, transparent) 1px, transparent 1.3px);
	background-size: 28px 28px;
}


/* pricing desk eggs — real data only: license.key echoes the card title bars,
   the note is the FAQ refund answer, the receipt prints the entry price */
.pricing__prop { position: absolute; z-index: 2; }
.pricing-desk .prop--file {
	padding: var(--space-2) var(--space-3);
	border-radius: var(--r-window);
	background: color-mix(in srgb, var(--bg) 88%, transparent);
}
/* lanes measured against the whole section (head included since v5.3) */
.pricing__prop--license { left: 3%; top: 38%; }
.pricing__prop--note { right: 2.5%; top: 26%; max-width: 130px; }
.pricing__prop--receipt { left: 3.5%; bottom: 12%; }
@media (max-width: 1340px) {
	.pricing__prop--note { display: none; }
}
/* the 1080px container fills the viewport before the hero's 960 cut — the
   gutters the eggs live in are gone by here */
@media (max-width: 1180px) {
	.pricing__prop { display: none; }
}

.pricing__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--space-6);
	align-items: stretch;
	/* three cards stretch gaunt at the container's full 1080 — cap and center */
	max-width: 1020px;
	margin-inline: auto;
}
@media (max-width: 820px) { .pricing__grid { grid-template-columns: 1fr; } }

/* on the painting the cards float like the hero windows do, and the
   recommended plan physically rises above its siblings — the art band gives
   the lift room that the old flat gray band never had. (Off-canvas tiers,
   if any return, keep the flat --shadow-window treatment below.) */
.pricing-desk .tier { box-shadow: 0 0 0 1px var(--line), var(--shadow-float); }
/* all three cards align — the recommended lift is gone with the ring, glow
   and badge (Fahim, 2026-07-26); only the tinted bar + filled button remain */

/* the card is a framed scene (Fahim's reference screenshot): white frame →
   the page's painting filling the interior → the license window sitting ON
   the art. All text lives inside .tier__win, so nothing ever reads on the
   painting. */
.tier {
	position: relative;
	background-color: var(--band); /* fallback until the art loads */
	background-size: cover;
	/* no frame border (Fahim) — the painting runs to the card edge; the
	   hairline ring below is the only edge definition. Radius is concentric
	   with the inner window: (r-window - 4) + the 8px art ring = r-window + 4,
	   so the ring stays even through the corners. */
	border-radius: calc(var(--r-window) + 4px);
	box-shadow: 0 0 0 1px var(--line), var(--shadow-window);
	display: flex;
	flex-direction: column;
	text-align: center;
	overflow: hidden; /* art clips to the frame's inner corners */
}
/* the window on the painting — an even art border all around (the
   reference's composition) */
.tier__win {
	flex: 1;
	display: flex;
	flex-direction: column;
	margin: 8px; /* the painting reads as an even border around the window — top = bottom = sides */
	background: var(--surface); /* solid fallback — glass upgrade below */
	border-radius: calc(var(--r-window) - 4px);
	box-shadow: var(--shadow-window);
	overflow: hidden;
}
/* Liquid Glass, BAR ONLY (Fahim): the body stays solid paper; the title bar
   frosts and the painting glows through it — the macOS-toolbar read. The
   window shell goes transparent so the bar's backdrop IS the painting; the
   body carries the solid surface. Solid rules above are the
   no-backdrop-filter fallback. White rgb() literals = specular alpha data
   (same sanctioned pattern as tokens.css's --shadow-window inset). */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	/* transparent only behind the 34px bar — solid below keeps corners clean */
	.tier__win { background: linear-gradient(to bottom, transparent 0 34px, var(--surface) 34px); }
	.tier__win .tier__body { background: var(--surface); }
	.tier__win .tier__bar {
		background: color-mix(in srgb, var(--surface-alt) 78%, transparent);
		-webkit-backdrop-filter: blur(12px) saturate(1.3);
		backdrop-filter: blur(12px) saturate(1.3);
	}
	.tier__win { box-shadow: 0 0 0 1px rgb(28 27 24 / 0.1), var(--shadow-window); }
}
.tier__bar {
	position: relative;
	height: 34px; /* slimmer than media windows — small utility window */
	/* own top radius matching the .tier__win container exactly (6px) — the
	   frosted bar's backdrop-filter ignores the ancestor clip, and the
	   inherited 9px admin-frame radius would notch this smaller container */
	border-radius: calc(var(--r-window) - 4px) calc(var(--r-window) - 4px) 0 0;
}
.tier__bar .admin-frame__lights i { width: 8px; height: 8px; }
/* mono license filename — centers in the bar's free space (flex, chrome.css),
   so the recommended chip can never overlap it. The window is narrower now
   (frame + win margins eat ~40px), so the filename yields with an ellipsis
   before the chip ever clips. */
.tier__file {
	margin-inline: auto;
	font-size: var(--text-micro);
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	/* ink, not ink-soft: over the recommended card's 18% accent-tinted bar
	   (and the product pages' tint band) soft ink falls under AA contrast */
	color: var(--ink);
}
/* recommended, pared back (Fahim, 2026-07-27): no ring, no glow, no bar tint —
   the filled blue button plus one quiet chip in the title bar. */
.tier__flag {
	flex: none;
	font-size: var(--text-micro);
	color: var(--on-accent);
	background: var(--accent);
	border-radius: 999px;
	padding: 2px 8px;
	margin-left: var(--space-2);
	white-space: nowrap;
}
/* in the tier bar the chip sits opposite the lights */
.tier__bar .tier__flag { margin-left: auto; }
.tier__body {
	flex: 1;
	padding: var(--space-5);
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-3);
}
.tier__name { font-size: var(--text-h3); font-weight: 600; margin: 0; }
.tier__audience { margin: 0; font-size: var(--text-small); color: var(--ink-soft); }
/* quiet, not accent-filled — .tier__flag already owns the loud pill for
   "Recommended"; two shouting chips on one card is one too many */
.tier__intro {
	font-size: var(--text-micro);
	color: var(--ink-soft);
	background: var(--band);
	border: 1px solid var(--line);
	border-radius: 999px;
	padding: 2px 10px;
}
/* soft dotted rule that fades at both ends — quieter than a full-bleed line */
/* the trial's terms, directly under its button: what happens when the days
   run out, and whether a card is taken now. A trial button with no price
   beside it is the oldest dark pattern in SaaS. */
.tier__trial {
	margin: var(--space-3) 0 0;
	font-size: var(--text-small);
	color: var(--ink-soft);
	text-align: center;
}
.tier__rule {
	width: 100%;
	height: 1px;
	background-image: linear-gradient(90deg, transparent, var(--line-strong) 18%, var(--line-strong) 82%, transparent);
	-webkit-mask-image: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 8px);
	mask-image: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 8px);
	margin-block: var(--space-3);
}
.tier__price {
	font-size: 2.75rem;
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--ink);
	font-variant-numeric: tabular-nums;
}
.tier__was {
	font-size: var(--text-lg);
	font-weight: 500;
	color: var(--ink-soft);
	text-decoration-thickness: 1px;
	margin-right: 2px;
	vertical-align: 6px;
}
.tier__billing { margin: calc(-1 * var(--space-2)) 0 0; font-size: var(--text-small); color: var(--ink-soft); } /* hugs the price */
.tier__body .btn { margin-top: var(--space-2); align-self: stretch; } /* full-width CTA: bigger target, cleaner column */
.tier__includes { width: 100%; text-align: left; }
.tier__includes ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); font-size: var(--text-small); }
.tier__includes li { padding-left: 1.5em; position: relative; color: var(--ink-soft); }
/* SVG check via mask (not the '✓' glyph — its shape drifts per font): rounded
   caps, even stroke, optically aligned to the first text line. Inherits ink
   through background-color, same mask technique as .tier__rule above. */
.tier__includes li::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.28em;
	width: 0.95em;
	height: 0.95em;
	background-color: var(--ink);
	-webkit-mask: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23000" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M20 6 9 17l-5-5"/%3E%3C/svg%3E') no-repeat center / contain;
	mask: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23000" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M20 6 9 17l-5-5"/%3E%3C/svg%3E') no-repeat center / contain;
}
/* refund + cancel promises — persistent at every viewport (the sticky-note
   prop is decoration and hides <1340px). Prose, so sans. */
.pricing__terms {
	margin: var(--space-4) 0 0;
	text-align: center;
	font-size: var(--text-small);
	color: var(--ink-soft);
}
/* links in muted prose need a non-colour cue (same rule as .hero__sub a) */
.pricing__terms a { text-decoration: underline; text-underline-offset: 3px; }

.allaccess-banner {
	margin-top: var(--space-5);
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	padding: var(--space-5) var(--space-6);
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-4);
}
.allaccess-banner p { margin: 0; }
.allaccess-banner .muted { font-size: var(--text-small); }

/* ---------- faq — a messages window (chat with the maker) ----------
   The thread lives inside a mac window: title bar names the conversation,
   questions are visitor bubbles (right), answers are Fahim's replies (left).
   Opening an item shows a brief typing indicator (JS, motion-safe); clicking
   a reply bubble pops a ❤️ tapback — the messages metaphor, doing real work. */
.faq-window {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-window);
	box-shadow: var(--shadow-window);
	overflow: hidden;
}
.faq-window__bar {
	position: relative;
	height: 34px;
	border-radius: calc(var(--r-window) - 1px) calc(var(--r-window) - 1px) 0 0;
}
.faq-window__bar .admin-frame__lights i { width: 8px; height: 8px; }
.faq-window__title {
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--ink-soft);
	white-space: nowrap;
}
.faq-chat { display: grid; gap: var(--space-4); padding: var(--space-6); }
.faq-chat__item { }
.faq-chat__q {
	cursor: pointer;
	list-style: none;
	display: flex;
	justify-content: flex-end;
}
.faq-chat__q::-webkit-details-marker { display: none; }
.faq-chat__q span {
	position: relative;
	display: inline-block;
	max-width: 80%;
	background: var(--band);
	border: 1px solid var(--line);
	border-radius: 18px 18px 4px 18px;
	padding: var(--space-3) var(--space-5);
	padding-right: 2.4rem;
	font-weight: 500;
	font-size: var(--text-body);
	transition: border-color .12s ease;
}
.faq-chat__q:hover span { border-color: var(--line-strong); }
.faq-chat__q span::after {
	content: '+';
	position: absolute;
	right: 1rem;
	top: 50%;
	translate: 0 -50%;
	color: var(--ink-soft);
	font: 400 1.125rem/1 var(--font-mono);
	transition: rotate .2s ease;
}
.faq-chat__item[open] .faq-chat__q span::after { rotate: 45deg; }
.faq-chat__a {
	display: flex;
	gap: var(--space-3);
	align-items: flex-end;
	margin-top: var(--space-3);
	max-width: 85%;
}
.faq-chat__avatar {
	width: 28px; height: 28px;
	border-radius: 50%;
	object-fit: cover;
	flex: none;
}
.faq-chat__avatar--pending {
	display: grid;
	place-items: center;
	background: var(--ink);
	color: var(--bg);
	font: 600 0.8125rem/1 var(--font-display);
}
.faq-chat__bubble {
	position: relative; /* anchors the tapback */
	background: var(--surface-alt);
	border: 1px solid var(--line);
	border-radius: 18px 18px 18px 4px;
	padding: var(--space-3) var(--space-5);
	color: var(--ink-soft);
}
.faq-chat__name {
	display: block;
	font-weight: 600;
	font-size: var(--text-mono);
	color: var(--ink);
	margin-bottom: 2px;
}

/* ❤️ tapback — pops on the bubble corner when the reply is clicked.
   Empty alt keeps the emoji out of the accessibility tree (decorative egg). */
.faq-chat__bubble::after {
	content: '❤️' / '';
	position: absolute;
	top: -12px;
	right: -8px;
	display: grid;
	place-items: center;
	width: 26px;
	height: 26px;
	font-size: 0.8125rem;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 50%;
	box-shadow: var(--shadow-window);
	scale: 0;
	transition: scale .15s ease;
}
.faq-chat__item.has-tapback .faq-chat__bubble::after { scale: 1; }

/* typing indicator — "Fahim is replying": a mini bubble of three dots shown
   for ~600ms after a question opens (JS toggles .is-typing, motion-safe) */
.faq-chat__typing { display: none; }
.pp-js .faq-chat__item.is-typing .faq-chat__typing {
	display: inline-flex;
	gap: 4px;
	align-items: center;
	background: var(--surface-alt);
	border: 1px solid var(--line);
	border-radius: 18px 18px 18px 4px;
	padding: var(--space-3) var(--space-4);
}
.pp-js .faq-chat__item.is-typing .faq-chat__bubble { display: none; }
.faq-chat__typing i {
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: var(--ink-soft);
}
@media (prefers-reduced-motion: no-preference) {
	.faq-chat__typing i { animation: pp-typing 1s ease-in-out infinite; }
	.faq-chat__typing i:nth-child(2) { animation-delay: .15s; }
	.faq-chat__typing i:nth-child(3) { animation-delay: .3s; }
	@keyframes pp-typing {
		0%, 60%, 100% { translate: 0 0; opacity: .5; }
		30% { translate: 0 -3px; opacity: 1; }
	}
	.pp-js .faq-chat__item[open] .faq-chat__bubble { animation: pp-bubble-in .25s ease; }
	@keyframes pp-bubble-in {
		from { opacity: 0; translate: 0 4px; }
	}
}

/* the standing P.S. reply — a real contact path, always visible */
.faq-chat__ps { margin-top: var(--space-2); }
.faq-chat__ps .faq-chat__bubble::after { content: none; }
.faq-chat__ps a { color: var(--ink); }

/* smooth open — answer height eases in where the platform can animate to
   auto; everywhere else <details> opens instantly (graceful fallback). Layers
   under the typing-dots beat: height settles while the dots play. */
@supports (interpolate-size: allow-keywords) {
	@media (prefers-reduced-motion: no-preference) {
		.faq-chat__item::details-content {
			block-size: 0;
			overflow-y: clip;
			opacity: 0;
			transition: content-visibility .3s allow-discrete, block-size .3s var(--ease-out), opacity .25s ease;
		}
		.faq-chat__item[open]::details-content { block-size: auto; opacity: 1; }
	}
}

/* blue band text (styleguide contract; home pricing history) */
.band--blue h2 { color: var(--surface); }
.band--blue .mono { color: rgb(255 255 255 / .7); }

/* ---------- footer — quiet columns over a giant ghost wordmark ----------
   Sits on the gray band: the page rhythm ends pricing-gray → FAQ-white →
   footer-gray, and the desk edge reads against the paper above it. */
.site-footer {
	background: var(--band);
	border-top: 1px dotted var(--line-strong); /* the desk edge */
	padding-top: var(--space-section);
	color: var(--ink-soft);
	font-size: var(--text-small);
	overflow: hidden;
}
.site-footer a { color: var(--ink-soft); }
.site-footer a:hover { color: var(--ink); }

/* link columns (heyclicky structure): brand anchored left, the four link
   columns packed together on the right at content width — an even 1fr spread
   left the links drifting apart */
.site-footer__cols {
	display: flex;
	gap: clamp(2rem, 4vw, 3.25rem);
	margin-bottom: var(--space-7);
}
.site-footer__brand { max-width: 280px; margin-right: auto; }
.site-footer__brand img { display: block; margin-bottom: var(--space-3); }
.site-footer__tag {
	margin: 0 0 var(--space-2);
	color: var(--ink);
	font-weight: 600;
	font-size: var(--text-small);
}
@media (max-width: 900px) {
	.site-footer__cols { display: grid; grid-template-columns: 1fr 1fr; }
	.site-footer__brand { grid-column: 1 / -1; max-width: none; margin-right: 0; }
}
@media (max-width: 560px) { .site-footer__cols { grid-template-columns: 1fr; } }
.site-footer__label { /* column labels — not headings; keeps the page outline honest */
	font-family: var(--font-sans);
	font-size: var(--text-small);
	font-weight: 600;
	color: var(--ink);
	margin-bottom: var(--space-3);
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.site-footer__note { margin: 0; max-width: 28em; }

/* the desk — ghost wordmark flanked by working props (trash → 404, folder → blog) */
.site-footer__desk { position: relative; }
.site-footer__prop { position: absolute; bottom: var(--space-5); z-index: 1; }
.site-footer__prop--trash { left: clamp(1rem, 4vw, 3rem); }
.site-footer__prop--folder { right: clamp(1rem, 4vw, 3rem); }
@media (max-width: 820px) { .site-footer__prop { display: none; } }
.site-footer__line {
	/* above the wordmark: its inline-block letters' hitboxes overflow their
	   0.72 line box upward and were swallowing clicks on the colophon links */
	position: relative;
	z-index: 2;
	border-top: 1px dotted var(--line-strong);
	padding-block: var(--space-5);
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3) var(--space-5);
	justify-content: space-between;
	align-items: baseline;
}
/* the Waggle credit is a link inside running colophon text — underline, not colour */
.site-footer__line a { text-decoration: underline; text-underline-offset: 3px; }
/* "PlugPress" in real <i> letters (aria-hidden) so each can lift under the
   cursor — the one interactive wink down here. Wordmark itself stays
   pointer-transparent; only letters catch hover. */
.site-footer__wordmark {
	display: block;
	text-align: center;
	font-family: var(--font-display);
	font-weight: 800;
	font-size: clamp(5rem, 16vw, 15rem); /* documented exception: ghost texture, not type scale */
	line-height: 0.72;
	letter-spacing: -0.04em;
	color: var(--line); /* one step darker than the gray footer it sits on */
	user-select: none;
	pointer-events: none;
	margin-top: var(--space-7); /* breathing room under the colophon line */
	margin-bottom: -0.06em;
	white-space: nowrap;
}
.site-footer__wordmark i {
	font-style: normal;
	display: inline-block;
	pointer-events: auto;
	transition: translate .25s var(--ease-out), color .25s ease;
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
	/* the letter under the cursor wakes up brand-blue and lifts… */
	.site-footer__wordmark i:hover {
		translate: 0 -0.06em;
		color: var(--blue);
	}
	/* …and PRESSES down on click (it is PlugPress, after all) */
	.site-footer__wordmark i:active {
		translate: 0 0.03em;
		transition-duration: .07s;
	}
}

/* ---------- legal pages — heyclicky anatomy (Fahim's reference, 2026-07-27):
   the dotted desk carries the whole page, a big centered lowercase title,
   "← back", then one narrow gray-prose column with numbered headings. ---------- */
.legal-desk { background: var(--surface); } /* plain white — Fahim dropped the dots */
.legal-hero {
	padding: clamp(4rem, 10vw, 7rem) 0 var(--space-6);
	text-align: center;
}
.legal-hero h1 {
	margin: 0 0 var(--space-3);
	font-size: var(--text-h1);
	/* sentence case like every other heading — lowercase was heyclicky's brand
	   voice, not ours (the wordmark alone owns lowercase) */
	letter-spacing: -0.03em;
}
.legal-col { padding-bottom: var(--space-section); }
.legal-back { margin: 0 0 var(--space-7); }
.legal-back a { color: var(--ink-soft); text-decoration: none; }
.legal-back a:hover { color: var(--ink); }
.legal-lede { color: var(--ink-soft); margin: 0 0 var(--space-5); }
.legal-updated { color: var(--ink-soft); font-size: var(--text-label); margin: 0; }
/* prose runs gray; headings stay ink and number themselves */
.legal-body { color: var(--ink-soft); counter-reset: legal; }
.legal-body h2 { color: var(--ink); counter-increment: legal; }
.legal-body h2::before { content: counter(legal) '. '; }
.legal-body { margin-top: var(--space-7); }
.legal-body h2:first-child { margin-top: 0; }
/* a policy is a document, not a landing page — the display scale would have
   eight section headings shouting over the clauses they introduce */
.legal-body h2 { font-size: var(--text-h3); }
.legal-body h3 { font-size: var(--text-lg); }

/* an unanswered question in a policy — deliberately loud. Uses the highlighter
   token, the same voice the sticky note speaks in, so it reads as a human note
   to self rather than an error state. */
.legal-blank {
	background: var(--marker-soft);
	color: var(--ink);
	font-family: var(--font-mono);
	font-size: var(--text-mono);
	padding: 1px 8px;
	border-radius: var(--r-inner);
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}
.legal-blank::before { content: 'TO CONFIRM: '; color: var(--ink-soft); }

.legal-foot {
	margin: var(--space-8) 0 var(--space-section);
	padding-top: var(--space-5);
	border-top: 1px dotted var(--line-strong);
	font-size: var(--text-small);
	color: var(--ink-soft);
}
.legal-foot p { margin: 0; }
.legal-foot a { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- contact form — a window you type into ----------
   Sits in the same admin-frame chrome as every other surface on the site, so
   the form reads as furniture rather than a bolted-on widget. Labels are sans:
   mono stays reserved for real data. */
.form-card {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	box-shadow: var(--shadow-window);
	overflow: hidden;
}
.form { padding: var(--space-6); display: grid; gap: var(--space-5); }

.field { margin: 0; display: grid; gap: var(--space-2); }
.field label { font-size: var(--text-small); font-weight: 600; color: var(--ink); }
.field__hint { font-size: var(--text-small); color: var(--ink-soft); }
.field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); }
@media (max-width: 640px) { .field-row { grid-template-columns: minmax(0, 1fr); } }

.field input, .field select, .field textarea {
	width: 100%;
	font: inherit;
	font-size: var(--text-body);
	color: var(--ink);
	background: var(--bg);
	border: 1px solid var(--line-strong);
	border-radius: var(--r-inner);
	padding: var(--space-3) var(--space-4);
	transition: border-color .15s ease, box-shadow .15s ease;
}
.field textarea { resize: vertical; min-height: 8rem; line-height: 1.55; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ink-soft); }
.field input:focus, .field select:focus, .field textarea:focus {
	outline: none; /* replaced by the ring below — :focus-visible still applies for keyboard */
	border-color: var(--blue);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 18%, transparent);
}

.form-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-4);
}
.form-actions__alt { font-size: var(--text-small); color: var(--ink-soft); }
.form-actions__alt a { text-decoration: underline; text-underline-offset: 3px; }

/* honeypot — must be reachable to a bot parsing the DOM, invisible to a person.
   Not `display:none`: some bots skip those. */
.form-trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* result banner — never colour alone: each carries its own glyph */
.form-notice {
	margin: 0 0 var(--space-5);
	padding: var(--space-4) var(--space-5);
	border-radius: var(--r-inner);
	border: 1px solid var(--line);
	background: var(--surface);
	font-size: var(--text-small);
	color: var(--ink);
}
.form-notice::before { font-family: var(--font-mono); margin-right: var(--space-2); }
.form-notice--ok { border-color: color-mix(in srgb, var(--blue) 35%, var(--line)); }
.form-notice--ok::before { content: '✓'; }
.form-notice--error::before { content: '!'; }
.form-notice--error { border-color: var(--line-strong); background: var(--surface-alt); }

/* blog archive cards live in blog.css section 6 */

/* author archive hero — avatar + name + bio on one line */
.author-hero { display: flex; align-items: center; gap: var(--space-5); }
.author-hero__avatar { display: block; border-radius: 50%; border: 1px solid var(--line); flex: none; }
.author-hero .hero__sub { margin: var(--space-2) 0 0; }
@media (max-width: 640px) { .author-hero { flex-direction: column; align-items: flex-start; gap: var(--space-4); } }

/* ---------- author card — the post-footer byline as a mini mac window ---------- */
.author-card {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-window);
	box-shadow: var(--shadow-window);
	overflow: hidden;
	margin-bottom: var(--space-6);
}
.author-card__bar {
	position: relative;
	display: flex;
	align-items: center;
	height: 28px;
	padding-inline: var(--space-3);
	background: var(--surface-alt);
	border-bottom: 1px solid var(--line);
}
.author-card__bar .admin-frame__lights i { width: 8px; height: 8px; }
/* the author archive path, dead-center in the bar — real data, mono voice */
.author-card__label {
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
	font-size: var(--text-micro);
	color: var(--ink-soft);
	white-space: nowrap;
}
.author-card__body { display: flex; align-items: flex-start; gap: var(--space-4); padding: var(--space-5); }
.author-card__avatar { display: block; border-radius: 50%; border: 1px solid var(--line); flex: none; }
.author-card__role { display: block; font-size: var(--text-label); color: var(--ink-soft); margin-bottom: 2px; }
.author-card__name { font-weight: 600; color: var(--ink); }
.author-card__name:hover { color: var(--blue); text-decoration: none; }
.author-card__bio { margin: var(--space-1) 0 var(--space-2); color: var(--ink-soft); font-size: var(--text-small); }
.author-card__more { font-size: var(--text-small); font-weight: 500; color: var(--blue); }
.author-card__more:hover { text-decoration: underline; }
@media (max-width: 640px) { .author-card__body { flex-direction: column; } }

/* pagination — mono pills (the_posts_pagination markup) */
.pagination { margin-top: var(--space-6); }
.pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	justify-content: center;
	font-family: var(--font-mono);
	font-size: var(--text-mono);
}
.pagination .page-numbers {
	display: inline-grid;
	place-items: center;
	min-width: 36px;
	height: 36px;
	padding-inline: 10px;
	border: 1px solid var(--line);
	border-radius: var(--r-inner);
	color: var(--ink-soft);
}
.pagination a.page-numbers:hover { border-color: var(--line-strong); color: var(--ink); text-decoration: none; }
.pagination .page-numbers.current { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.pagination .page-numbers.dots { border: 0; }

/* single post prev/next — closes the page under the maker notice */
.post-navigation { margin-top: var(--space-6); border-top: 1px dotted var(--line-strong); padding-top: var(--space-5); }
.post-navigation .nav-links { display: flex; justify-content: space-between; gap: var(--space-4); font-size: var(--text-small); }
.post-navigation .nav-next { margin-left: auto; text-align: right; }

/* 404 — the trash sits above the headline, gently tipped */
.error404 .prop--trash { margin-bottom: var(--space-4); rotate: -3deg; }
.error404 .hero .btn-row { margin-bottom: var(--space-2); }

/* ---------- blog / entry content ---------- */
.single .hero, .blog .hero, .archive .hero, .error404 .hero { padding-bottom: var(--space-6); }
.entry { font-size: var(--text-body); }
.entry > * + * { margin-top: var(--space-4); }
.entry h2 { margin-top: var(--space-7); }
.entry h3 { margin-top: var(--space-6); }
.entry img { border: 1px solid var(--line); border-radius: var(--r-card); }
.entry pre {
	background: var(--surface-alt);
	border: 1px solid var(--line);
	border-radius: var(--r-window);
	padding: var(--space-4);
	overflow-x: auto;
	font-family: var(--font-mono);
	font-size: var(--text-mono);
}
.entry code { font-family: var(--font-mono); font-size: 0.9em; }
.entry blockquote {
	margin: 0;
	padding-left: var(--space-5);
	border-left: 3px solid var(--line);
	color: var(--ink-soft);
}
/* long-form structure — legal pages lean on lists, sub-headings and rules,
   none of which .entry styled before (they fell through to UA defaults) */
.entry h4 {
	font-family: var(--font-display);
	font-size: var(--text-lg);
	font-weight: 600;
	line-height: 1.25;
	letter-spacing: -0.01em;
	margin: var(--space-6) 0 var(--space-3);
}
.entry ul, .entry ol { padding-left: 1.35em; }
.entry li + li { margin-top: var(--space-2); }
.entry li::marker { color: var(--ink-soft); }
.entry ul ul, .entry ol ol { margin-top: var(--space-2); }
.entry hr {
	border: 0;
	border-top: 1px solid var(--line);
	margin-block: var(--space-7);
}
.entry table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--text-small);
}
.entry th, .entry td {
	text-align: left;
	padding: var(--space-3);
	border-bottom: 1px solid var(--line);
	vertical-align: top;
}
.entry th { font-weight: 600; }
/* a link inside body prose can't be told apart by colour alone */
.entry a { text-decoration: underline; text-underline-offset: 3px; }

/* 404 trash prop — ink on paper, not wallpaper */
.error404 .prop { color: var(--ink-soft); text-shadow: none; margin-bottom: var(--space-4); }
.error404 .prop__icon { fill: var(--ink-soft); filter: none; }

/* ---------- styleguide ---------- */
.styleguide .band { padding-block: var(--space-7); }
.styleguide__label {
	font-family: var(--font-mono);
	font-size: var(--text-label);
	color: var(--ink-soft);
	border-bottom: 1px dotted var(--line-strong);
	padding-bottom: var(--space-2);
	margin-bottom: var(--space-6);
}

/* ---------- product showcases (home shelf) ----------
   ONE section, three stacked zigzag panels (cursor's feature-card rhythm).
   One quiet shared fill — no borders, no per-product tint: the product's
   color identity lives in its icon and scene only. */
.showcase-stack { display: grid; gap: var(--space-8); } /* clear air between product panels — each reads as its own scene */
.showcase {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr)); /* content 50 / mock 50 */
	gap: var(--space-7);
	align-items: center;
	background: var(--band);
	border-radius: var(--r-canvas);
	padding: clamp(1.5rem, 3.5vw, 3rem);
}
.showcase--flip .showcase__stage { order: 2; }
/* the mock's half is a painted panel — the reference-screenshot anatomy
   (panel → art → window) at section scale. Inline wallpaper from shelf.php;
   --band is the pre-load fallback. Text stays in the pitch half, never here. */
.showcase__stage {
	background-color: var(--band);
	background-size: cover;
	background-position: center;
	/* concentric corners: outer radius = inner window radius + the 8px ring,
	   so the art border stays even THROUGH the corner (a 4px outer against
	   the 10px window pinched at the corners — Fahim's circles) */
	border-radius: calc(var(--r-window) + 8px);
	overflow: hidden;
	padding: 8px; /* thin, even art border around the mock — same 8px ring as the pricing cards */
}
.showcase__stage .admin-frame { width: 100%; margin-inline: auto; }
.showcase__stage .admin-frame__win { box-shadow: var(--shadow-float); }
/* Liquid Glass, BAR ONLY (Fahim) — the scene body stays solid; the browser
   bar frosts over the painting. Window shell transparent so the bar's
   backdrop is the art; the media/scene below keep their solid chrome.css
   backgrounds and cover the body. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	/* transparent only behind the 44px bar — solid below keeps corners clean */
	.showcase__stage .admin-frame__win { background: linear-gradient(to bottom, transparent 0 44px, var(--surface) 44px); }
	.showcase__stage .admin-frame__bar {
		background: color-mix(in srgb, var(--surface-alt) 78%, transparent);
		-webkit-backdrop-filter: blur(12px) saturate(1.3);
		backdrop-filter: blur(12px) saturate(1.3);
	}
	.showcase__stage .admin-frame__win { box-shadow: 0 0 0 1px rgb(28 27 24 / 0.12), var(--shadow-float); }
}
/* captions sitting on the panel art carry their own chip (same rule as the
   hero stage) */
.showcase__stage .admin-frame__caption {
	color: var(--ink);
	display: inline-block;
	padding: 2px 10px;
	border-radius: 999px;
	background: color-mix(in srgb, var(--bg) 88%, transparent);
}
.showcase__pitch h2 { margin: var(--space-2) 0 var(--space-3); }
.showcase__pitch p { color: var(--ink-soft); max-width: 42ch; }
/* no buttons here — one quiet arrow link; buying CTAs live on the product
   page and in pricing. The arrow nudges 3px on hover (motion-safe via the
   global reduce block zeroing transitions). */
.showcase__link {
	display: inline-flex;
	align-items: baseline;
	gap: 0.45em;
	margin-top: var(--space-5);
	font-weight: 500;
	color: var(--ink);
}
.showcase__link span { transition: translate .15s var(--ease-out); }
.showcase__link:hover { text-decoration: none; color: var(--blue); }
.showcase__link:hover span { translate: 3px 0; }
/* product icon beside the eyebrow name — optically centered, brand-colored */
.showcase__pitch .eyebrow {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
}
.showcase__icon {
	display: block;
	width: 24px;
	height: 24px;
}
/* three scannable facts — short lines, real numbers, ✓ in ink */
.showcase__points {
	list-style: none;
	margin: var(--space-4) 0 0;
	padding: 0;
	display: grid;
	gap: var(--space-2);
	font-size: var(--text-small);
	color: var(--ink-soft);
	max-width: 42ch;
}
.showcase__points li { padding-left: 1.5em; position: relative; }
/* same SVG check as .tier__includes — one check shape site-wide */
.showcase__points li::before {
	content: '';
	position: absolute;
	left: 0;
	top: 0.28em;
	width: 0.95em;
	height: 0.95em;
	background-color: var(--ink);
	-webkit-mask: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23000" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M20 6 9 17l-5-5"/%3E%3C/svg%3E') no-repeat center / contain;
	mask: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23000" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M20 6 9 17l-5-5"/%3E%3C/svg%3E') no-repeat center / contain;
}
@media (max-width: 960px) {
	/* minmax(0, …), not 1fr — a nowrap scene chip must crop, never widen the panel */
	.showcase { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); padding: var(--space-4); }
	.showcase--flip .showcase__stage { order: 0; } /* stage always first when stacked */
}

/* reveal choreography — the section doesn't fade as one slab: the window
   settles while the pitch arrives line by line (eyebrow → h2 → p → CTAs).
   Tight 70ms steps; one-shot IO in site.js; no-JS / reduced-motion get
   everything instantly (both gates below). */
@media (prefers-reduced-motion: no-preference) {
	.pp-js .showcase.reveal { opacity: 1; transform: none; }
	.pp-js .showcase.reveal .showcase__stage,
	.pp-js .showcase.reveal .showcase__pitch > * {
		opacity: 0;
		transform: translateY(16px);
		transition: opacity .55s var(--ease-out), transform .55s var(--ease-out);
	}
	.pp-js .showcase.reveal .showcase__stage { transform: translateY(24px) scale(.985); }
	.pp-js .showcase.reveal.is-visible .showcase__stage,
	.pp-js .showcase.reveal.is-visible .showcase__pitch > * { opacity: 1; transform: none; }
	.pp-js .showcase.reveal.is-visible .showcase__pitch > *:nth-child(2) { transition-delay: 60ms; }
	.pp-js .showcase.reveal.is-visible .showcase__pitch > *:nth-child(3) { transition-delay: 120ms; }
	.pp-js .showcase.reveal.is-visible .showcase__pitch > *:nth-child(4) { transition-delay: 180ms; }
	.pp-js .showcase.reveal.is-visible .showcase__pitch > *:nth-child(5) { transition-delay: 240ms; }
}

/* ---------- about timeline ---------- */
/* year in mono (real data), rows split by the site's dotted hairlines */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
	display: grid;
	grid-template-columns: 5rem 1fr;
	gap: var(--space-4);
	padding-block: var(--space-4);
	border-top: 1px dotted var(--line-strong);
}
.timeline li:first-child { border-top: 0; padding-top: 0; }
.timeline__year { color: var(--ink-soft); font-size: var(--text-small); line-height: 1.7; }
.timeline li p { margin: 0; }

/* ---------- about story ---------- */
/* lede typography: the story reads like a letter — one size up, tall leading,
   a real pause between beats, ~34em measure */
.about-desk .entry { max-width: 34em; }
.about-desk .entry p {
	font-size: 1.1875rem;
	line-height: 1.75;
}
.about-desk .entry p + p { margin-top: var(--space-5); }

/* the desk itself: the dotted-paper texture (pricing-desk's move), so the
   props sit on something and the story band stops being flat gray */
.about-desk {
	position: relative;
	background-color: var(--band);
	background-image: radial-gradient(color-mix(in srgb, var(--ink) 13%, transparent) 1px, transparent 1.3px);
	background-size: 28px 28px;
}

/* desk props — decoration at the section edges, gone before they can crowd */
.about-desk__prop { position: absolute; z-index: 2; }
.about-desk__prop--kaomoji { right: 7%; top: 22%; }
.about-desk__prop--folder { left: 4%; top: 30%; }
.about-desk__prop--trash { right: 3.5%; bottom: 12%; }
@media (max-width: 1200px) { .about-desk__prop { display: none; } }

/* prose beside the founder.jpg window; 224px source shown at exactly its own
   size inside the window — grayscale reads editorial, not underexposed */
.story-grid {
	display: grid;
	grid-template-columns: 1fr 240px;
	gap: var(--space-7);
	align-items: start;
}
.story-side { display: grid; gap: var(--space-6); justify-items: center; }
.story-side .admin-frame { width: 100%; }
.story-side .admin-frame__media img { filter: grayscale(1) contrast(1.05); }
.story-note { transform: rotate(-2deg); }
@media (max-width: 760px) {
	.story-grid { grid-template-columns: 1fr; }
	.story-side { justify-items: start; max-width: 240px; }
}

/* section separators: the dotted hairline, contained (not full-bleed) */
.about-sep > .container { border-top: 1px dotted var(--line-strong); padding-top: var(--space-7); }

/* ---------- faq: the telegram treatment ---------- */
/* a real messaging window: narrower than the prose column, floated on the
   page's painting (same anatomy as every other window), with the classic
   messenger doodle wallpaper inside the chat. */
.faq-window { max-width: 680px; margin-inline: auto; }

/* the canvas under the window — showcase__stage's recipe at FAQ scale */
.faq-stage {
	border-radius: var(--r-canvas);
	/* no overflow:hidden — the floating props hang OUTSIDE the canvas; the
	   background still respects the radius on its own */
	padding: clamp(1rem, 2.5vw, 1.75rem);
	background-size: cover;
	background-position: center 30%;
	background-color: var(--band); /* fallback until the painting loads */
}

/* chat body: accent-tinted paper (telegram's move — the tint follows the
   page accent), with a hand-drawn doodle tile. The tile is an alpha-only SVG
   mask (keyword 'black', zero hex) colored via color-mix on --ink, so the
   pattern always matches the theme and costs no asset request. */
.faq-chat { position: relative; background: color-mix(in srgb, var(--accent) 6%, var(--surface)); }
.faq-chat::before {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-color: color-mix(in srgb, var(--ink) 8%, transparent);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'%3E%3Cg fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M30 48c-6-8-14-10-14-18a8 8 0 0 1 14-5a8 8 0 0 1 14 5c0 8-8 10-14 18z'/%3E%3Cpath d='M150 18l4 9 10 1-7 7 2 10-9-5-9 5 2-10-7-7 10-1z' transform='rotate(12 150 30)'/%3E%3Cpath d='M50 152l38-16-11 34-8-11-19-7z' transform='rotate(-8 66 160)'/%3E%3Cpath d='M182 116h16v9a8 8 0 0 1-16 0zM186 116v-8M194 116v-8M190 133v9' transform='rotate(15 190 124)'/%3E%3Cpath d='M96 192h28a6 6 0 0 1 6 6v10a6 6 0 0 1-6 6h-14l-8 7v-7h-6a6 6 0 0 1-6-6v-10a6 6 0 0 1 6-6z'/%3E%3Cpath d='M204 214l6 6 12-14'/%3E%3Cpath d='M104 78l-10 18h8l-6 16 16-20h-8l6-14z' transform='rotate(-10 102 94)'/%3E%3Ccircle cx='222' cy='52' r='4'/%3E%3Ccircle cx='18' cy='112' r='4'/%3E%3C/g%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'%3E%3Cg fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M30 48c-6-8-14-10-14-18a8 8 0 0 1 14-5a8 8 0 0 1 14 5c0 8-8 10-14 18z'/%3E%3Cpath d='M150 18l4 9 10 1-7 7 2 10-9-5-9 5 2-10-7-7 10-1z' transform='rotate(12 150 30)'/%3E%3Cpath d='M50 152l38-16-11 34-8-11-19-7z' transform='rotate(-8 66 160)'/%3E%3Cpath d='M182 116h16v9a8 8 0 0 1-16 0zM186 116v-8M194 116v-8M190 133v9' transform='rotate(15 190 124)'/%3E%3Cpath d='M96 192h28a6 6 0 0 1 6 6v10a6 6 0 0 1-6 6h-14l-8 7v-7h-6a6 6 0 0 1-6-6v-10a6 6 0 0 1 6-6z'/%3E%3Cpath d='M204 214l6 6 12-14'/%3E%3Cpath d='M104 78l-10 18h8l-6 16 16-20h-8l6-14z' transform='rotate(-10 102 94)'/%3E%3Ccircle cx='222' cy='52' r='4'/%3E%3Ccircle cx='18' cy='112' r='4'/%3E%3C/g%3E%3C/svg%3E");
	-webkit-mask-size: 240px;
	mask-size: 240px;
}
.faq-chat > * { position: relative; }
/* bubbles stay opaque paper on the tint — visitor bubble goes full white so
   the outgoing/incoming contrast reads like a real messenger */
.faq-chat__q span { background: var(--surface); }

/* floating eggs on the faq canvas — fahim's cursor and a note, drifting
   slowly (motion-safe); gone on small screens before they can crowd */
.faq-stage { position: relative; }
.faq-stage__prop { position: absolute; z-index: 2; }
/* props sit OUTSIDE the window, on the band beside the canvas */
.faq-stage__prop--cursor { left: -3.5rem; bottom: 10%; }
.faq-stage__prop--note { right: -4.5rem; top: 16%; transform: rotate(2deg); max-width: 110px; }
@media (prefers-reduced-motion: no-preference) {
	.faq-stage__prop { animation: pp-drift 7s ease-in-out infinite alternate; }
	.faq-stage__prop--note { animation-duration: 9s; animation-delay: 1.2s; }
}
@keyframes pp-drift { to { translate: 0 -12px; } }
@media (max-width: 900px) { .faq-stage__prop { display: none; } }

/* faq messenger eggs: the day chip, the presence line, and the composer —
   a message input that is really the mailto contact path */
.faq-chat__day {
	justify-self: center;
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--ink-soft);
	padding: 2px 12px;
	border-radius: 999px;
	background: color-mix(in srgb, var(--ink) 7%, transparent);
}
.faq-chat__presence {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin-left: calc(28px + var(--space-3)); /* clears the avatar column */
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--ink-soft);
}
.faq-chat__presence i {
	width: 7px; height: 7px;
	border-radius: 50%;
	background: var(--mac-green);
}
.faq-chat__composer {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-3);
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 999px;
	padding: var(--space-2) var(--space-2) var(--space-2) var(--space-5);
	color: var(--ink-soft);
	text-decoration: none;
	transition: border-color .12s ease;
}
.faq-chat__composer:hover { border-color: var(--line-strong); }
.faq-chat__composer b {
	display: grid;
	place-items: center;
	width: 28px; height: 28px;
	border-radius: 50%;
	background: var(--accent);
	color: var(--surface);
	font-weight: 600;
}

/* ---------- support: the compose window ---------- */
/* the mail To: line under the title bar — real recipient, mono artifact voice */
.compose-to {
	padding: var(--space-3) var(--space-6);
	border-bottom: 1px dotted var(--line-strong);
	font-size: var(--text-mono);
	color: var(--ink-soft);
	background: var(--surface);
}
.compose-to b { color: var(--ink); font-weight: 400; }
/* desk eggs beside the compose window (same contract as .faq-stage__prop) */
.support-stage__prop { position: absolute; z-index: 2; }
.support-stage__prop--folder { left: -3.5rem; bottom: 14%; }
.support-stage__prop--note { right: -4.5rem; top: 20%; transform: rotate(2deg); max-width: 120px; }
@media (prefers-reduced-motion: no-preference) {
	.support-stage__prop { animation: pp-drift 8s ease-in-out infinite alternate; }
	.support-stage__prop--note { animation-delay: 1s; }
}
@media (max-width: 900px) { .support-stage__prop { display: none; } }

/* optional marker on form labels — quiet, not a second label */
.field__optional { color: var(--ink-soft); font-weight: 400; font-size: var(--text-small); }

/* ---------- affiliates: the earnings window ---------- */
.earnings { max-width: 560px; margin-inline: auto; }
.earnings__body { padding: var(--space-4) var(--space-6) var(--space-5); }
.earnings__body p { margin: var(--space-3) 0 0; font-size: var(--text-small); color: var(--ink-soft); }

/* the application card: a short form reads cleaner narrow and centered */
.apply-card { max-width: 640px; margin-inline: auto; }
/* don't stretch the name input to match the email field's hint line */
.apply-card .field-row { align-items: start; }

/* checkbox row (affiliate terms tick): label flows inline beside the box */
.field--check label {
	display: flex;
	align-items: baseline;
	gap: var(--space-2);
	font-weight: 400;
	font-size: var(--text-small);
	color: var(--ink);
}
.field--check input[type='checkbox'] { width: auto; flex: 0 0 auto; accent-color: var(--blue); translate: 0 1px; }
.field--check a { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- mini window — the smallest mac window, for feature mocks ---------- */
.mini-window { background: var(--surface); }
.mini-window__bar {
	position: relative;
	display: flex;
	align-items: center;
	height: 28px;
	padding-inline: var(--space-3);
	/* white, same call as .admin-frame__bar (Fahim, 2026-08-25: "make bar
	   white"). It has to be here too: --surface-alt is the same #f5f5f5 as
	   the --band tile these sit on, so the grey bar vanished into the card
	   and left three lights floating with no window under them. */
	background: var(--surface);
	border-bottom: 1px solid var(--line);
}
.mini-window__bar .admin-frame__lights i { width: 7px; height: 7px; }
.mini-window__label {
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
	font-size: var(--text-micro);
	color: var(--ink-soft);
	white-space: nowrap;
}

/* ---------- liquid glass windows on canvases ---------- */
/* the contact form's compose window sitting ON the sky frosts it (Apple's
   liquid glass): translucent surface + backdrop blur/saturate, inner top
   highlight. Content stays opaque (inputs) so contrast never pays for the
   effect. Solid surface remains the no-backdrop-filter fallback. The FAQ
   chat window deliberately stays solid paper (Fahim, 2026-07-30), as do
   conversion surfaces (pricing tier bodies). */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.faq-stage .form-card {
		background: color-mix(in srgb, var(--surface) 72%, transparent);
		-webkit-backdrop-filter: blur(22px) saturate(1.5);
		backdrop-filter: blur(22px) saturate(1.5);
		border-color: color-mix(in srgb, var(--surface) 55%, transparent);
		box-shadow:
			inset 0 1px 0 color-mix(in srgb, var(--surface) 85%, transparent),
			var(--shadow-float);
	}
	/* the layers inside go translucent so the glass reads through */
	.faq-stage .form-card .admin-frame__bar { background: color-mix(in srgb, var(--surface-alt) 50%, transparent); }
	.faq-stage .compose-to { background: transparent; }
}

/* ---------- cookbook ----------
   Cards follow the house card: surface, --line hairline, --r-card, --space-6
   and --shadow-window. The first cut used none of the shadow and a tighter
   pad, which is exactly why it read as a wireframe next to the feature cards
   it sits two scroll-lengths away from.

   Index: a radio group whose labels are the tabs. The :has() selectors below
   are what actually filter — no script, so cards are filtered on first paint
   and stay filtered if JS never arrives. Every card is in the DOM regardless,
   which is what keeps the page crawlable. */
.cookbook-hero h1 { max-width: 18ch; }

.cookbook-filter > input[type='radio'] {
	position: absolute;
	opacity: 0;
	pointer-events: none;
}

.cookbook-filter__tabs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-bottom: var(--space-6);
}

.cookbook-filter__tabs label {
	display: inline-flex;
	align-items: center;
	gap: 0.45em;
	padding: 0.45rem 0.9rem;
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	background: var(--surface);
	color: var(--ink-soft);
	font-size: var(--text-small);
	cursor: pointer;
	transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out);
}

.cookbook-filter__tabs label:hover { border-color: var(--line-strong); }

/* Real data, so mono — the same rule the plugin cards and the release meta
   follow. */
.cookbook-filter__count {
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--ink-soft);
	opacity: 0.75;
}

/* Selected tab. One rule per category — verbose, but a filter that reads its
   own state is worth more than a clever selector nobody can debug. */
.cookbook-filter:has(#cookbook-cat-all:checked) label[for='cookbook-cat-all'],
.cookbook-filter:has(#cookbook-cat-building:checked) label[for='cookbook-cat-building'],
.cookbook-filter:has(#cookbook-cat-writing:checked) label[for='cookbook-cat-writing'],
.cookbook-filter:has(#cookbook-cat-fixing:checked) label[for='cookbook-cat-fixing'],
.cookbook-filter:has(#cookbook-cat-checking:checked) label[for='cookbook-cat-checking'],
.cookbook-filter:has(#cookbook-cat-teaching:checked) label[for='cookbook-cat-teaching'],
.cookbook-filter:has(#cookbook-cat-design:checked) label[for='cookbook-cat-design'],
.cookbook-filter:has(#cookbook-cat-settings:checked) label[for='cookbook-cat-settings'],
.cookbook-filter:has(#cookbook-cat-safety:checked) label[for='cookbook-cat-safety'] {
	border-color: var(--ink);
	color: var(--ink);
	background: var(--bg);
}

.cookbook-filter:has(#cookbook-cat-building:checked) .cookbook-card:not([data-cat='building']),
.cookbook-filter:has(#cookbook-cat-writing:checked) .cookbook-card:not([data-cat='writing']),
.cookbook-filter:has(#cookbook-cat-fixing:checked) .cookbook-card:not([data-cat='fixing']),
.cookbook-filter:has(#cookbook-cat-checking:checked) .cookbook-card:not([data-cat='checking']),
.cookbook-filter:has(#cookbook-cat-teaching:checked) .cookbook-card:not([data-cat='teaching']),
.cookbook-filter:has(#cookbook-cat-design:checked) .cookbook-card:not([data-cat='design']),
.cookbook-filter:has(#cookbook-cat-settings:checked) .cookbook-card:not([data-cat='settings']),
.cookbook-filter:has(#cookbook-cat-safety:checked) .cookbook-card:not([data-cat='safety']) {
	display: none;
}

.cookbook-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
	gap: var(--space-5);
}

.cookbook-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	padding: var(--space-6);
	box-shadow: var(--shadow-window);
	transition: transform .16s var(--ease-out), box-shadow .16s var(--ease-out),
		border-color .16s var(--ease-out);
}

/* The lift the pricing tiers already use, without their deliberate tilt —
   a cookbook grid is a list to scan, not a shelf of objects to pick up. */
.cookbook-card:hover {
	transform: translateY(-2px);
	border-color: var(--line-strong);
	box-shadow: var(--shadow-lift), var(--shadow-window);
}

.cookbook-card__meta {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-2);
}

.cookbook-card__cat,
.cookbook-card__pro {
	font-family: var(--font-mono);
	font-size: var(--text-label);
	letter-spacing: 0.02em;
	color: var(--ink-soft);
}

.cookbook-card__pro {
	color: var(--accent);
	border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
	border-radius: var(--r-inner);
	padding: 2px 7px;
}

.cookbook-card__title { margin: 0; font-size: var(--text-h3); line-height: 1.25; }

/* The whole card is the target, but the link stays the accessible name — the
   stretched pseudo-element is what makes the rest of it clickable without
   nesting anything inside the anchor. */
.cookbook-card__title a { color: var(--ink); text-decoration: none; }
.cookbook-card__title a::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
}
.cookbook-card:hover .cookbook-card__title a { text-decoration: underline; }

.cookbook-card__summary {
	margin: 0;
	color: var(--ink-soft);
	font-size: var(--text-small);
	line-height: 1.55;
}

.cookbook-card__facts {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin: auto 0 0;
	padding-top: var(--space-4);
	border-top: 1px solid var(--line);
	font-family: var(--font-mono);
	font-size: var(--text-micro);
	color: var(--ink-soft);
}

/* ---------- one recipe ---------- */
.recipe__breadcrumb {
	font-family: var(--font-mono);
	font-size: var(--text-label);
	color: var(--ink-soft);
	margin-bottom: var(--space-3);
}

.recipe__breadcrumb span { margin: 0 0.4em; opacity: 0.5; }
.recipe__lede { font-size: var(--text-article-lede); color: var(--ink-soft); line-height: 1.6; }

.entry .recipe__facts {
	display: flex;
	padding-left: 0;
	flex-wrap: wrap;
	gap: var(--space-5);
	padding: var(--space-4) var(--space-5);
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-card);
	box-shadow: var(--shadow-window);
	list-style: none;
	font-size: var(--text-small);
}

.entry .recipe__facts strong {
	display: block;
	font-family: var(--font-mono);
	font-size: var(--text-label);
	letter-spacing: 0.02em;
	color: var(--ink-soft);
	font-weight: 400;
	margin-bottom: 2px;
}

.recipe__hint { font-size: var(--text-small); color: var(--ink-soft); }

/* The prompt, in the site's own window chrome.
   .admin-frame__win on the element brings the surface, hairline, --r-window
   and --shadow-window with it, so this is the same object as every other mock
   on the site rather than a lookalike maintained twice. Only the body is
   described here. */
.entry .recipe__prompt { margin-block: var(--space-4) var(--space-7); }

.recipe__prompt-label {
	/* the bar is already mono at --text-label; this only stops the label
	   stretching and swallowing the lights */
	flex: 1;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.recipe__prompt-body { padding: var(--space-5) var(--space-6) var(--space-6); }

/* Mono, deliberately. The design plan is explicit that mono means real data,
   and a prompt is the literal string the reader is about to paste — there is
   nothing more literal on the page. In body sans it read as a pull quote,
   which is how a thing you copy stops looking copyable. */
.recipe__prompt pre {
	margin: 0;
	padding: 0;
	background: none;
	border: 0;
	white-space: pre-wrap;
	word-break: break-word;
	font-family: var(--font-mono);
	font-size: var(--text-small);
	line-height: 1.7;
	color: var(--ink);
}

/* Sans, for the same reason the prompt is mono: this is a control, not data.
   It was mono, which had the rule exactly backwards. */
.recipe__copy {
	margin-top: var(--space-5);
	padding: 0.45rem 0.9rem;
	border: 1px solid var(--line-strong);
	border-radius: var(--r-inner);
	background: var(--bg);
	color: var(--ink);
	font-family: inherit;
	font-size: var(--text-small);
	cursor: pointer;
	transition: border-color .12s var(--ease-out), background-color .12s var(--ease-out);
}

.recipe__copy:hover { border-color: var(--ink); background: var(--surface-alt); }

/* Tool names are real data — mono, and framed so they read as artifacts
   rather than prose. */
.entry .recipe__uses { list-style: none; padding-left: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.entry .recipe__uses li { margin: 0; }
.entry .recipe__uses code {
	display: inline-block;
	padding: 3px 9px;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-inner);
	font-size: var(--text-mono);
	color: var(--ink-soft);
}

/* keeps its markers — it is a list of links and reads as one */

.recipe__foot {
	display: flex;
	align-items: center;
	gap: var(--space-5);
	margin-top: var(--space-7);
	padding-top: var(--space-5);
	border-top: 1px solid var(--line);
}

/* ---------- relay — how it works (product pages with a 'bridge' key) ----------
   v3 (Fahim, 2026-08-24). v2 boxed this into a 40rem card that floated,
   small and lonely, in the middle of an otherwise-empty full-width section —
   called out as looking bad. v3 commits to the width instead of fighting
   it: the section wears the same dotted-desk texture as the pricing band
   (full-bleed, token-pure — the same background-image formula, so the two
   "textured desk" sections on this site actually match), the panel fills
   the container, and Saddle's real product mark rides a continuous accent
   rail at center instead of an abstract glyph.

   v4 (Fahim, 2026-08-25): "fit one screen", "visualation so they can
   undetantd easily", "use chat gpt logo", "section design too nice that we
   can use that as og image". v3 measured ~950px tall on a 1440x900 laptop,
   so its closing paragraph sat below the fold. Four changes, three of which
   delete text:

     - the panel is a POSTER, not a window. The mac bar and crumb are gone
       (-44px, and the visitor already passed two lit title bars in the hero
       alone), and the section heading moved inside the frame. A framed
       composition that carries its own title is what an OG image is, so the
       paddings here are tuned to land the panel near 1.91:1 at container
       width: crop it and you have og-saddle.png.
     - the body paragraph is gone (-160px). Its substance moved into the
       first FAQ answer, which is the only copy on this page that reaches
       JSON-LD. Three fact chips carry it visually here.
     - the app-name crossfade is gone, replaced by real client marks. Text
       that animates cannot be screenshotted, and this panel is meant to be.
     - the rail sat at top:42px inside a row that padded 64px, so it drew
       ABOVE the circles instead of through them (Fahim's arrow pointed
       straight at it). The row carries no padding of its own now, and every
       glyph centre lands on 36px, so the trace runs through all three.

   Net: ~640px including band padding. */
#how-it-works {
	position: relative;
	background-color: var(--band);
	background-image: radial-gradient(color-mix(in srgb, var(--ink) 13%, transparent) 1px, transparent 1.3px);
	background-size: 28px 28px;
	/* the one section on the site that does not pad --space-section. A poster
	   is sized to its frame and the frame here is the viewport, so this uses
	   the viewport-relative --space-hero: it gives back 100px on a laptop and
	   keeps giving on shorter screens, which is the whole point of the pass. */
	padding-block: var(--space-hero);
}
.relay {
	position: relative;
	overflow: hidden; /* the packets start and end past the stops; the frame clips them */
	background: var(--surface);
	border-radius: var(--r-card);
	box-shadow: 0 0 0 1px var(--line), var(--shadow-float);
	/* tuned, not declared: an aspect-ratio here would clip the row the moment a
	   note wraps to a third line. These paddings put the measured box at
	   ~1.9:1 at container width, which is the OG crop. */
	padding: clamp(var(--space-6), 4.5vw, 3.4375rem) clamp(var(--space-5), 4vw, var(--space-8));
}
.relay__head {
	text-align: center;
	margin-bottom: clamp(var(--space-6), 4vw, var(--space-7));
}
/* no .section-head here on purpose: its 34em cap is what wrapped this heading
   onto two lines (44px x 34em is 578px, the line wants 780px). Inside the
   panel there are 888px to spend, so it sits on one. */
.relay__head h2 { margin-bottom: 0; }
.relay__row {
	position: relative;
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--space-6);
	/* the lane the packets fly in. Without it a full sentence travelling the
	   rail lands on top of an 88px circle and reads as a collision, so the
	   command and the reply pass ABOVE the stops instead of through them. */
	padding-top: var(--relay-lane);
	/* the three column centres, shared by the rail, the packets and the
	   arrowheads so every travelling thing uses one geometry. NOT 100%/6: the
	   grid's gaps eat into the columns, so a sixth of the row lands 11px inside
	   each end glyph. Half a column is 100%/6 less a third of the gap. */
	--relay-lane: 46px;
	--relay-a: calc(100% / 6 - var(--space-6) / 3);
	--relay-b: 50%;
	--relay-c: calc(100% - (100% / 6 - var(--space-6) / 3));
}
/* the rail runs behind the three stops, centre to centre — a continuous
   trace, not a separate dashed segment per gap. The insets are the first and
   last column's own half-width, NOT 1/6 of the row: with a 3-column grid the
   gaps eat into the columns, so 100%/6 lands 11px inside each end glyph and
   the trace stops short of the circles it is supposed to run into. Half a
   column is 100%/6 less a third of the gap. top:35px is the 72px glyph's own
   centre less half the rail. */
.relay__rail {
	position: absolute;
	top: calc(var(--relay-lane) + 35px);
	left: var(--relay-a);
	right: var(--relay-a);
	height: 2px;
	border-radius: 1px;
	background: linear-gradient(
		90deg,
		var(--line-strong) 0%,
		color-mix(in srgb, var(--accent) 65%, var(--line-strong)) 50%,
		var(--line-strong) 100%
	);
}
/* arrowheads at the two hop midpoints. The travelling pulse showed direction
   before, which meant direction disappeared under reduced motion and in every
   screenshot — including the OG one. These are static and say the same thing. */
.relay__rail::before,
.relay__rail::after {
	content: '';
	position: absolute;
	top: 50%;
	width: 0;
	height: 0;
	translate: -50% -50%;
	border-top: 5px solid transparent;
	border-bottom: 5px solid transparent;
	border-left: 7px solid color-mix(in srgb, var(--accent) 45%, var(--line-strong));
}
.relay__rail::before { left: 25%; }
.relay__rail::after  { left: 75%; }
/* dotted rails between the columns — the same "frame it with dots" move as
   specs-rail and the pricing tiers, so the extra width reads as three
   deliberate bays instead of icons stranded in empty space. */
.relay__stop + .relay__stop { position: relative; }
.relay__stop + .relay__stop::before {
	content: '';
	position: absolute;
	top: 6px; /* the stop's own box already starts below the packet lane */
	bottom: 0;
	left: calc(var(--space-6) / -2);
	border-left: 1px dotted var(--line-strong);
}
.relay__pulse {
	position: absolute;
	top: -3px;
	left: 0;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--accent);
	box-shadow: 0 0 8px 1px color-mix(in srgb, var(--accent) 70%, transparent);
	opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
	.relay__pulse { animation: relay-travel 3.2s ease-in-out infinite; }
}
@keyframes relay-travel {
	0%   { left: 0; opacity: 0; }
	8%   { opacity: 1; }
	92%  { opacity: 1; }
	100% { left: calc(100% - 8px); opacity: 0; }
}
.relay__stop {
	position: relative;
	z-index: 1; /* sits over the rail, so the trace reads as running into it */
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: var(--space-1);
}
.relay__glyph {
	display: grid;
	place-items: center;
	width: 72px;
	height: 72px;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 50%;
	box-shadow: var(--shadow-window);
	color: var(--ink-soft);
}
.relay__glyph--lead {
	width: 88px;
	height: 88px;
	margin-top: -8px; /* keeps its centre on 36px despite the size jump */
	background: var(--accent);
	border-color: transparent;
	box-shadow: var(--shadow-window), 0 0 0 10px color-mix(in srgb, var(--accent) 13%, transparent);
}
/* the product mark, painted in --on-accent via mask instead of an <img> —
   the source SVG is a flat fill="black" mark, right everywhere else it's
   used (light chips), wrong here (Saddle's own #171717 accent badge would
   put black on near-black). Masking lets the badge paint it instead, so it
   stays readable against whatever accent a future product sets. */
.relay__mark {
	display: block;
	width: 34px;
	height: 34px;
	background-color: var(--on-accent);
	-webkit-mask-image: var(--mark);
	mask-image: var(--mark);
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
}
@media (prefers-reduced-motion: no-preference) {
	.relay__glyph--lead { animation: relay-glow 2.6s ease-in-out infinite; }
}
@keyframes relay-glow {
	0%, 100% { box-shadow: var(--shadow-window), 0 0 0 10px color-mix(in srgb, var(--accent) 13%, transparent); }
	50%      { box-shadow: var(--shadow-window), 0 0 0 16px color-mix(in srgb, var(--accent) 22%, transparent); }
}
/* the "your AI app" stop — three real client marks fanned like a group of
   avatars, replacing v3's cycling app names. Three overlapping circles say
   "any of these, whichever you already use" in one glance and, unlike text
   on a 3.6s loop, they are still there in a screenshot. The stop carries no
   outer circle of its own: the fan IS the glyph, sized so its centres land
   on the same 36px line as the other two. */
.relay__glyph--fan {
	display: flex;
	align-items: center;
	justify-content: center;
	width: auto;
	height: 72px;
	background: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
}
.relay__logos { display: flex; align-items: center; }
.relay__logo {
	display: block;
	width: 48px;
	height: 48px;
	border-radius: 50%;
	border: 1px solid var(--line);
	background-color: var(--surface);
	box-shadow: var(--shadow-window);
}
/* the mark is a mask over --ink, not an <img>: the source files are flat
   black, and pure #000 beside this page's #171717 text reads as three hard
   stamps. Masked, the trio sits as one quiet object. */
.relay__logo::after {
	content: '';
	display: block;
	width: 22px;
	height: 22px;
	margin: 12px;
	background-color: var(--ink);
	-webkit-mask-image: var(--mark);
	mask-image: var(--mark);
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
}
.relay__logo + .relay__logo { margin-left: -16px; }
/* the "WordPress" stop — an abstract mini window (bar + blank body), not a
   circled letter or the WordPress mark */
.relay__win {
	display: block;
	width: 34px;
	height: 26px;
	border: 1.5px solid currentColor;
	border-radius: 6px;
	overflow: hidden;
}
.relay__win-bar { display: block; height: 7px; background: currentColor; opacity: .4; }
.relay__label { margin-top: var(--space-3); font-size: var(--text-lg); }
.relay__note {
	font-size: var(--text-small);
	color: var(--ink-soft);
	max-width: 16rem;
}
/* the fact chips — what the five-sentence paragraph used to say, as three
   things you read in a glance. Fill, no border (one or the other, never
   both), and sans not mono: mono on this site is the artifact voice, kept
   for filenames, versions and counts. */
.relay__facts {
	list-style: none;
	margin: clamp(var(--space-6), 4vw, var(--space-7)) 0 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-3);
}
.relay__fact {
	padding: 9px 18px;
	border-radius: var(--r-inner);
	background: var(--surface-alt);
	font-size: var(--text-small);
	color: var(--ink);
}
/* every section ends knowing what to do next. Outside the panel, so the
   poster crops clean without it. */
.relay__next { margin: var(--space-6) 0 0; text-align: center; }
.relay__link { display: inline-flex; align-items: baseline; gap: 0.45em; font-weight: 500; color: var(--ink); }
.relay__link span { transition: translate .15s var(--ease-out); }
.relay__link:hover { text-decoration: none; color: var(--accent); }
.relay__link:hover span { translate: 3px 0; }
/* ---------- the exchange (v5) ----------
   Fahim, 2026-08-25: "it like they send command also system reply", "make
   more intutive, add some ester eggs, intracive and creative". The row stops
   being a picture of a pipeline and becomes one. A real command leaves the
   AI-app stop, Saddle takes it, the site builds, and a real reply comes
   back. It plays itself once when the section first enters the viewport
   (site.js), which is the whole discoverability plan: no "click to run"
   label on a section this pass just stripped text from. After that the
   badge is a button.

   Everything here rides the --relay-a/b/c geometry declared on .relay__row,
   so the packets stop exactly where the rail ends and the glyphs sit, at
   every width, with nothing measured in JS. */
.relay__packet {
	position: absolute;
	top: 0;
	left: var(--relay-a);
	translate: -50% 0;
	padding: 5px 12px;
	border-radius: var(--r-inner);
	background: var(--surface-alt);
	color: var(--ink);
	line-height: 1.5;
	white-space: nowrap;
	opacity: 0;
	pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
	.relay.is-sending .relay__packet--out  { animation: relay-out 1.9s var(--ease-out) both; }
	.relay.is-replying .relay__packet--back { animation: relay-back 1.1s var(--ease-out) both; }
	.relay.is-reading .relay__packet--read  { animation: relay-back 1.4s var(--ease-out) both; }
}
/* out: your app to Saddle, a beat while it checks, then on to the site */
@keyframes relay-out {
	0%       { left: var(--relay-a); opacity: 0; scale: .96; }
	10%      { opacity: 1; scale: 1; }
	34%, 56% { left: var(--relay-b); opacity: 1; }
	94%      { left: var(--relay-c); opacity: 1; }
	100%     { left: var(--relay-c); opacity: 0; }
}
/* back: the reply, and the egg's read pass, both travel the same way home */
@keyframes relay-back {
	0%   { left: var(--relay-c); opacity: 0; scale: .96; }
	12%  { opacity: 1; scale: 1; }
	88%  { left: var(--relay-a); opacity: 1; }
	100% { left: var(--relay-a); opacity: 0; }
}
/* the badge is a real button now: tabbable, Enter and Space for free, and
   the only labelled thing in a row that is otherwise all decoration. */
.relay__go {
	padding: 0;
	font: inherit;
	color: inherit;
	appearance: none;
	-webkit-appearance: none;
	cursor: pointer;
}
/* the global :focus-visible sets border-radius:2px, which would square off a
   circular button while it is focused. */
.relay__go:focus-visible { border-radius: 50%; outline-offset: 4px; }
@media (prefers-reduced-motion: no-preference) {
	.relay__go { transition: scale .18s var(--ease-out); }
	/* relay-glow already owns box-shadow on this element, so the working state
	   speaks in scale instead of fighting the animation for the same property */
	.relay.is-working .relay__go { scale: 1.06; }
	.relay__go:active { scale: .97; transition-duration: .07s; }
	.relay__go.is-drop { scale: 1.1; }
}
/* the site fills in: bar first, then three lines of content, and it stays
   built. The change landing IS the point, so this is a state, not motion —
   it survives prefers-reduced-motion as an instant fill. */
.relay__win-body { display: grid; gap: 3px; padding: 3px 4px 0; }
.relay__win-body i {
	display: block;
	height: 2px;
	border-radius: 1px;
	background: currentColor;
	opacity: 0;
	transition: opacity .3s ease;
}
.relay__win-body i:nth-child(1) { width: 100%; }
.relay__win-body i:nth-child(2) { width: 72%; }
.relay__win-body i:nth-child(3) { width: 88%; }
.relay__win.is-built i { opacity: .5; }
.relay__win.is-built i:nth-child(2) { transition-delay: .08s; }
.relay__win.is-built i:nth-child(3) { transition-delay: .16s; }
/* the fan opens under the pointer: three marks overlapping read as "some
   apps", three separated read as "any of these". Same 2px-and-a-nudge
   movement budget the cards and arrow links keep. */
@media (prefers-reduced-motion: no-preference) {
	.relay__logo { transition: translate .2s var(--ease-out), rotate .2s var(--ease-out); }
	.relay__logos:hover .relay__logo:first-child { translate: -7px 0; rotate: -6deg; }
	.relay__logos:hover .relay__logo:last-child  { translate: 7px 0; rotate: 6deg; }
	.relay__glyph { transition: translate .2s var(--ease-out); }
	.relay__stop:hover .relay__glyph:not(.relay__glyph--lead) { translate: 0 -2px; }
}
/* hovering a stop lights the stretch of line that belongs to it, so the
   diagram answers "which part is mine" without a word of copy. Nested :has()
   so the whole stop is the target, not just its glyph; where :has() is
   missing nothing happens, which is a fine resting state. */
.relay__rail::before,
.relay__rail::after { transition: border-left-color .15s ease, scale .15s var(--ease-out); }
.relay__row:has(.relay__stop:hover:has(.relay__glyph--fan)) .relay__rail::before,
.relay__row:has(.relay__stop--lead:hover) .relay__rail::before,
.relay__row:has(.relay__stop--lead:hover) .relay__rail::after,
.relay__row:has(.relay__stop:hover:has(.relay__win)) .relay__rail::after {
	border-left-color: var(--accent);
	scale: 1.25;
}
/* the egg: press the badge three times and the exchange runs the other way,
   then this peels on. It is the read-only default told as a joke you have to
   find, in the desk-prop vocabulary the rest of the site already speaks. */
/* .prop sets display:inline-flex, which beats the UA's [hidden]{display:none}
   — without this the egg ships visible instead of hiding until it is earned */
.relay__egg[hidden] { display: none; }
.relay__egg {
	position: absolute;
	right: clamp(var(--space-5), 4vw, var(--space-7));
	bottom: clamp(var(--space-5), 4vw, var(--space-7));
	max-width: 140px;
	text-align: center;
}
@media (prefers-reduced-motion: no-preference) {
	.relay__egg { animation: relay-peel .35s var(--ease-out) both; }
}
/* no `to` — it lands on .prop--note's own resting -2deg */
@keyframes relay-peel {
	from { opacity: 0; translate: 0 10px; rotate: 5deg; }
}
@media (max-width: 720px) {
	.relay { padding: var(--space-7) var(--space-5); }
	.relay__row { grid-template-columns: 1fr; gap: var(--space-7); padding-top: 0; }
	/* stacked, there is no line for a packet to travel and no corner for the
	   note to peel into. The badge still runs, and the site still builds. */
	.relay__packet, .relay__egg { display: none; }
	/* three peers stacked, so the horizontal rail/pulse/arrowheads (a
	   between-columns device) and the dotted column rails stop making sense —
	   hide both rather than contort them into a vertical line the v1 mobile
	   fallback already tried and this section moved away from. */
	.relay__rail, .relay__stop + .relay__stop::before { display: none; }
	.relay__note { max-width: 22rem; }
}
@media (max-width: 420px) {
	.relay__glyph { width: 64px; height: 64px; }
	.relay__glyph--lead { width: 78px; height: 78px; margin-top: 0; }
	.relay__glyph--fan { width: auto; height: 64px; }
	.relay__mark { width: 30px; height: 30px; }
	.relay__logo { width: 42px; height: 42px; }
	.relay__logo::after { width: 20px; height: 20px; margin: 10px; }
	.relay__logo + .relay__logo { margin-left: -14px; }
}
