/* Sleeves Up: the data driven blocks.
 *
 * Two bands on the front page stopped being hand written HTML on 2026-09-09:
 * the product grid, which is now a core query loop over the children of the
 * `courses` and `books` pages, and the community band, whose panel now lists
 * real forum threads from [su_forum_activity].
 *
 * Everything those two need lives here rather than in site.css, which owns the
 * brand layer: type scale, bands, cards, forms. Nothing in this file introduces
 * a size. Kicker 0.875rem, small 0.9375rem, body 1.0625rem and card heading
 * 1.25rem are the whole scale, they are declared in theme.json, and the rules
 * below only ever reference the presets.
 */

/* ---- Product grid ----
 *
 * The band has to look deliberate at two products and at ten, which rules out
 * the two hard coded columns it replaced.
 *
 * It is flex rather than grid on purpose. `repeat(auto-fill, minmax(...))`
 * leaves empty tracks, and `auto-fit` still strands the last card alone in a
 * row of three when there are four of them. Both break the one rule the band
 * system has: no band may leave a third of its width visually empty at 1440px
 * (site/IA.md). Flex items grow into the space instead, so EVERY row is full at
 * every count. Three cards fill a row; a fourth would be a wide card on its own
 * row, which is a shape, not a gap.
 *
 * The 22rem basis is what decides the column count: at the 1200px band that is
 * three per row, and below roughly 800px it becomes two, then one.
 */
.su-product-grid .wp-block-post-template {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--40);
	margin: 0;
	padding: 0;
	list-style: none;
}
.su-product-grid .wp-block-post-template > li {
	display: flex;
	flex: 1 1 22rem;
	/* Without this the basis is a floor and the card overflows a 390px screen. */
	min-width: 0;
	margin-block: 0;
}

/* Counts that would otherwise leave one card alone behind a full row of three
 * (4, 7, 10 ...) drop to two per row, so four reads as two by two. Browsers
 * without :has() fall back to the rule above, which still fills every row. */
.su-product-grid .wp-block-post-template:has(> :nth-child(3n + 1):last-child) > li {
	flex-basis: calc(50% - (var(--wp--preset--spacing--40) / 2));
}

/* Equal height is the flex row's doing. This makes the card fill the row's
 * height rather than sitting at its own, and stacks its parts so the button can
 * be pinned to the bottom edge whatever the excerpt length. */
.su-product-card {
	display: flex;
	flex-direction: column;
	width: 100%;
}
.su-product-card > .wp-block-post-excerpt {
	margin-block-end: 1.75rem;
}
.su-product-card > .wp-block-read-more {
	margin-block-start: auto;
}

/* The title is the card's link. Card headings are never teal underlined body
 * links, so it takes the card's own colour and earns an underline on hover. */
.su-product-card .wp-block-post-title {
	margin-block-end: 0;
}
.su-product-card .wp-block-post-title a {
	color: inherit;
	text-decoration: none;
}
.su-product-card .wp-block-post-title a:hover,
.su-product-card .wp-block-post-title a:focus {
	color: var(--wp--preset--color--accent-2);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* post-terms renders a div, so the `.su-kicker + h3` rhythm rule in site.css,
 * which is an adjacent sibling selector, still applies. Only the block's own
 * default margins need clearing. */
.su-product-card .wp-block-post-terms {
	margin-block: 0 0.75rem;
}

/* The card call to action is core/read-more, because the link has to come from
 * the queried page rather than from typed markup. It carries wp-element-button
 * in its class list, so it inherits the button treatment from theme.json and
 * cannot drift away from every other button on the site. */
.su-product-card .su-card-cta {
	display: inline-block;
	width: fit-content;
}

/* ---- Activity lists ----
 * The two panels of the live activity band on /: [su_blog_activity] on the left
 * and [su_forum_activity] on the right. They MUST share one rhythm, because the
 * owner's note that started this rebuild was that the band's two halves did not
 * balance, so every rule below is written for both class families at once. Add
 * a rule to one and you have reintroduced the problem.
 *
 * .su-thread* is the forum's, .su-feed* is the blog's. Sizes are the small and
 * medium presets; nothing new. A title is medium, 17px, the same 17px the forum
 * threads have always used. */
.su-thread-list,
.su-feed-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.su-thread + .su-thread,
.su-feed + .su-feed {
	margin-top: 0.9rem;
	padding-top: 0.9rem;
	border-top: 1px solid var(--wp--preset--color--border-light);
}
.su-thread__title,
.su-feed__title {
	display: block;
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
	line-height: 1.4;
	color: var(--wp--preset--color--accent-2);
	text-decoration: none;
}
.su-thread__title:hover,
.su-thread__title:focus,
.su-feed__title:hover,
.su-feed__title:focus {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}
/* .su-muted only carries a colour on dark bands, and this list sits on an ivory
   panel, so the meta line takes the ivory muted tone. The .su-dark rule in
   site.css is the more specific selector and still wins if the band ever flips. */
.su-thread__meta,
.su-feed__meta {
	display: block;
	margin-top: 0.25rem;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--accent-4);
}
.su-thread__sep,
.su-feed__sep {
	padding: 0 0.15rem;
}
.su-dark .su-thread + .su-thread,
.su-dark .su-feed + .su-feed {
	border-top-color: var(--wp--preset--color--border-dark);
}
.su-dark .su-thread__title,
.su-dark .su-feed__title {
	color: var(--wp--preset--color--accent-1);
}


/* ---- Live activity band ----
 * The band on / that carries the blog on the left and the forum on the right.
 *
 * THE WHOLE POINT IS THAT THE TWO PANELS ARE EQUAL CITIZENS. They are 50/50
 * columns with identical padding, ground and hairline, so the only thing that
 * could unbalance them is content height. Two rules handle that:
 *
 *   1. the columns are stretch aligned, so both panel boxes are the height of
 *      the taller one, whichever side that is on the day;
 *   2. each panel is a flex column and its button is pushed to the bottom of
 *      that box, so the two buttons sit on one line instead of one floating in
 *      the middle of a half empty panel.
 *
 * That holds in both of the blog's states, which is the case this was built
 * for: the blog has no posts yet, so the left panel renders a composed empty
 * state rather than a list, and it still has to stand beside four live threads.
 */
.su-activity-panel {
	display: flex;
	flex-direction: column;
}

/* margin-top: auto is what does the bottom alignment; it also replaces the
   column's 0.9rem blockGap above this element, hence the padding, which is the
   minimum air the button gets when the panel is exactly content height. */
.su-activity-panel > .su-feed__cta {
	margin-top: auto;
	padding-top: 1.5rem;
}

/* The empty state's heading. Large is the panel heading size the whole site
   uses, 20px; this is not a new step on the scale. */
/* The kicker's own margin-bottom and the `.su-kicker + h3` rule in site.css set
   the space above this; everything below it takes the panel's 0.9rem rhythm, the
   same rhythm the threads opposite are on. No measure cap: the paragraph fills
   the panel exactly as a thread title does, and a 46ch cap here would leave the
   left panel's own right-hand quarter empty, which is the shape of the complaint
   this band was rebuilt to answer. */
.su-feed-empty__title {
	margin-block: 0;
	line-height: 1.3;
}
.su-feed-empty__body {
	margin-block: 0.9rem 0;
}

/* Core stacks columns below 782px on its own. All that is left is to stop the
   bottom alignment from opening a gap inside a stacked panel, where there is no
   taller neighbour to align to. */
@media (max-width: 781px) {
	.su-activity-panel {
		display: block;
	}
}

/* =========================================================================
   BLOG: index, sidebar, post cards, pagination, single post, comments
   Written 2026-09-09 after his blog review. The templates were built by an
   agent that died mid-run when the machine slept; this is the stylesheet
   half, matched to the classes those templates actually emit.
   ========================================================================= */

/* ---- Index layout ---- */
.su-blog-layout {
	gap: var(--wp--preset--spacing--70);
}
.su-blog-main {
	min-width: 0; /* a grid/flex child will not shrink below content without this */
}

/* The sidebar sticks while the list scrolls. `align-self: start` is what makes
   sticky work inside a flex row: the default `stretch` makes the column as tall
   as the list, so there is nothing left to stick against and it silently does
   nothing. This is the usual reason a sticky sidebar "does not work". */
.su-blog-side {
	min-width: 0;
	align-self: start;
	position: sticky;
	top: 2rem;
}

/* ---- Post cards ---- */
.su-post-list {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50);
}
.su-post-card {
	display: grid;
	grid-template-columns: 13rem 1fr;
	gap: var(--wp--preset--spacing--40);
	align-items: start;
	padding-bottom: var(--wp--preset--spacing--50);
	border-bottom: 1px solid var(--wp--preset--color--border-light);
}
.su-post-list > *:last-child .su-post-card,
.su-post-card:last-child {
	border-bottom: 0;
}

/* Most posts will have no featured image, and a card that only works WITH one is
   a card that breaks on the day he publishes without one. The media column is
   dropped entirely when the block renders nothing, so the text takes the full
   width instead of sitting beside an empty rectangle. */
.su-post-card:not(:has(.su-post-media img)) {
	grid-template-columns: 1fr;
}
.su-post-card:not(:has(.su-post-media img)) .su-post-media {
	display: none;
}
.su-post-media img {
	display: block;
	width: 100%;
	height: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border: 1px solid var(--wp--preset--color--border-light);
}
.su-post-card .wp-block-post-title {
	margin: 0.35rem 0 0.5rem;
}
.su-post-card .wp-block-post-title a {
	text-decoration: none;
	border-bottom: 1px solid transparent;
}
.su-post-card .wp-block-post-title a:hover,
.su-post-card .wp-block-post-title a:focus {
	border-bottom-color: currentColor;
}
.su-post-card .wp-block-post-date {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--accent-4);
}
.su-post-card .wp-block-post-excerpt__more-link {
	display: inline-block;
	margin-top: 0.6rem;
	font-family: var(--wp--preset--font-family--montserrat);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	border-bottom: 1px solid currentColor;
}

/* ---- Pagination ---- */
.su-pagination {
	margin-top: var(--wp--preset--spacing--60);
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid var(--wp--preset--color--border-light);
	font-family: var(--wp--preset--font-family--montserrat);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
}
.su-pagination a {
	text-decoration: none;
	border-bottom: 1px solid transparent;
}
.su-pagination a:hover,
.su-pagination a:focus {
	border-bottom-color: currentColor;
}
.su-pagination .page-numbers.current {
	color: var(--wp--preset--color--accent-2);
}

/* ---- Single post ---- */
.su-post-hero .su-post-h1 {
	max-width: 22ch;
}
.su-article .su-post-body {
	max-width: 68ch;
}
.su-article .su-post-body > * {
	margin-block: 1.15em 0;
}
.su-article .su-post-body h2,
.su-article .su-post-body h3 {
	margin-block-start: 2em;
}
.su-article .wp-block-post-featured-image img {
	width: 100%;
	height: auto;
	border: 1px solid var(--wp--preset--color--border-light);
}

/* ---- Comments ---- */
.su-comments {
	margin-top: var(--wp--preset--spacing--70);
	padding-top: var(--wp--preset--spacing--60);
	border-top: 1px solid var(--wp--preset--color--border-light);
	max-width: 68ch;
}
.su-comment {
	padding: var(--wp--preset--spacing--40) 0;
	border-bottom: 1px solid var(--wp--preset--color--border-light);
}
.su-comment-author {
	font-family: var(--wp--preset--font-family--montserrat);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
}
.su-comment-date,
.su-comment-actions {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--accent-4);
}
.su-comment-avatar img {
	border-radius: 50%;
}
.su-comment-form {
	margin-top: var(--wp--preset--spacing--50);
	max-width: 68ch;
}
/* The comment form is core markup, not our .su-form, so it needs the same control
   treatment spelled out or it renders as raw browser widgets next to our styled
   ones. Same tokens as .su-form in site.css. */
.su-comment-form input[type="text"],
.su-comment-form input[type="email"],
.su-comment-form input[type="url"],
.su-comment-form textarea {
	width: 100%;
	padding: 0.9rem 1rem;
	font-size: var(--wp--preset--font-size--medium);
	font-family: inherit;
	color: var(--wp--preset--color--contrast);
	background-color: var(--wp--preset--color--base);
	border: 2px solid var(--wp--preset--color--border-dark);
	border-radius: 2px;
}
.su-comment-form textarea {
	resize: vertical;
	line-height: 1.55;
}
.su-comment-form input:focus,
.su-comment-form textarea:focus {
	outline: 2px solid var(--wp--preset--color--accent-1);
	outline-offset: 2px;
}
.su-comment-form .wp-block-post-comments-form input[type="submit"],
.su-comment-form input[type="submit"] {
	padding: 0.9rem 1.6rem;
	font-family: var(--wp--preset--font-family--montserrat);
	font-weight: 700;
	color: var(--wp--preset--color--base);
	background-color: var(--wp--preset--color--accent-2);
	border: 0;
	border-radius: 2px;
	cursor: pointer;
}

/* ---- Mobile ----
   Below the block editor's own 782px stacking point the sidebar sits UNDER the
   list, so sticky would pin the signup to the bottom of a scrolled page and
   follow the reader around. Turn it off, and let the cards go full width. */
@media (max-width: 781px) {
	.su-blog-side {
		position: static;
		top: auto;
	}
	.su-post-card {
		grid-template-columns: 1fr;
	}
	.su-post-media img {
		aspect-ratio: 16 / 9;
	}
}

/* The post header is no longer a dark slab (his review: "on individual post this is too
   loud"). It sits on the page ground, so the only thing separating it from the body is
   space and the measure cap on the title. */
.su-post-head + .su-section {
	border-top: 0;
}

/* The featured image sat flush against the first line of the post. The block carries no
   bottom margin of its own and the body band sets blockGap 0, so nothing was separating
   an image from the text it belongs to. */
.su-article .su-post-hero,
.su-post-hero {
	margin-bottom: var(--wp--preset--spacing--50);
}
.su-article .su-post-hero img {
	display: block;
}

/* ---- Related posts, under a single post ---- */
.su-related {
	margin-top: var(--wp--preset--spacing--70);
	padding-top: var(--wp--preset--spacing--50);
	border-top: 1px solid var(--wp--preset--color--border-light);
}
.su-related-list {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--wp--preset--spacing--40);
	margin: 1.25rem 0 0;
	padding: 0;
	list-style: none;
}
.su-related-item {
	margin: 0;
}
.su-related-media {
	display: block;
	margin-bottom: 0.75rem;
}
.su-related-media img {
	display: block;
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border: 1px solid var(--wp--preset--color--border-light);
}
.su-related-date {
	margin: 0 0 0.3rem;
	font-family: var(--wp--preset--font-family--montserrat);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--kicker);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--accent-4);
}
.su-related-title {
	margin: 0;
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.25;
}
.su-related-title a {
	text-decoration: none;
	border-bottom: 1px solid transparent;
}
.su-related-title a:hover,
.su-related-title a:focus {
	border-bottom-color: currentColor;
}
@media (max-width: 781px) {
	.su-related-list {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--50);
	}
}

/* The price line sits under the buy button. Quiet on purpose: it is a fact the reader
   wants confirmed, not a claim that needs selling, and the real number lives on the
   storefront the button points at. */
.su-price {
	margin-top: 0.75rem;
	opacity: 0.85;
}

/* home: latest post card (2026-09-10) */
/* The left panel of the activity band on / stopped being a list of four titles
   and became ONE post as a card, so the band has a picture in it. Owner's note:
   "some small thumbnail of feature image on the home page blog section, that
   will just make home page look better", then, seeing it: the image and the
   title should take as much width as possible, and no button under the card.

   So: one column. Image across the panel at 16/9 (the post images are authored
   16/9, so nothing is shaved off), title full width so it stays on one line at
   desktop, meta, then the excerpt and "Read more". The hairline is the one
   .su-post-media already uses on /blog/. No image is the common case, not the
   broken one: the shortcode emits no media element then, and the column simply
   starts with the title. */
.su-latest-post {
	display: grid;
	grid-template-columns: 1fr;
	row-gap: 0.9rem; /* the panel's own rhythm, the one the threads opposite use */
	align-items: start;
}
.su-latest-post__head,
.su-latest-post__body {
	min-width: 0; /* a grid child will not shrink below its content without this */
}
.su-latest-post__media {
	display: block;
}
.su-latest-post__img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border: 1px solid var(--wp--preset--color--border-light);
}
.su-latest-post__title {
	margin: 0;
	/* 1.125rem, not the large preset: at the panel's 448px inner width the
	   large size splits a 43-character title onto two lines, and he wants it on
	   one. Measured 2026-09-10: 18px = 419px of text, 20px wraps. */
	font-size: 1.125rem;
	line-height: 1.3;
	text-wrap: balance;
}
.su-latest-post__title a {
	color: var(--wp--preset--color--accent-2);
	text-decoration: none;
	border-bottom: 1px solid transparent;
}
.su-latest-post__title a:hover,
.su-latest-post__title a:focus {
	border-bottom-color: currentColor;
}
/* Same meta treatment as the feed opposite: small, accent-4, so the two panels
   still read as one system now that one of them is a card. */
.su-latest-post__meta {
	margin: 0.35rem 0 0;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--accent-4);
}
.su-latest-post__excerpt {
	margin: 0; /* the grid's row-gap is the space above it */
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.5;
}
/* Lifted from .su-post-card .wp-block-post-excerpt__more-link so the "Read more"
   on the front page and the one on /blog/ are the same control. */
.su-latest-post__more {
	display: inline-block;
	margin-top: 0.6rem;
	font-family: var(--wp--preset--font-family--montserrat);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	border-bottom: 1px solid currentColor;
}
.su-dark .su-latest-post__title a {
	color: var(--wp--preset--color--accent-1);
}
.su-dark .su-latest-post__img {
	border-color: var(--wp--preset--color--border-dark);
}
/* end */

/* home: community feed (2026-09-10) */
/* The forum panel on / now lists MESSAGES, not threads: a name, a line of what
   that person said, and the thread it is in. It deliberately reuses .su-thread,
   .su-thread__title, .su-thread__meta and .su-thread__sep, so the hairline
   rhythm, the title weight and the meta type stay identical to the blog panel
   opposite. Only the two rules below are new, and neither introduces a size:
   the snippet is body copy, the thread link inherits the meta line it sits in. */
.su-msg__snippet {
	margin: 0.2rem 0 0;
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.5;
}
/* The link sits inside the small muted meta line, so it takes that line's
   colour rather than the link blue: the name and the snippet are already the
   most colour a four item panel can carry. It is still a link, which the
   underline on hover and focus says. */
.su-msg__thread {
	color: inherit;
	text-decoration: none;
}
.su-msg__thread:hover,
.su-msg__thread:focus {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}
/* end */

/* home: activity panel titles (2026-09-10) */
/* "Latest from the blog" and "Latest from the community" are the TITLES of their
   panels, not eyebrows above a heading, and at kicker size in teal they read as
   part of the body (his words: "they look like part of normal text, not the
   section heading"). So inside the two panels the kicker steps up: larger,
   heavier, in the text colour. No rule under it; he cut the teal lines on
   2026-09-09 and space does the separating here too. */
.su-activity-panel > .su-kicker {
	font-size: 1.125rem;
	font-weight: 800;
	letter-spacing: 0.12em;
	color: var(--wp--preset--color--contrast);
	margin-bottom: 1.25rem;
}
/* end */
