/* ==========================================================================
   LobbyVPN — single post typography

   SCOPE: `.lvpn-article` only, which `template-parts/single.php` puts on <main>
   for classic blog posts. The blog index, archives, search, pages and the
   landing page are untouched — they keep blog.css as it is.

   WHAT THIS IS. The client's reference is the live article at
   lobbyvpn.com/blog/best-controller-settings-for-call-of-duty-on-ps5/. Its type
   scale and spacing are reproduced here exactly, measured from the live page
   rather than eyeballed:

     H1     32px / 48px   / 700
     H2     28px / 42px   / 700   margin 42px top, 14px bottom
     H3     24px / 36px   / 700   margin 36px top, 12px bottom
     body   17px / 27.2px / 400   margin-bottom 32px
     lists  17px / 27.2px / 400   margin-bottom 32px, 34px indent, no gap
            between items

   WHAT IS DELIBERATELY NOT COPIED. The live page is light — #f7fafc behind
   #2d3748 text with blue links — and sets everything in the system sans stack.
   This site is dark, so the palette stays on the brand tokens, and headings
   stay Orbitron so the article still reads as the same site as the home,
   contact and legal pages. Body copy takes the system stack, which is what
   makes 17px prose readable at length.

   The layout — hero, centred header, sticky TOC — is unchanged. Only the text
   column narrows, to the live measure.
   ========================================================================== */

.lvpn-article {
	/* The live stack verbatim. No webfont, so nothing to preload or swap. */
	--lvpn-read-font: -apple-system, system-ui, 'Segoe UI', Roboto, Oxygen-Sans,
		Ubuntu, Cantarell, 'Helvetica Neue', sans-serif, 'Apple Color Emoji',
		'Segoe UI Emoji', 'Segoe UI Symbol';
}

/* --------------------------------------------------------------------------
   Layout — contained hero with the content sheet lapping over it

   Measured off live at seven widths. The hero is a contained 1054px image, not
   a full-bleed band, and the article sits on a 794px card whose top edge
   overlaps the image by 73px. Inside the card, 32px of gutter leaves the 730px
   measure.

   The card's three parts — header, layout, footer — are already consecutive
   siblings in single.php, so they can be given a shared width and background
   and read as one sheet. No template change needed.
   -------------------------------------------------------------------------- */

body.lvpn-site .lvpn-article__hero {
	max-width: 1054px;
	margin-inline: auto;
}

/*
 * Hello Elementor caps post thumbnails at `.post .wp-post-image { max-height:
 * 500px }` (400 under 992, 300 under 576), which silently clamps any height set
 * here. Clearing it is what makes the declared heights the rendered ones.
 */
body.lvpn-site .lvpn-article__hero img {
	height: 60vw;
	max-height: none;
}

/*
 * The gradient exists to fade a full-bleed band into the page behind a headline
 * sitting on top of it. The headline is on the card now, so it only muddies the
 * artwork.
 */
body.lvpn-site .lvpn-article__hero::after {
	display: none;
}

body.lvpn-site .lvpn-article__header,
body.lvpn-site .lvpn-article__layout,
body.lvpn-site .lvpn-article__footer {
	width: calc(100% - 16px);
	max-width: 794px;
	margin-inline: auto;
	padding-inline: 24px;
	/* Live's card is lighter than its page. Same relationship, inverted. */
	background-color: var(--lvpn-surface-1);
}

body.lvpn-site .lvpn-article__header {
	padding-top: 32px;
	padding-bottom: 0;
	border-radius: var(--lvpn-radius) var(--lvpn-radius) 0 0;
	/* Header centres, body copy stays left. */
	text-align: center;
}

/* The overlap. Live laps the card 73px over the image at every width. */
body.lvpn-site .lvpn-article__hero + .lvpn-article__header {
	margin-top: -73px;
}

body.lvpn-site .lvpn-article__layout {
	padding-top: 24px;
	/* The sheet ends with the reading, so it closes here. */
	padding-bottom: 32px;
	border-radius: 0 0 var(--lvpn-radius) var(--lvpn-radius);
}

body.lvpn-site .lvpn-article__body {
	max-width: none;
	padding: 0;
}

/*
 * The footer is page furniture, not reading, so it sits on the page rather than
 * on the card. It also has to: the prev/next cards are `--lvpn-surface-2` and
 * were sitting on the sheet's `--lvpn-surface-1` — 8 points apart, so the cards
 * barely read as cards. On black they do.
 *
 * Width and padding stay, so the cards still line up with the text column above.
 */
body.lvpn-site .lvpn-article__footer {
	padding-bottom: 32px;
	border-radius: 0;
	background-color: transparent;
}

/*
 * The tags line carried a top rule to divide it from the body. Off the sheet it
 * has the card's own bottom edge doing that a few pixels above, so the rule was
 * drawing a second divider in empty space.
 */
body.lvpn-site .lvpn-article__tags {
	padding-top: 24px;
	border-top: 0;
}

body.lvpn-site .lvpn-article__aside {
	margin-top: 8px;
}

@media (min-width: 768px) {
	body.lvpn-site .lvpn-article__hero img {
		height: 480px;
	}

	body.lvpn-site .lvpn-article__header,
	body.lvpn-site .lvpn-article__layout,
	body.lvpn-site .lvpn-article__footer {
		width: calc(100% - 48px);
		padding-inline: 32px;
	}

	body.lvpn-site .lvpn-article__layout {
		padding-bottom: 40px;
	}
}

@media (min-width: 1024px) {
	body.lvpn-site .lvpn-article__hero img {
		height: 529px;
	}
}

/* --------------------------------------------------------------------------
   Rails — table of contents left, subscribe right

   Three widths, three arrangements:

     <1200   the layout IS the card. TOC is a sticky collapsible bar at the top
             of it, subscribe is a block at the end.
     1200+   TOC becomes the left rail; the card is the middle column, and the
             subscribe panel drops under the body inside it.
     1440+   subscribe becomes the right rail. 260 + 40 + 794 + 40 + 260 needs
             1394px of grid, which is why it waits for 1440 rather than
             appearing with the TOC.

   The grid rules are scoped to `--toc` because that class is only emitted when
   a table of contents exists; a post without one keeps the plain card at every
   width and would otherwise render an empty 260px column.
   -------------------------------------------------------------------------- */

body.lvpn-site .lvpn-article__layout .lvpn-toc {
	margin-bottom: 24px;
}

/*
 * blog.css switches the TOC into rail mode from 1200px. The rails here start at
 * 1440, so the 1200-1439 band is held on the collapsible bar; without this the
 * TOC would go transparent and static inside a layout that is still a plain
 * block, and simply disappear.
 */
@media (min-width: 1200px) and (max-width: 1439.98px) {
	/* blog.css turns the layout into the rail grid here too. Back to a block. */
	body.lvpn-site .lvpn-article__layout--toc {
		display: block;
		max-width: 794px;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc {
		position: sticky;
		top: 58px;
		opacity: 1;
		visibility: visible;
		transform: none;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc__inner {
		position: static;
		max-height: none;
		display: block;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc__panel {
		grid-template-rows: 0fr;
		-webkit-mask-image: none;
		mask-image: none;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc.is-open .lvpn-toc__panel {
		grid-template-rows: 1fr;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc__scroll {
		max-height: min(60vh, 420px);
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc__toggle {
		cursor: pointer;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-toc__chevron {
		display: flex;
	}
}

@media (min-width: 1440px) {
	/*
	 * One breakpoint for both rails, and it is 1440 rather than the 1200 the
	 * rail used before the card existed.
	 *
	 * The reason is symmetry. The header and footer are centred 794px blocks
	 * outside this grid, so the middle column has to land on the viewport
	 * centre or the sheet visibly steps sideways halfway down the article. That
	 * only happens when the two side columns are equal, which needs
	 * 260 + 40 + 794 + 40 + 260 = 1394px. Below that the rails would have to be
	 * narrower than a table of contents can usefully be, so everything stacks
	 * inside the card instead — the TOC as its sticky collapsible bar, the
	 * subscribe panel as a block at the end.
	 */
	body.lvpn-site .lvpn-article__layout--toc {
		display: grid;
		grid-template-columns: 260px minmax(0, 794px) 260px;
		justify-content: center;
		gap: 40px;
		width: auto;
		max-width: 1394px;
		padding-top: 0;
		padding-bottom: 0;
		padding-inline: 0;
		border-radius: 0;
		background: none;
	}

	/* The sheet moves from the layout to the middle column, closing radius and all. */
	body.lvpn-site .lvpn-article__layout--toc .lvpn-article__body {
		padding: 24px 32px 40px;
		border-radius: 0 0 var(--lvpn-radius) var(--lvpn-radius);
		background-color: var(--lvpn-surface-1);
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-article__aside {
		grid-column: 3;
		grid-row: 1;
		margin-top: 0;

		/*
		 * Same reveal as the TOC rail, driven by the same `is-visible` toggle in
		 * frontend.js. `visibility` is animated too so the form is not a
		 * keyboard trap while it is invisible.
		 */
		opacity: 0;
		visibility: hidden;
		transform: translateY(-8px);
		transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
	}

	body.lvpn-site .lvpn-article__layout--toc .lvpn-article__aside.is-visible {
		opacity: 1;
		visibility: visible;
		transform: none;
	}

	/*
	 * The sticky box wraps the form AND the promo. Sticking the form alone left
	 * the promo scrolling away beneath it.
	 */
	body.lvpn-site .lvpn-article__aside-sticky {
		position: sticky;
		/* Matches the TOC rail: 64px header plus breathing room. */
		top: 88px;
		max-height: calc(100vh - 120px);
		overflow-y: auto;
		scrollbar-width: thin;
		scrollbar-color: var(--lvpn-border-mid) transparent;
	}

	body.lvpn-site .lvpn-article__aside-sticky::-webkit-scrollbar {
		width: 6px;
	}

	body.lvpn-site .lvpn-article__aside-sticky::-webkit-scrollbar-thumb {
		border-radius: 3px;
		background-color: var(--lvpn-border-mid);
	}
}

/* --------------------------------------------------------------------------
   Subscribe panel
   -------------------------------------------------------------------------- */

body.lvpn-site .lvpn-article__aside-inner {
	padding: 20px;
	border: 1px solid var(--lvpn-border-dim);
	border-radius: var(--lvpn-radius-lg);
	background-color: var(--lvpn-surface-2);
}

body.lvpn-site .lvpn-article__aside-title {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 8px;
	color: var(--lvpn-green-soft);
	font-family: var(--lvpn-font);
	font-size: 14px;
	line-height: 20px;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	text-align: left;
}

body.lvpn-site .lvpn-article__aside-title svg {
	width: 16px;
	height: 16px;
	flex: 0 0 auto;
}

body.lvpn-site .lvpn-article__aside-text {
	margin: 0 0 14px;
	color: var(--lvpn-text-soft);
	font-family: var(--lvpn-read-font);
	font-size: 14px;
	line-height: 20px;
	text-align: left;
}

/* --------------------------------------------------------------------------
   Sidebar promo

   Set at LobbyVPN → Sidebar Promo. Sits under the subscribe panel: in the rail
   from 1440px up, and after the article below that.
   -------------------------------------------------------------------------- */

body.lvpn-site .lvpn-article__promo {
	margin-top: 16px;
}

body.lvpn-site .lvpn-article__promo-link {
	display: block;
	border-radius: var(--lvpn-radius-lg);
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}

body.lvpn-site .lvpn-article__promo-link:hover,
body.lvpn-site .lvpn-article__promo-link:focus-visible {
	transform: translateY(-2px);
	box-shadow: 0 10px 24px rgba(0, 0, 0, 0.45);
}

body.lvpn-site .lvpn-article__promo-img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--lvpn-radius-lg);
}

/*
 * Below the rail breakpoint the promo is a block after the article, where a
 * full-measure banner would tower over the text. Cap it at the rail width and
 * centre it so it stays an aside rather than becoming a section.
 */
@media (max-width: 1439.98px) {
	body.lvpn-site .lvpn-article__promo {
		max-width: 360px;
		margin-inline: auto;
	}
}

/*
 * The plugin's own form is a flex row. In a 260px rail it stacks.
 */
body.lvpn-site .lvpn-article__aside-form .lvpn-newsletter {
	flex-direction: column;
	align-items: stretch;
	gap: 8px;
}

body.lvpn-site .lvpn-article__aside-form .lvpn-newsletter__input {
	width: 100%;
	padding: 8px 14px;
	font-family: var(--lvpn-read-font);
	font-size: 15px;
	line-height: 22px;
}

body.lvpn-site .lvpn-article__aside-form .lvpn-newsletter__submit {
	width: 100%;
	justify-content: center;
}

body.lvpn-site .lvpn-article__aside-form .lvpn-newsletter__message {
	font-family: var(--lvpn-read-font);
	font-size: 13px;
	line-height: 18px;
}

/*
 * The rules below only apply if someone points the panel at a Fluent Forms
 * shortcode through `lvpn_child_article_subscribe_shortcode`. Fluent lays its
 * subscription form out in two 50% cells with inline `flex-basis`; inline
 * styles cannot be beaten by specificity, so the container is switched to grid,
 * where `flex-basis` has no meaning and goes inert — the same trick the footer
 * uses (D-047). Here the cells stack, because the rail is 260px wide.
 */
body.lvpn-site .lvpn-article__aside-form .fluentform .ff-column-container {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 8px;
	margin: 0;
}

body.lvpn-site .lvpn-article__aside-form .fluentform .ff-t-cell {
	padding: 0;
}

body.lvpn-site .lvpn-article__aside-form .fluentform .ff-el-group {
	margin-bottom: 0;
}

body.lvpn-site .lvpn-article__aside-form .fluentform input[type='email'],
body.lvpn-site .lvpn-article__aside-form .fluentform input[type='text'] {
	width: 100%;
	min-width: 0;
	padding: 8px 14px;
	background-color: var(--lvpn-gray-900);
	border: 1px solid var(--lvpn-gray-700);
	border-radius: var(--lvpn-radius);
	color: #fff;
	font-family: var(--lvpn-read-font);
	font-size: 15px;
	line-height: 22px;
	transition: border-color 0.2s ease;
}

body.lvpn-site .lvpn-article__aside-form .fluentform input::placeholder {
	color: var(--lvpn-gray-500);
}

body.lvpn-site .lvpn-article__aside-form .fluentform input[type='email']:focus,
body.lvpn-site .lvpn-article__aside-form .fluentform input[type='text']:focus {
	outline: none;
	border-color: var(--lvpn-green);
}

/*
 * The form ships its own inline <style> at (0,3,1) painting the button blue.
 * `.lvpn-article` takes ours to (0,4,0), and class count is compared before
 * element count. `:focus` is declared with `:hover` because Hello Elementor
 * ships `button:focus { background-color: #c36 }` (D-030).
 */
.lvpn-article .lvpn-article__aside-form .fluentform .ff-btn-submit,
.lvpn-article .lvpn-article__aside-form .fluentform button[type='submit'] {
	width: 100%;
	min-width: 0;
	padding: 8px 16px;
	background-color: var(--lvpn-green-lime);
	border: 1px solid transparent;
	border-radius: var(--lvpn-radius);
	color: #000;
	font-family: var(--lvpn-font);
	font-size: 14px;
	font-weight: 700;
	line-height: 22px;
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.lvpn-article .lvpn-article__aside-form .fluentform .ff-btn-submit:hover,
.lvpn-article .lvpn-article__aside-form .fluentform .ff-btn-submit:focus,
.lvpn-article .lvpn-article__aside-form .fluentform button[type='submit']:hover,
.lvpn-article .lvpn-article__aside-form .fluentform button[type='submit']:focus {
	background-color: var(--lvpn-green-soft);
	color: #000;
}

body.lvpn-site .lvpn-article__aside-form .fluentform .error,
body.lvpn-site .lvpn-article__aside-form .fluentform .text-danger,
body.lvpn-site .lvpn-article__aside-form .ff-errors-in-stack {
	margin-top: 8px;
	color: #ff8080;
	font-family: var(--lvpn-read-font);
	font-size: 13px;
	line-height: 18px;
	font-weight: 600;
}

body.lvpn-site .lvpn-article__aside-form .ff-message-success {
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	color: var(--lvpn-green);
	font-family: var(--lvpn-read-font);
	font-size: 14px;
	line-height: 20px;
	font-weight: 600;
}

/* --------------------------------------------------------------------------
   Body copy
   -------------------------------------------------------------------------- */

body.lvpn-site .lvpn-article__body {
	font-family: var(--lvpn-read-font);
	font-size: 17px;
	line-height: 27.2px;
	font-weight: 400;
}

/*
 * Live drives every gap from `margin-bottom`, and the numbers only work that
 * way: a paragraph's 32px bottom margin collapses against an H2's 42px top
 * margin to give 42, while the H2's own 14px bottom margin is what sits under
 * it. blog.css sets `> * + * { margin-top: 1.15em }` on `.page-content`, which
 * would add to all of that, so it is zeroed here first.
 */
body.lvpn-site .lvpn-article__body > * + * {
	margin-top: 0;
}

body.lvpn-site .lvpn-article__body p,
body.lvpn-site .lvpn-article__body ul,
body.lvpn-site .lvpn-article__body ol,
body.lvpn-site .lvpn-article__body blockquote,
body.lvpn-site .lvpn-article__body figure,
body.lvpn-site .lvpn-article__body pre {
	margin-top: 0;
	margin-bottom: 32px;
}

body.lvpn-site .lvpn-article__body p,
body.lvpn-site .lvpn-article__body li {
	font-family: var(--lvpn-read-font);
	font-size: 17px;
	line-height: 27.2px;
}

body.lvpn-site .lvpn-article__body ul,
body.lvpn-site .lvpn-article__body ol {
	padding-left: 34px;
}

/* Live runs list items tight against each other. */
body.lvpn-site .lvpn-article__body li + li {
	margin-top: 0;
}

body.lvpn-site .lvpn-article__body strong,
body.lvpn-site .lvpn-article__body b {
	font-weight: 700;
}

body.lvpn-site .lvpn-article__body figcaption {
	font-family: var(--lvpn-read-font);
}

/* --------------------------------------------------------------------------
   Headings — live's metrics, this site's typeface

   `--lvpn-font` is Orbitron, the face every other page uses for headings.
   -------------------------------------------------------------------------- */

body.lvpn-site .lvpn-article__body h2,
body.lvpn-site .lvpn-article__body h3,
body.lvpn-site .lvpn-article__body h4 {
	font-family: var(--lvpn-font);
	font-weight: 700;
}

body.lvpn-site .lvpn-article__body h2 {
	margin-top: 42px;
	margin-bottom: 14px;
	font-size: 28px;
	line-height: 42px;
}

body.lvpn-site .lvpn-article__body h3 {
	margin-top: 36px;
	margin-bottom: 12px;
	font-size: 24px;
	line-height: 36px;
}

/*
 * The reference article has no H4, so this continues the H2-to-H3 ratio rather
 * than inventing a different one.
 */
body.lvpn-site .lvpn-article__body h4 {
	margin-top: 30px;
	margin-bottom: 10px;
	font-size: 20px;
	line-height: 30px;
}

/* Nothing opens the body with a section gap under the byline. */
body.lvpn-site .lvpn-article__body > :first-child {
	margin-top: 0;
}

/* --------------------------------------------------------------------------
   Header — live's H1 metrics, our centred layout
   -------------------------------------------------------------------------- */

/*
 * The tinted pill from the blog cards (`.lvpn-card__terms a` in blog.css), so a
 * category reads the same wherever it appears. Live sets a bare label here, but
 * matching our own index beats matching live on this one.
 */
body.lvpn-site .lvpn-article__terms {
	justify-content: center;
	margin-bottom: 12px;
}

body.lvpn-site .lvpn-article__terms a {
	padding: 4px 12px;
	border: 0;
	border-radius: var(--lvpn-radius-full);
	background-color: rgba(98, 255, 140, 0.12);
	color: var(--lvpn-green-soft);
	font-family: var(--lvpn-read-font);
	font-size: 12px;
	line-height: 18px;
	font-weight: 700;
	letter-spacing: 0.04em;
}

body.lvpn-site .lvpn-article__terms a:hover,
body.lvpn-site .lvpn-article__terms a:focus {
	background-color: var(--lvpn-green-soft);
	color: #000;
}

body.lvpn-site .lvpn-article__title {
	margin-bottom: 0;
	font-size: 32px;
	line-height: 48px;
	font-weight: 700;
	text-align: center;
}

/*
 * The byline is chrome, not prose. It was 14px grey against 17px grey body copy
 * two lines below, which read as a first paragraph in a smaller size. Smaller,
 * dimmer, letter-spaced, and closed off with a rule so the body starts cleanly.
 */
body.lvpn-site .lvpn-article__meta {
	justify-content: center;
	margin-top: 16px;
	padding-bottom: 20px;
	border-bottom: 1px solid var(--lvpn-border-dim);
	color: var(--lvpn-text-muted);
	font-family: var(--lvpn-read-font);
	font-size: 13px;
	line-height: 20px;
	letter-spacing: 0.02em;
}

body.lvpn-site .lvpn-article__meta svg {
	width: 14px;
	height: 14px;
	color: var(--lvpn-green-review);
	opacity: 0.75;
}
