/*
Theme Name: ThinkStreamTV
Theme URI: https://blog.thinkstreamtv.com/
Description: TSV One - the ThinkStreamTV design system as a Twenty Twenty-Five child theme. Replaces the archive/search templates that rendered full article bodies, adds cluster-aware related posts, a table of contents, breadcrumbs, reading time and a dark/light toggle.
Author: ThinkStreamTV
Template: twentytwentyfive
Version: 1.0.0
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: thinkstreamtv
*/

/* TSV-SHARED:START tokens
   ==========================================================================
   TSV One design tokens.

   Dark is the default: it is the existing brand identity on the apex domain
   and it fits a developer audience. Both palettes below were contrast-checked;
   the ratios in the comments are measured, not estimated.

   The one rule that must never be broken: a label on --accent is --bg (dark),
   never white. White on #30c48d is 2.23:1 and fails WCAG outright, while
   #0e1726 on the same green is 8.04:1 (AAA).

   THIS REGION IS SHARED WITH thinkstreamtv.com. It is extracted verbatim into
   apex_site/src/styles/tsv-shell.css by scripts/build_apex_shell_css.py, and a
   test asserts the two are byte-identical. Edit it here and nowhere else: a
   token duplicated into a second file is a token the two hosts will eventually
   disagree about, which is exactly the "one product" property this exists to
   hold.
   ========================================================================== */

:root {
	--tsv-bg: #0e1726;
	--tsv-bg-alt: #111d2e;
	--tsv-bg-card: #182233;
	--tsv-bg-code: #0b1422;
	--tsv-text: #e6edf3;          /* 15.20:1 on --tsv-bg  AAA */
	--tsv-muted: #9fb0c0;         /*  8.08:1 on --tsv-bg  AAA */
	--tsv-accent: #30c48d;        /*  8.04:1 on --tsv-bg  AAA */
	--tsv-accent-ink: #30c48d;    /* accent used as text colour */
	--tsv-accent-2: #4ea1ff;      /*  6.73:1 on --tsv-bg  AA  */
	--tsv-on-accent: #0e1726;     /*  8.04:1 on --tsv-accent AAA */
	--tsv-border: rgba(255, 255, 255, .10);
	--tsv-border-strong: rgba(255, 255, 255, .18);
	--tsv-shadow: 0 8px 24px rgba(0, 0, 0, .35);

	--tsv-success: #30c48d;
	--tsv-warning: #e0a33e;
	--tsv-danger: #e5484d;
	--tsv-info: #4ea1ff;

	--tsv-font: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
	--tsv-font-mono: "Cascadia Code", "Fira Code", "SFMono-Regular", Consolas, monospace;

	--tsv-radius: 12px;
	--tsv-radius-sm: 8px;

	--tsv-max-w: 1200px;
	--tsv-max-w-post: 720px;

	--tsv-sp-1: 4px;
	--tsv-sp-2: 8px;
	--tsv-sp-3: 12px;
	--tsv-sp-4: 16px;
	--tsv-sp-5: 24px;
	--tsv-sp-6: 32px;
	--tsv-sp-8: 48px;
	--tsv-sp-10: 64px;
	--tsv-sp-12: 96px;

	color-scheme: dark;
}

[data-theme="light"] {
	--tsv-bg: #ffffff;
	--tsv-bg-alt: #f5f7fa;
	--tsv-bg-card: #f5f7fa;
	--tsv-bg-code: #0b1422;       /* code stays dark in both modes - it is a code surface, not chrome */
	--tsv-text: #16202c;          /* 16.44:1 on white  AAA */
	--tsv-muted: #53616f;         /*  6.35:1 on white  AA  */
	--tsv-accent: #30c48d;
	--tsv-accent-ink: #127a52;    /*  5.34:1 on white  AA - the accent is not readable as text on white */
	--tsv-accent-2: #0b5fbf;      /*  6.17:1 on white  AA  */
	--tsv-on-accent: #0e1726;
	--tsv-border: rgba(16, 32, 48, .12);
	--tsv-border-strong: rgba(16, 32, 48, .22);
	--tsv-shadow: 0 8px 24px rgba(16, 32, 48, .10);

	color-scheme: light;
}
/* TSV-SHARED:END tokens */

/* TSV-SHARED:START shell
   ==========================================================================
   The unified shell - header, navigation, footer, cards, topic rail, code
   affordances. Every selector here is host-agnostic on purpose: it names only
   `tsv-*` classes and no WordPress block class, so the identical stylesheet
   dresses the Astro apex and the WordPress blog. The WordPress-block-specific
   rules further down this file map core block markup onto these same visuals;
   they are NOT shared, because the apex has no block markup to map.

   Same extraction contract as the tokens above: edit here, never in
   apex_site/src/styles/tsv-shell.css.

   No shadows are used as an elevation primitive on chrome and no gradient
   anywhere: elevation is a border plus a surface tint, which is the only
   approach that reads in both polarities (a shadow system is near-invisible in
   the brand's default dark mode). --tsv-shadow appears solely as a hover
   affordance on an already-bordered card.
   ========================================================================== */

/* --- Layout container ---------------------------------------------------- */

/* Used by the apex, which has no block-layout system of its own. WordPress
   constrains the shell with its own `alignwide` layout instead, so this class
   simply does not appear in the WordPress markup - it is inert there, not
   conflicting. */
.tsv-shell-container {
	margin-inline: auto;
	max-width: var(--tsv-max-w);
	padding-inline: var(--tsv-sp-5);
	width: 100%;
}

/* --- Header ------------------------------------------------------------- */

.tsv-header {
	background-color: var(--tsv-bg);
	border-bottom: 1px solid var(--tsv-border);
	position: sticky;
	top: 0;
	z-index: 100;
}

.tsv-header a {
	color: var(--tsv-text);
	text-decoration: none;
}

.tsv-header a:hover {
	color: var(--tsv-accent-ink);
}

.tsv-header-row {
	align-items: center;
	display: flex;
	gap: var(--tsv-sp-5);
	justify-content: space-between;
}

/* --- Brand ------------------------------------------------------------- */

.tsv-brand-link {
	align-items: center;
	display: inline-flex;
	flex: 0 0 auto;
	gap: var(--tsv-sp-2);
	font-weight: 700;
	letter-spacing: -0.01em;
	text-decoration: none;
}

.tsv-mark {
	color: var(--tsv-accent);
	display: block;
	flex: 0 0 auto;
}

.tsv-wordmark {
	font-size: 1.0625rem;
	line-height: 1;
	white-space: nowrap;
}

/* --- Navigation --------------------------------------------------------- */

.tsv-nav {
	min-width: 0;
}

.tsv-nav-list {
	display: flex;
	gap: var(--tsv-sp-1);
	list-style: none;
	margin: 0;
	padding: 0;
}

.tsv-nav-list > li {
	margin: 0;
}

/* A 44px minimum target, per WCAG 2.5.8, without a JavaScript drawer: the row
   scrolls horizontally on a narrow viewport instead. A drawer would need a
   focus trap, an inert background and an escape handler to hide five links. */
.tsv-nav-list a {
	border-radius: var(--tsv-radius-sm);
	display: inline-flex;
	align-items: center;
	font-size: 0.9375rem;
	min-height: 44px;
	padding: 0 var(--tsv-sp-3);
	white-space: nowrap;
}

.tsv-nav-list a[aria-current="page"] {
	color: var(--tsv-accent-ink);
	text-decoration: underline;
	text-underline-offset: 6px;
	text-decoration-thickness: 2px;
}

.tsv-header-tools {
	align-items: center;
	display: flex;
	flex: 0 0 auto;
	gap: var(--tsv-sp-2);
}

/* --- Theme toggle + search control --------------------------------------- */

.tsv-theme-toggle,
.tsv-search-link {
	background: transparent;
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius-sm);
	color: var(--tsv-muted);
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding: 0 var(--tsv-sp-3);
	transition: color .15s ease, border-color .15s ease;
}

.tsv-theme-toggle:hover,
.tsv-search-link:hover {
	color: var(--tsv-text);
	border-color: var(--tsv-border-strong);
}

.tsv-theme-toggle svg {
	width: 20px;
	height: 20px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.5;
}

.tsv-theme-toggle .tsv-icon-sun { display: none; }
[data-theme="light"] .tsv-theme-toggle .tsv-icon-sun { display: block; }
[data-theme="light"] .tsv-theme-toggle .tsv-icon-moon { display: none; }

@media (max-width: 900px) {
	/* The nav drops to its own row, so the header is two rows tall here - and a
	   two-row sticky header would permanently occupy ~110px, about a sixth of a
	   phone viewport. Below this breakpoint the header scrolls away instead;
	   above it, where the row is single and short, sticky stays. */
	.tsv-header {
		position: static;
	}

	.tsv-header-row {
		flex-wrap: wrap;
		gap: var(--tsv-sp-3);
	}

	.tsv-nav {
		flex: 1 0 100%;
		order: 3;
		overflow-x: auto;
		/* Reachable by keyboard, because it is a scrollable region. */
		scrollbar-width: thin;
		-webkit-overflow-scrolling: touch;
	}

	.tsv-nav-list {
		gap: 0;
	}
}

/* --- Pills -------------------------------------------------------------- */

.tsv-pill {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border);
	border-radius: 999px;
	color: var(--tsv-muted);
	display: inline-block;
	font-size: 0.75rem;
	letter-spacing: .02em;
	padding: 2px 10px;
	text-decoration: none;
	text-transform: uppercase;
}

.tsv-pill:hover {
	border-color: var(--tsv-accent);
	color: var(--tsv-accent-ink);
}

/* --- Universal article card --------------------------------------------- */

ul.tsv-cards {
	display: grid;
	gap: var(--tsv-sp-5);
	grid-template-columns: 1fr;
	list-style: none;
	margin: 0;
	padding: 0;
}

@media (min-width: 640px) {
	ul.tsv-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
	ul.tsv-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

li.tsv-card {
	background-color: var(--tsv-bg-card);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius);
	display: flex;
	flex-direction: column;
	gap: var(--tsv-sp-3);
	margin: 0;
	padding: var(--tsv-sp-5);
	transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}

li.tsv-card:hover {
	border-color: var(--tsv-accent);
	transform: translateY(-2px);
	box-shadow: var(--tsv-shadow);
}

.tsv-card-title {
	font-size: 1.1875rem;
	line-height: 1.35;
	margin: 0;
}

.tsv-card-title a {
	color: var(--tsv-text);
	text-decoration: none;
}

.tsv-card-title a:hover {
	color: var(--tsv-accent-ink);
}

.tsv-card-excerpt {
	color: var(--tsv-muted);
	font-size: 0.9375rem;
	line-height: 1.6;
	margin: 0;
}

.tsv-card-meta {
	color: var(--tsv-muted);
	font-size: 0.8125rem;
	margin: auto 0 0;
	padding-top: var(--tsv-sp-2);
}

/* --- Library sections ---------------------------------------------------- */

.tsv-section {
	margin-top: var(--tsv-sp-10);
}

.tsv-section-heading {
	font-size: 1.625rem;
	margin: 0;
}

.tsv-section-note {
	color: var(--tsv-muted);
	font-size: 0.9375rem;
	margin: var(--tsv-sp-2) 0 0;
	max-width: 62ch;
}

.tsv-section .tsv-cards {
	margin-top: var(--tsv-sp-5);
}

/* --- Topic rail --------------------------------------------------------- */

.tsv-topics {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tsv-sp-3);
	list-style: none;
	margin: var(--tsv-sp-5) 0 0;
	padding: 0;
}

.tsv-topic {
	margin: 0;
}

.tsv-topic > a {
	align-items: center;
	background-color: var(--tsv-bg-card);
	border: 1px solid var(--tsv-border);
	border-radius: 999px;
	color: var(--tsv-text);
	display: inline-flex;
	gap: var(--tsv-sp-2);
	min-height: 44px;
	padding: 0 var(--tsv-sp-4);
	text-decoration: none;
	transition: border-color .15s ease, color .15s ease;
}

.tsv-topic > a:hover {
	border-color: var(--tsv-accent);
	color: var(--tsv-accent-ink);
}

.tsv-topic-name {
	font-size: 0.9375rem;
	font-weight: 600;
}

.tsv-topic-count {
	background-color: var(--tsv-bg-alt);
	border-radius: 999px;
	color: var(--tsv-muted);
	font-size: 0.75rem;
	font-variant-numeric: tabular-nums;
	padding: 1px 8px;
}

/* --- Article deck + byline ---------------------------------------------- */

.tsv-deck {
	color: var(--tsv-muted);
	font-size: 1.125rem;
	line-height: 1.6;
	margin: var(--tsv-sp-4) 0 0;
	max-width: 62ch;
}

.tsv-byline a {
	color: var(--tsv-muted);
	text-decoration-color: var(--tsv-border-strong);
	text-underline-offset: 3px;
}

.tsv-byline a:hover {
	color: var(--tsv-accent-ink);
}

/* --- Code blocks: keyboard access and a copy affordance ------------------ */

.tsv-code {
	position: relative;
}

/* The button sits inside the block's own padding rather than overlapping the
   first line of code, so it never covers a character. */
.tsv-copy {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border-strong);
	border-radius: var(--tsv-radius-sm);
	color: var(--tsv-text);
	cursor: pointer;
	font-family: var(--tsv-font);
	font-size: 0.75rem;
	line-height: 1;
	opacity: 0;
	padding: 7px 10px;
	position: absolute;
	right: var(--tsv-sp-2);
	top: var(--tsv-sp-2);
	transition: opacity .15s ease, border-color .15s ease;
}

.tsv-code:hover .tsv-copy,
.tsv-copy:focus-visible {
	opacity: 1;
}

/* Never hidden from a keyboard or touch user just because there is no hover. */
@media (hover: none) {
	.tsv-copy { opacity: 1; }
}

.tsv-copy:hover {
	border-color: var(--tsv-accent);
}

.tsv-copy[data-tsv-state="ok"] {
	border-color: var(--tsv-accent);
	color: var(--tsv-accent-ink);
	opacity: 1;
}

/* --- Ready to use ------------------------------------------------------- */

.tsv-ready {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border);
	border-left: 3px solid var(--tsv-accent);
	border-radius: var(--tsv-radius);
	margin: var(--tsv-sp-6) 0;
	padding: var(--tsv-sp-5);
}

/* Two classes deep, not !important: theme.json emits its own `h2` rule and the
   two would otherwise tie on specificity and be decided by load order. */
.tsv-ready .tsv-ready-heading {
	color: var(--tsv-muted);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: .08em;
	margin: 0 0 var(--tsv-sp-3);
	text-transform: uppercase;
}

.tsv-ready .tsv-code {
	margin: 0;
}

.tsv-ready pre {
	margin: 0;
}

.tsv-ready-note {
	color: var(--tsv-muted);
	font-size: 0.875rem;
	margin: var(--tsv-sp-3) 0 0;
}

/* --- Footer ------------------------------------------------------------- */

.tsv-footer {
	background-color: var(--tsv-bg-alt);
	border-top: 1px solid var(--tsv-border);
	color: var(--tsv-muted);
	font-size: 0.9375rem;
	margin-top: var(--tsv-sp-12);
	padding: var(--tsv-sp-10) 0 var(--tsv-sp-8);
}

.tsv-footer a {
	color: var(--tsv-muted);
	text-decoration: none;
}

.tsv-footer a:hover {
	color: var(--tsv-accent-ink);
	text-decoration: underline;
}

.tsv-footer h2 {
	color: var(--tsv-text);
	font-size: 0.8125rem;
	letter-spacing: .08em;
	margin: 0 0 var(--tsv-sp-3);
	text-transform: uppercase;
}

.tsv-footer-grid {
	display: grid;
	gap: var(--tsv-sp-6);
	grid-template-columns: 1fr;
}

@media (min-width: 640px) {
	.tsv-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
	.tsv-footer-grid { grid-template-columns: 2fr 1fr 1fr 1fr; }
}

.tsv-footer-brand .tsv-brand-link {
	color: var(--tsv-text);
	margin-bottom: var(--tsv-sp-3);
}

.tsv-footer-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.tsv-footer-list > li {
	margin: 0 0 var(--tsv-sp-1);
}

.tsv-footer-list a,
.tsv-footer-col a {
	display: inline-block;
	min-height: 32px;
	line-height: 32px;
}

.tsv-footer-legal {
	border-top: 1px solid var(--tsv-border);
	font-size: 0.8125rem;
	margin-top: var(--tsv-sp-8);
	padding-top: var(--tsv-sp-5);
}
/* TSV-SHARED:END shell */

/* ==========================================================================
   Base
   ========================================================================== */

body {
	background-color: var(--tsv-bg);
	color: var(--tsv-text);
	font-family: var(--tsv-font);
	-webkit-font-smoothing: antialiased;
}

a {
	color: var(--tsv-accent-ink);
}

a:hover,
a:focus-visible {
	color: var(--tsv-accent-2);
}

/* Visible focus on every interactive element - never removed, only restyled. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
	outline: 2px solid var(--tsv-accent-2);
	outline-offset: 2px;
	border-radius: var(--tsv-radius-sm);
}

h1, h2, h3, h4, h5, h6 {
	color: var(--tsv-text);
	line-height: 1.25;
	text-wrap: balance;
}

p {
	text-wrap: pretty;
}

/* The reading column, capped by measure rather than by pixels alone. */
.tsv-article .wp-block-post-content > * {
	max-width: 68ch;
}

/* The header, navigation, footer and theme toggle now live in the TSV-SHARED
   shell region above, because thinkstreamtv.com renders the identical markup.
   Only the WordPress-block mappings remain below this point. */

/* ==========================================================================
   Cards - WordPress block mapping onto the shared card visuals above.

   The apex renders <li class="tsv-card"> directly; core's Query Loop renders
   <li class="wp-block-post"> instead, so these rules exist purely to make the
   two produce the same result. The visual values themselves are declared once,
   in the shared region.
   ========================================================================== */

.tsv-cards .wp-block-post-template {
	display: grid;
	gap: var(--tsv-sp-5);
	grid-template-columns: 1fr;
	list-style: none;
	padding: 0;
	margin: 0;
}

@media (min-width: 640px) {
	.tsv-cards .wp-block-post-template {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.tsv-cards .wp-block-post-template {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.tsv-cards .wp-block-post {
	background-color: var(--tsv-bg-card);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius);
	padding: var(--tsv-sp-5);
	display: flex;
	flex-direction: column;
	gap: var(--tsv-sp-3);
	transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}

.tsv-cards .wp-block-post:hover {
	border-color: var(--tsv-accent);
	transform: translateY(-2px);
	box-shadow: var(--tsv-shadow);
}

/* A compact rail of cards, used by the Comparisons section. */
@media (min-width: 640px) {
	ul.tsv-cards--compact { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
	ul.tsv-cards--compact { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.tsv-cards .wp-block-post-title {
	font-size: 1.1875rem;
	line-height: 1.35;
	margin: 0;
}

.tsv-cards .wp-block-post-title a {
	color: var(--tsv-text);
	text-decoration: none;
}

.tsv-cards .wp-block-post-title a:hover {
	color: var(--tsv-accent-ink);
}

.tsv-cards .wp-block-post-excerpt {
	margin: 0;
}

.tsv-cards .wp-block-post-excerpt__excerpt {
	color: var(--tsv-muted);
	font-size: 0.9375rem;
	line-height: 1.6;
	margin: 0;
}

/* The excerpt is a summary, not a teaser to be clicked - the title is the link. */
.tsv-cards .wp-block-post-excerpt__more-text {
	display: none;
}

.tsv-cards .wp-block-post-date {
	color: var(--tsv-muted);
	font-size: 0.8125rem;
	margin: 0;
	margin-top: auto;
	padding-top: var(--tsv-sp-2);
}

/* Core renders category terms as plain anchors; give them the shared pill. */
.tsv-cards .wp-block-post-terms a {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border);
	border-radius: 999px;
	color: var(--tsv-muted);
	display: inline-block;
	font-size: 0.75rem;
	letter-spacing: .02em;
	padding: 2px 10px;
	text-decoration: none;
	text-transform: uppercase;
}

.tsv-cards .wp-block-post-terms a:hover {
	border-color: var(--tsv-accent);
	color: var(--tsv-accent-ink);
}

/* ==========================================================================
   Article
   ========================================================================== */

/* Core's post-excerpt block wraps its text one level down; the shared .tsv-deck
   values are declared once above, this maps the block markup onto them. */
.tsv-article .tsv-deck,
.tsv-article .tsv-deck .wp-block-post-excerpt__excerpt {
	color: var(--tsv-muted);
	font-size: 1.125rem;
	line-height: 1.6;
	margin: 0;
	max-width: 62ch;
}

.tsv-article .tsv-deck {
	margin-top: var(--tsv-sp-4);
}

/* The excerpt is a summary here, not a teaser to be clicked. */
.tsv-article .tsv-deck .wp-block-post-excerpt__more-text {
	display: none;
}

.tsv-article-meta {
	color: var(--tsv-muted);
	font-size: 0.9375rem;
	display: flex;
	flex-wrap: wrap;
	gap: var(--tsv-sp-3);
	align-items: center;
}

.tsv-article-meta > * {
	margin: 0;
}

.tsv-article .wp-block-post-content {
	font-size: 1.0625rem;
	line-height: 1.7;
}

.tsv-article .wp-block-post-content h2 {
	font-size: 1.625rem;
	margin-top: var(--tsv-sp-8);
	scroll-margin-top: 84px;
}

.tsv-article .wp-block-post-content h3 {
	font-size: 1.25rem;
	margin-top: var(--tsv-sp-6);
	scroll-margin-top: 84px;
}

/* Code: never wrapped. A shell command broken mid-flag teaches the wrong command. */
.tsv-article pre,
.wp-block-code {
	background-color: var(--tsv-bg-code);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius-sm);
	color: #e6edf3;
	font-family: var(--tsv-font-mono);
	font-size: 0.9375rem;
	line-height: 1.6;
	overflow-x: auto;
	padding: var(--tsv-sp-4);
	white-space: pre;
}

.tsv-article :not(pre) > code {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border);
	border-radius: 4px;
	font-family: var(--tsv-font-mono);
	font-size: 0.9em;
	padding: 1px 5px;
	word-break: break-word;
}

/* Tables are focusable so a keyboard user can scroll a wide one. */
.tsv-article .wp-block-table {
	overflow-x: auto;
}

.tsv-article table {
	border-collapse: collapse;
	width: 100%;
}

.tsv-article th,
.tsv-article td {
	border: 1px solid var(--tsv-border);
	padding: var(--tsv-sp-2) var(--tsv-sp-3);
	text-align: left;
}

.tsv-article thead th {
	background-color: var(--tsv-bg-alt);
}

.tsv-article tbody tr:nth-child(even) {
	background-color: var(--tsv-bg-alt);
}

.tsv-article blockquote {
	border-left: 3px solid var(--tsv-accent);
	color: var(--tsv-muted);
	margin-left: 0;
	padding-left: var(--tsv-sp-5);
}

/* ==========================================================================
   CTA / affiliate blocks (markup is owned by cta_system.py - styled, never rewritten)
   ========================================================================== */

.tsv-article .tsv-cta,
.tsv-cta {
	background-color: var(--tsv-bg-card);
	border: 1px solid var(--tsv-border);
	border-left: 3px solid var(--tsv-accent);
	border-radius: var(--tsv-radius);
	color: var(--tsv-text);
	margin: var(--tsv-sp-8) 0;
	padding: var(--tsv-sp-5);
}

.tsv-cta a {
	color: var(--tsv-accent-ink);
	font-weight: 600;
}

.tsv-article .tsv-internal-links {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius);
	margin: var(--tsv-sp-8) 0;
	padding: var(--tsv-sp-5);
}

/* ==========================================================================
   Table of contents
   ========================================================================== */

.tsv-toc {
	background-color: var(--tsv-bg-alt);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius);
	margin: var(--tsv-sp-6) 0;
	padding: var(--tsv-sp-4) var(--tsv-sp-5);
}

.tsv-toc > summary {
	cursor: pointer;
	font-weight: 600;
	list-style: none;
	padding: var(--tsv-sp-2) 0;
}

.tsv-toc > summary::-webkit-details-marker {
	display: none;
}

.tsv-toc > summary::after {
	content: "▾";
	color: var(--tsv-muted);
	float: right;
	transition: transform .15s ease;
}

.tsv-toc[open] > summary::after {
	transform: rotate(180deg);
}

.tsv-toc ol {
	list-style: none;
	margin: var(--tsv-sp-3) 0 0;
	padding: 0;
}

.tsv-toc li {
	margin: 0;
	padding: var(--tsv-sp-1) 0;
}

.tsv-toc li.tsv-toc-h3 {
	padding-left: var(--tsv-sp-5);
	font-size: 0.9375rem;
}

.tsv-toc a {
	color: var(--tsv-muted);
	text-decoration: none;
}

.tsv-toc a:hover {
	color: var(--tsv-accent-ink);
	text-decoration: underline;
}

/* ==========================================================================
   Breadcrumbs
   ========================================================================== */

.tsv-breadcrumbs {
	color: var(--tsv-muted);
	font-size: 0.875rem;
	margin-bottom: var(--tsv-sp-4);
}

.tsv-breadcrumbs a {
	color: var(--tsv-muted);
	text-decoration: none;
}

.tsv-breadcrumbs a:hover {
	color: var(--tsv-accent-ink);
	text-decoration: underline;
}

.tsv-breadcrumbs .tsv-breadcrumb-sep {
	opacity: .55;
	padding: 0 var(--tsv-sp-2);
}

.tsv-breadcrumbs .tsv-breadcrumb-current {
	color: var(--tsv-text);
	display: inline-block;
	max-width: 40ch;
	overflow: hidden;
	text-overflow: ellipsis;
	vertical-align: bottom;
	white-space: nowrap;
}

/* ==========================================================================
   Related posts
   ========================================================================== */

.tsv-related {
	border-top: 1px solid var(--tsv-border);
	margin-top: var(--tsv-sp-10);
	padding-top: var(--tsv-sp-8);
}

.tsv-related h2 {
	font-size: 1.375rem;
	margin-bottom: var(--tsv-sp-5);
}

/* ==========================================================================
   Hubs (home page)
   ========================================================================== */

.tsv-hero {
	border-bottom: 1px solid var(--tsv-border);
	padding: var(--tsv-sp-12) 0 var(--tsv-sp-10);
}

.tsv-hero h1 {
	font-size: clamp(2rem, 5vw, 3.4rem);
	letter-spacing: -0.02em;
	margin: 0 0 var(--tsv-sp-4);
}

.tsv-hero p {
	color: var(--tsv-muted);
	font-size: 1.125rem;
	max-width: 62ch;
}

.tsv-hubs {
	display: grid;
	gap: var(--tsv-sp-5);
	grid-template-columns: 1fr;
	list-style: none;
	margin: 0;
	padding: 0;
}

@media (min-width: 640px) {
	.tsv-hubs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
	.tsv-hubs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.tsv-hub {
	background-color: var(--tsv-bg-card);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius);
	margin: 0;
	transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}

.tsv-hub:hover {
	border-color: var(--tsv-accent);
	transform: translateY(-2px);
	box-shadow: var(--tsv-shadow);
}

/* The whole card is one link - not a nested-link card, which breaks both
   keyboard navigation and the click target. */
.tsv-hub > a {
	color: inherit;
	display: block;
	padding: var(--tsv-sp-5);
	text-decoration: none;
}

.tsv-hub-name {
	display: block;
	font-size: 1.125rem;
	font-weight: 600;
	margin-bottom: var(--tsv-sp-1);
}

.tsv-hub-count {
	color: var(--tsv-muted);
	font-size: 0.875rem;
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.wp-block-button__link,
.tsv-button {
	background-color: var(--tsv-accent);
	border: 0;
	border-radius: var(--tsv-radius-sm);
	color: var(--tsv-on-accent);   /* never white - see the token comment above */
	display: inline-flex;
	align-items: center;
	font-weight: 600;
	min-height: 44px;
	padding: 0 var(--tsv-sp-5);
	text-decoration: none;
	transition: filter .15s ease;
}

.wp-block-button__link:hover,
.tsv-button:hover {
	color: var(--tsv-on-accent);
	filter: brightness(1.08);
}

.is-style-outline .wp-block-button__link,
.tsv-button--secondary {
	background-color: transparent;
	border: 1px solid var(--tsv-border-strong);
	color: var(--tsv-text);
}

/* ==========================================================================
   Search + pagination
   ========================================================================== */

.wp-block-search__input {
	background-color: var(--tsv-bg-card);
	border: 1px solid var(--tsv-border);
	border-radius: var(--tsv-radius-sm);
	color: var(--tsv-text);
	min-height: 44px;
	padding: 0 var(--tsv-sp-4);
}

.wp-block-search__input::placeholder {
	color: var(--tsv-muted);
}

.wp-block-search__button {
	background-color: var(--tsv-accent);
	border: 0;
	border-radius: var(--tsv-radius-sm);
	color: var(--tsv-on-accent);
	font-weight: 600;
	min-height: 44px;
	padding: 0 var(--tsv-sp-5);
}

.wp-block-query-pagination {
	border-top: 1px solid var(--tsv-border);
	margin-top: var(--tsv-sp-8);
	padding-top: var(--tsv-sp-5);
}

.wp-block-query-pagination a {
	color: var(--tsv-muted);
	text-decoration: none;
}

.wp-block-query-pagination a:hover {
	color: var(--tsv-accent-ink);
}

.wp-block-query-pagination-numbers .current {
	color: var(--tsv-accent-ink);
	font-weight: 700;
}

/* The footer lives in the TSV-SHARED shell region above. */

/* ==========================================================================
   Motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: .001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .001ms !important;
		scroll-behavior: auto !important;
	}

	.tsv-cards .wp-block-post:hover,
	li.tsv-card:hover,
	.tsv-topic > a:hover,
	.tsv-hub:hover {
		transform: none;
	}
}
