/**
 * Monitee — Design System
 * Component + utility layer on top of the theme.json token layer.
 *
 * Every value here resolves to a token. If you need a new colour, size or
 * radius, add it to theme.json first — never hard-code it in this file.
 *
 * Naming: .mnt-<component>[__<part>][--<variant>]
 */

/* ==========================================================================
   0. Base
   ========================================================================== */

/**
 * Border-box everywhere.
 *
 * Deliberately duplicated from style.css. Several components here combine
 * height: 100% with padding — equal-height cards above all — and under
 * content-box those overflow their container by exactly the padding, which on
 * a grid means every row overlapping the next. That failure is silent, looks
 * like a grid bug rather than a missing stylesheet, and is not worth risking
 * on this file and style.css both being loaded in the right order.
 */
*,
*::before,
*::after {
	box-sizing: border-box;
}

:root {
	color-scheme: light;
	--mnt-header-h: 60px;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	scroll-padding-top: calc(var(--mnt-header-h) + 1.5rem);
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	font-variant-ligatures: contextual common-ligatures;
}

/*
 * Nothing may scroll sideways.
 *
 * `hidden` was doing this before, and it is the wrong tool: overflow-x: hidden
 * against a visible overflow-y computes overflow-y to auto, which turns the
 * element into a scroll container. That is what makes a sticky header stop
 * sticking, and it leaves the axis one browser quirk away from scrolling
 * anyway. `clip` does the one thing wanted — clip, no scroll container, no
 * effect on the other axis — so position: sticky keeps working.
 *
 * Declared on both elements because either can end up as the viewport's
 * scrolling box, and kept as a pair so browsers without `clip` still get the
 * old behaviour.
 */
html,
body {
	overflow-x: hidden;
	overflow-x: clip;
}

/* Tabular figures everywhere numbers are compared — stats, metrics, tables. */
.mnt-tnum,
.mnt-stat__value,
table {
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum" 1;
}

::selection {
	background: rgba(74, 87, 168, 0.18);
	color: var(--wp--preset--color--text);
}

:where(a, button, summary, input, textarea, select):focus-visible {
	outline: 2px solid var(--wp--preset--color--primary);
	outline-offset: 3px;
	border-radius: var(--wp--custom--radius--xs);
}

/* Optical fix: Inter's cap height sits high in very large sizes. */
.has-display-font-size,
.has-heading-1-font-size {
	font-feature-settings: "cv05" 1, "cv08" 1, "ss03" 1;
}

/* ==========================================================================
   1. Typography helpers
   ========================================================================== */

.mnt-mono {
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.9375em;
	letter-spacing: 0;
}

/* Eyebrow — small uppercase section label with a leading status dot. */
.mnt-eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--eyebrow);
	text-transform: uppercase;
	color: var(--wp--preset--color--text-faint);
	margin-bottom: var(--wp--preset--spacing--30);
}

/*
 * The dot glows only in dark mode — a bloom is light spilling onto a dark
 * surface, and the same shadow on a near-white page is a grey smudge. Section
 * 16 adds it back.
 */
.mnt-eyebrow::before {
	content: "";
	width: 6px;
	height: 6px;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--primary);
	flex: none;
}

.mnt-eyebrow--success::before { background: var(--wp--preset--color--success); }
.mnt-eyebrow--warning::before { background: var(--wp--preset--color--warning); }
.mnt-eyebrow--danger::before  { background: var(--wp--preset--color--danger); }

/* Gradient text — use sparingly, one per page at most. */
.mnt-gradient-text {
	background: linear-gradient(180deg, var(--wp--preset--color--text) 30%, rgba(20, 22, 28, 0.68) 100%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;

	/*
	 * background-clip: text paints the gradient only inside the element's own
	 * box. Display type runs at line-height 1.02, so that box stops above the
	 * descenders — the tail of a "y" on the last line falls outside it, gets no
	 * gradient, and renders transparent. It reads as a clipped glyph.
	 *
	 * Extending the box downward and pulling the same amount back off the
	 * margin fixes the paint without moving anything.
	 */
	padding-bottom: 0.14em;
	margin-bottom: -0.14em;
}

.mnt-text-balance { text-wrap: balance; }
.mnt-text-pretty  { text-wrap: pretty; }

/* Constrain measure on long-form copy inside wide layouts. */
.mnt-measure { max-width: 62ch; }

/* ==========================================================================
   2. Surfaces
   ========================================================================== */

/**
 * Card. The signature shape from the app: generous radius, flat surface,
 * hairline border, and a 1px top highlight that reads as a light source.
 */
.mnt-card {
	position: relative;
	display: flex;
	flex-direction: column;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--lg);
	box-shadow: var(--wp--preset--shadow--card);
	padding: var(--wp--preset--spacing--60);
	overflow: hidden;
}

/**
 * Equal heights.
 *
 * A grid stretches its items to the row height, but only if the item itself
 * fills the track — so cards need an explicit height. Without this, cards in
 * the same row end at different points and the row looks ragged.
 */
.mnt-bento > .mnt-card,
.mnt-grid-equal > .mnt-card,
.wp-block-group.is-layout-grid > .mnt-card,
.wp-block-group.is-layout-flex > .mnt-card,
.wp-block-column > .mnt-card {
	height: 100%;
	margin: 0;
}

.mnt-bento,
.mnt-grid-equal,
.wp-block-group.is-layout-grid {
	align-items: stretch;
}

/* The card is a flex column, so the last element decides where it ends. */
.mnt-card > :first-child { margin-top: 0; }
.mnt-card > :last-child  { margin-bottom: 0; }

/**
 * Pin an element to the bottom of a card regardless of how much copy sits
 * above it — this is what keeps a row of cards with uneven text looking
 * deliberate rather than broken.
 */
.mnt-card__foot {
	margin-top: auto;
	padding-top: var(--wp--preset--spacing--50);
}

/* Children that must not stretch to the card's full width. */
.mnt-card > .mnt-feature__icon,
.mnt-card > .mnt-badge,
.mnt-card > .mnt-eyebrow {
	align-self: flex-start;
}

.mnt-card--flush   { padding: 0; }
.mnt-card--tight   { padding: var(--wp--preset--spacing--50); }
.mnt-card--roomy   { padding: var(--wp--preset--spacing--70); }
.mnt-card--nested  { background: var(--wp--preset--color--surface-raised); border-radius: var(--wp--custom--radius--md); }

/* Interactive card — lifts and warms its border on hover. */
.mnt-card--interactive {
	transition:
		transform var(--wp--custom--duration--base) var(--wp--custom--ease--out),
		border-color var(--wp--custom--duration--base) var(--wp--custom--ease--out),
		background-color var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

/*
 * surface-raised, not base-raised. On light both `surface` and `base-raised`
 * are #FFFFFF — a card is already the lightest thing on the page, so hovering
 * it toward the "raised background" is a transition between two identical
 * values and the card simply does not respond. surface-raised is the token
 * that means "a step away from the card surface", and it moves in both themes.
 */
.mnt-card--interactive:hover {
	transform: translateY(-2px);
	border-color: var(--wp--preset--color--line-strong);
	background: var(--wp--preset--color--surface-raised);
}

/**
 * Spotlight card — an accent bloom follows the cursor.
 * Requires monitee.js (sets --mnt-mx / --mnt-my). Degrades to a static card.
 */
.mnt-card--spotlight::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	opacity: 0;
	background: radial-gradient(
		420px circle at var(--mnt-mx, 50%) var(--mnt-my, 0%),
		rgba(74, 87, 168, 0.06),
		transparent 65%
	);
	transition: opacity var(--wp--custom--duration--slow) var(--wp--custom--ease--out);
}

.mnt-card--spotlight:hover::before { opacity: 1; }

/* Gradient-border card — for the one card that must stand out (pricing, CTA). */
.mnt-card--accent {
	border-color: transparent;
	background:
		linear-gradient(var(--wp--preset--color--surface), var(--wp--preset--color--surface)) padding-box,
		linear-gradient(180deg, var(--wp--preset--color--line-accent), var(--wp--preset--color--line) 60%) border-box;
}

/* ==========================================================================
   3. Badges, chips, pills
   ========================================================================== */

.mnt-badge {
	display: inline-flex;
	align-items: center;
	gap: 0.4375rem;
	padding: 0.3125rem 0.75rem;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--surface-raised);
	border: 1px solid var(--wp--preset--color--line-strong);
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	line-height: 1.3;
	color: var(--wp--preset--color--text-muted);
	white-space: nowrap;
}

.mnt-badge__dot {
	width: 6px;
	height: 6px;
	border-radius: var(--wp--custom--radius--pill);
	background: currentColor;
	flex: none;
}

.mnt-badge--success { color: var(--wp--preset--color--success); border-color: rgba(10, 122, 76, 0.28); background: rgba(10, 122, 76, 0.09); }
.mnt-badge--warning { color: var(--wp--preset--color--warning); border-color: rgba(154, 90, 0, 0.28);  background: rgba(154, 90, 0, 0.09); }
.mnt-badge--danger  { color: var(--wp--preset--color--danger);  border-color: rgba(179, 45, 87, 0.28); background: rgba(179, 45, 87, 0.09); }
.mnt-badge--primary { color: var(--wp--preset--color--primary); border-color: rgba(74, 87, 168, 0.26); background: rgba(74, 87, 168, 0.08); }

/**
 * Address chip — the mono green host/IP badge straight out of the app.
 * A small, high-recognition detail; use it wherever a host appears.
 */
.mnt-addr {
	display: inline-block;
	padding: 0.1875rem 0.5rem;
	border-radius: var(--wp--custom--radius--xs);
	border: 1px solid rgba(10, 122, 76, 0.32);
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.8125rem;
	font-weight: 500;
	letter-spacing: 0;
	color: var(--wp--preset--color--success);
	background: rgba(10, 122, 76, 0.07);
}

/* Live pulse — for "real-time" claims. */
.mnt-pulse {
	position: relative;
	width: 8px;
	height: 8px;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--success);
	flex: none;
}

.mnt-pulse::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: inherit;
	animation: mnt-ping 2s var(--wp--custom--ease--out) infinite;
}

@keyframes mnt-ping {
	0%   { transform: scale(1);   opacity: 0.7; }
	70%  { transform: scale(2.6); opacity: 0; }
	100% { transform: scale(2.6); opacity: 0; }
}

/* ==========================================================================
   4. Buttons — secondary / ghost variants
   (Primary comes from theme.json elements.button.)
   ========================================================================== */

.wp-block-button.is-style-secondary .wp-block-button__link {
	background: var(--wp--preset--color--surface-raised);
	color: var(--wp--preset--color--text);
	border: 1px solid var(--wp--preset--color--line-strong);
	transition:
		background-color var(--wp--custom--duration--fast) var(--wp--custom--ease--out),
		border-color var(--wp--custom--duration--fast) var(--wp--custom--ease--out);
}

.wp-block-button.is-style-secondary .wp-block-button__link:hover {
	background: var(--wp--preset--color--surface-overlay);
	border-color: var(--wp--preset--color--line-accent);
	color: var(--wp--preset--color--text);
}

.wp-block-button.is-style-ghost .wp-block-button__link {
	background: transparent;
	color: var(--wp--preset--color--text-muted);
	border: 1px solid transparent;
	padding-left: 1rem;
	padding-right: 1rem;
}

.wp-block-button.is-style-ghost .wp-block-button__link:hover {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--text);
}

/* Primary buttons get the subtle vertical sheen the app uses on filled chips. */
.wp-block-button:not(.is-style-secondary):not(.is-style-ghost):not(.is-style-outline) .wp-block-button__link {
	background-image: var(--wp--preset--gradient--primary-sheen);
	transition:
		transform var(--wp--custom--duration--fast) var(--wp--custom--ease--out),
		box-shadow var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

.wp-block-button:not(.is-style-secondary):not(.is-style-ghost):not(.is-style-outline) .wp-block-button__link:hover {
	transform: translateY(-1px);
	box-shadow: 0 8px 28px -10px rgba(74, 87, 168, 0.45);
}

/* Arrow affordance on any button whose label ends with an arrow character. */
.mnt-arrow .wp-block-button__link::after,
a.mnt-arrow::after {
	content: "→";
	display: inline-block;
	margin-left: 0.4em;
	transition: transform var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

.mnt-arrow:hover .wp-block-button__link::after,
a.mnt-arrow:hover::after { transform: translateX(3px); }

/* ==========================================================================
   5. Backdrops — glow, grid, grain, hairline
   ========================================================================== */

/**
 * Section glow. Apply to a group; it paints an accent bloom behind its
 * content without affecting layout.
 */
.mnt-glow {
	position: relative;
	isolation: isolate;
}

/*
 * Bleeds upward but not sideways. The -10% each side it used to have was real
 * layout overflow — on a 390px phone that is 39px of page hanging off the
 * right — and it bought nothing: the gradient is 60% of the box wide, centred,
 * so it has faded to transparent long before it reaches an edge.
 */
.mnt-glow::before {
	content: "";
	position: absolute;
	z-index: -1;
	inset: -20% 0 auto;
	height: 70%;
	background: var(--wp--preset--gradient--primary-glow);
	pointer-events: none;
}

.mnt-glow--danger::before { background: var(--wp--preset--gradient--danger-glow); }
/*
 * The default glow is anchored `at 50% 0%`, so it is brightest along its own
 * top edge. That is fine when the box starts above the section and only the
 * fade is visible — but the centred variant puts that top edge in the middle
 * of the content, where it reads as a hard horizontal line straight through
 * whatever sits there. The centred variant therefore needs a centred gradient.
 */
.mnt-glow--center::before {
	inset: 50% 0 auto;
	transform: translateY(-50%);
	background: var(--wp--preset--gradient--primary-bloom);
}

.mnt-glow--center.mnt-glow--danger::before { background: var(--wp--preset--gradient--danger-glow); }

/* Grid backdrop — faint technical lattice, fading out at the edges. */
.mnt-grid-bg {
	position: relative;
	isolation: isolate;
}

.mnt-grid-bg::before {
	content: "";
	position: absolute;
	z-index: -1;
	inset: 0;
	background-image:
		linear-gradient(to right, rgba(124, 134, 171, 0.22) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(124, 134, 171, 0.22) 1px, transparent 1px);
	background-size: 64px 64px;
	mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 20%, transparent 75%);
	-webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 20%, transparent 75%);
	pointer-events: none;
}

/* Fading hairline divider. Use instead of a hard <hr> between sections. */
.mnt-hairline {
	height: 1px;
	border: 0;
	background: var(--wp--preset--gradient--hairline);
	margin: 0;
}

/*
 * Film grain — kills banding in the large dark gradients.
 *
 * Scoped to the dark theme because that is the only place it does a job. There
 * is no banding to hide on a near-white page, so all a noise layer contributes
 * there is dirt.
 */
:root[data-theme="dark"] .mnt-grain::after {
	content: "";
	position: fixed;
	inset: 0;
	z-index: 9999;
	pointer-events: none;
	opacity: var(--wp--custom--grain);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   6. Device frame + screenshot presentation
   ========================================================================== */

/**
 * Phone frame for the app screenshots. The bezel radius is tuned to the
 * 470x1024 exports on monitee.app so the screen corners sit flush.
 */
.mnt-device {
	/*
	 * The screenshots are full-bleed captures including the Android status
	 * bar, so the clock sits close to their own top-left corner. An 8px bezel
	 * with a 24px inner radius put the frame's curve right through it. A wider
	 * bezel and a gentler inner curve give that corner room to breathe.
	 */
	--mnt-bezel: 13px;

	position: relative;
	display: block;
	max-width: 300px;
	margin-inline: auto;
	padding: var(--mnt-bezel);
	border-radius: var(--wp--custom--radius--xl);
	background: linear-gradient(160deg, #2E313D 0%, #17181E 45%, #23252E 100%);
	box-shadow: var(--wp--preset--shadow--float);
}

.mnt-device img,
.mnt-device .wp-block-image img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: calc(var(--wp--custom--radius--xl) - var(--mnt-bezel) - 4px);
	background: var(--wp--preset--color--base);
}

.mnt-device--sm { max-width: 232px; --mnt-bezel: 11px; }
.mnt-device--lg { max-width: 340px; --mnt-bezel: 14px; }

/* Tilt the hero device slightly — depth without a 3D library. */
.mnt-device--tilt {
	transform: perspective(1400px) rotateX(4deg) rotateY(-9deg) rotateZ(1deg);
	transition: transform var(--wp--custom--duration--slow) var(--wp--custom--ease--out);
}

.mnt-device--tilt:hover {
	transform: perspective(1400px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
}

/**
 * Screenshot row — a staggered fan of phones. Center phone sits forward,
 * outer phones recede and dim. Collapses to a scroller on small screens.
 */
.mnt-fan {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: clamp(0.75rem, 2vw, 1.75rem);
	perspective: 1800px;
}

/*
 * The five phones are ~1500px of intrinsic width against a 1200px container,
 * so they must be allowed to shrink. With flex: none they simply overflowed
 * and the outer two got sliced off by the clip mask.
 */
.mnt-fan > * {
	flex: 0 1 auto;
	min-width: 0;
}

.mnt-fan .mnt-device      { width: 300px; }
.mnt-fan .mnt-device--sm  { width: 232px; }
.mnt-fan .mnt-device--lg  { width: 340px; }

/*
 * Depth in the fan comes from three things: translate, scale, and opacity. The
 * first two work identically in both themes; opacity does not.
 *
 * Fading a screenshot toward a near-black page pushes it back into shadow, and
 * reads as distance. Fading the same screenshot toward a near-white page
 * bleaches it, and reads as an image that has not finished loading. So the
 * light theme leans on translate and scale and barely touches opacity; section
 * 16 restores the deeper fade for dark.
 */
.mnt-fan > *:nth-child(odd)  { transform: translateY(2.5rem) scale(0.9);  opacity: 0.82; }
.mnt-fan > *:nth-child(even) { transform: translateY(1rem)   scale(0.96); opacity: 0.94; }
.mnt-fan > *:nth-child(3)    { transform: none; opacity: 1; z-index: 2; }

@media (max-width: 880px) {
	.mnt-fan {
		justify-content: flex-start;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		padding-block-end: var(--wp--preset--spacing--50);
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}
	.mnt-fan::-webkit-scrollbar { display: none; }
	.mnt-fan > * { transform: none !important; opacity: 1 !important; scroll-snap-align: center; }
}

/**
 * Bleed a screenshot off the bottom of its section — implies "there's more".
 *
 * A mask always fades to whatever is behind it, so the same declaration reads
 * as two different effects. On the dark theme a dark phone dissolving into a
 * near-black page is continuous: nothing changes hue, and the fade looks like
 * the bottom of the phone falling into shadow. On the light theme the phone
 * and the page have nothing in common, so a fade that long is 40% of the
 * image turning progressively grey — it reads as a rendering fault rather than
 * as depth.
 *
 * Light therefore holds the image solid until much further down and then cuts
 * quickly, which reads as a deliberate crop. Section 16 restores the long,
 * soft dissolve for dark.
 */
.mnt-clip-bottom {
	max-height: clamp(320px, 46vw, 560px);
	overflow: hidden;
	-webkit-mask-image: linear-gradient(180deg, #000 82%, transparent 100%);
	mask-image: linear-gradient(180deg, #000 82%, transparent 100%);
}

/* ==========================================================================
   7. Marquee — infinite logo / screenshot ribbon
   ========================================================================== */

.mnt-marquee {
	position: relative;
	overflow: hidden;
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
	mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

.mnt-marquee__track {
	display: flex;
	align-items: center;
	width: max-content;
	gap: var(--wp--preset--spacing--70);
	animation: mnt-scroll 42s linear infinite;
}

/*
 * Bare scrolling words read as decoration and float free of the page. Giving
 * each one a chip anchors the row to the surrounding surfaces, and the tight
 * variant stops it claiming a whole screen of its own.
 */
.mnt-marquee--tight {
	padding-block: var(--wp--preset--spacing--20);
}

.mnt-marquee__item {
	display: inline-flex;
	align-items: center;
	padding: 0.5rem 1.125rem;
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--text-muted);
	font-size: var(--wp--preset--font-size--small);
	white-space: nowrap;
}

.mnt-marquee:hover .mnt-marquee__track { animation-play-state: paused; }

@keyframes mnt-scroll {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

/* ==========================================================================
   8. Stats
   ========================================================================== */

.mnt-stat { text-align: center; }

.mnt-stat__value {
	display: block;
	font-size: var(--wp--preset--font-size--stat);
	font-weight: 600;
	line-height: 1;
	letter-spacing: var(--wp--custom--tracking--display);
	color: var(--wp--preset--color--text);
}

.mnt-stat__value sup,
.mnt-stat__unit {
	font-size: 0.45em;
	font-weight: 500;
	color: var(--wp--preset--color--text-faint);
	letter-spacing: 0;
	margin-left: 0.1em;
	vertical-align: baseline;
}

.mnt-stat__label {
	display: block;
	margin-top: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--text-muted);
}

.mnt-stat--primary .mnt-stat__value { color: var(--wp--preset--color--primary); }
.mnt-stat--danger  .mnt-stat__value { color: var(--wp--preset--color--danger); }

/* ==========================================================================
   9. Feature list — icon + text rows
   ========================================================================== */

.mnt-feature__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: var(--wp--custom--radius--sm);
	background: var(--wp--preset--color--surface-raised);
	border: 1px solid var(--wp--preset--color--line-strong);
	color: var(--wp--preset--color--primary);
	font-size: 1.125rem;
	margin-bottom: var(--wp--preset--spacing--40);
	flex: none;
}

.mnt-feature__icon svg { width: 20px; height: 20px; }

/* ==========================================================================
   9b. Install method card
   ========================================================================== */

.mnt-method {
	text-decoration: none;
	color: inherit;
	gap: 0.25rem;
}

.mnt-method:hover { text-decoration: none; }

.mnt-method__name {
	font-size: var(--wp--preset--font-size--heading-3);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--heading);
	color: var(--wp--preset--color--text);
}

.mnt-method__detail {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--text-muted);
}

.mnt-method .mnt-card__foot { padding-top: var(--wp--preset--spacing--40); }

/* ==========================================================================
   9ba. Route list — install methods inside a category card
   ========================================================================== */

.mnt-routes {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--wp--preset--spacing--20);
}

.mnt-routes__link {
	display: block;
	padding: var(--wp--preset--spacing--40);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--md);
	background: var(--wp--preset--color--surface-raised);
	text-decoration: none;
	color: inherit;
	transition:
		border-color var(--wp--custom--duration--fast) var(--wp--custom--ease--out),
		background-color var(--wp--custom--duration--fast) var(--wp--custom--ease--out);
}

.mnt-routes__link:hover {
	border-color: var(--wp--preset--color--line-accent);
	background: var(--wp--preset--color--surface-overlay);
	text-decoration: none;
}

/*
 * A route is a title, a badge and an arrow on one line. It used to carry a
 * paragraph of explanation underneath, which is why this had a bottom margin —
 * there is nothing under it now, and the explaining belongs to the guide.
 */
.mnt-routes__head {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: wrap;
}

.mnt-routes__name {
	font-weight: 600;
	color: var(--wp--preset--color--text);
}

.mnt-routes__arrow {
	margin-left: auto;
	color: var(--wp--preset--color--text-faint);
	transition: transform var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

.mnt-routes__link:hover .mnt-routes__arrow {
	transform: translateX(3px);
	color: var(--wp--preset--color--primary);
}

/* Let a long name shrink rather than push the badge and arrow out of the row. */
.mnt-routes__name {
	min-width: 0;
}

/* ==========================================================================
   9bb. Numbered steps
   ========================================================================== */

.mnt-step {
	display: flex;
	gap: var(--wp--preset--spacing--50);
	align-items: flex-start;
}

.mnt-step__num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 40px;
	height: 40px;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--primary-container);
	border: 1px solid var(--wp--preset--color--line-accent);
	color: var(--wp--preset--color--primary);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
}

.mnt-step__title {
	font-size: var(--wp--preset--font-size--heading-2);
	line-height: var(--wp--custom--leading--heading);
	letter-spacing: var(--wp--custom--tracking--heading);
	margin: 0 0 0.5rem;
}

.mnt-step__body {
	color: var(--wp--preset--color--text-muted);
	font-size: var(--wp--preset--font-size--lead);
	max-width: 62ch;
	margin: 0;
}

/* ==========================================================================
   9c. Terminal
   ==========================================================================
   One of the three things that deliberately do not flip with the theme, and so
   one of the three places in this file allowed literals instead of tokens —
   the others being the device bezel in section 6 and the rendered-markdown
   code block in section 20.

   A terminal is a dark object. Everyone who will read these commands has one
   open on another screen right now, and it is not white. Recolouring the
   chrome to match the page would make the block read as a quotation of the
   site rather than as machine output — which is the whole reason it is set in
   mono to begin with. Same argument, and the same literals, as the rendered
   markdown code block in section 20.
   ========================================================================== */

.mnt-terminal {
	border: 1px solid #23252E;
	border-radius: var(--wp--custom--radius--md);
	background: #14161C;
	overflow: hidden;
	box-shadow: var(--wp--preset--shadow--raised);
}

.mnt-terminal__bar {
	display: flex;
	align-items: center;
	gap: 0.4375rem;
	padding: 0.6875rem 0.875rem;
	background: #1A1C24;
	border-bottom: 1px solid #23252E;
}

.mnt-terminal__dot {
	width: 10px;
	height: 10px;
	border-radius: var(--wp--custom--radius--pill);
	background: #353B4D;
	flex: none;
}

.mnt-terminal__title {
	margin-left: auto;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--micro);
	color: #7B839F;
}

.mnt-terminal__body {
	margin: 0;
	padding: var(--wp--preset--spacing--50);
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.8125rem;
	line-height: 1.75;
	color: #E4E5F0;
	overflow-x: auto;
	white-space: pre;
	tab-size: 2;
}

.mnt-terminal__body code {
	font-family: inherit;
	font-size: inherit;
	background: none;
	padding: 0;
	color: inherit;
}

/* Comment and string tokens. Literals, for the reason above. */
.mnt-terminal__body .mnt-c { color: #7B839F; }
.mnt-terminal__body .mnt-s { color: #4ADE9B; }

/* Checklist — replaces bullet discs with accent-coloured ticks. */
.mnt-checklist {
	list-style: none;
	padding-left: 0;
	margin: 0;
	display: grid;
	gap: var(--wp--preset--spacing--30);
}

.mnt-checklist li {
	position: relative;
	padding-left: 1.75rem;
	color: var(--wp--preset--color--text-muted);
}

.mnt-checklist li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.45em;
	width: 14px;
	height: 8px;
	border-left: 2px solid var(--wp--preset--color--primary);
	border-bottom: 2px solid var(--wp--preset--color--primary);
	transform: rotate(-45deg);
	border-radius: 1px;
}

/* ==========================================================================
   10. Header
   ========================================================================== */

.mnt-header {
	position: sticky;
	top: 0;
	z-index: 100;
	border-bottom: 1px solid transparent;
	transition: border-color var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

/*
 * The frosted pane is a pseudo-element, not the header itself, and that is
 * load-bearing rather than tidiness.
 *
 * backdrop-filter makes an element a containing block for every fixed-position
 * descendant. The mobile navigation overlay is `position: fixed; inset: 0`, so
 * with the filter on .mnt-header it sized itself to the 60px-tall header
 * instead of the viewport — the menu opened as a sliver showing only its first
 * link, which looked like the menu had lost its other items. Moving the filter
 * down to a child takes the header out of that chain and the overlay resolves
 * against the viewport again.
 */
.mnt-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: rgba(251, 251, 253, 0.75);
	backdrop-filter: saturate(160%) blur(14px);
	-webkit-backdrop-filter: saturate(160%) blur(14px);
	pointer-events: none;
}

/* Border only appears once the page has scrolled — set by monitee.js. */
.mnt-header.is-stuck { border-bottom-color: var(--wp--preset--color--line); }

@supports not (backdrop-filter: blur(1px)) {
	.mnt-header::before { background: var(--wp--preset--color--base); }
}

/*
 * The header lives outside the post content, so nothing gives it the root
 * padding every other section gets — .alignwide inside a flow layout is inert,
 * which left the brand hard against the left edge and the Get started button
 * hard against the right. Constrain and pad it here rather than in the
 * template, so it cannot be lost by an editor saving the header part.
 */
.mnt-header > .wp-block-group {
	max-width: var(--wp--style--global--wide-size, 1200px);
	margin-inline: auto;
	padding-inline: var(--wp--style--root--padding-left, 1.25rem) var(--wp--style--root--padding-right, 1.25rem);
}

/* Below the nav breakpoint the overlay menu carries the links; the inline CTA
   would only crowd the logo. */
@media (max-width: 599px) {
	.mnt-header__cta { display: none; }
}

/*
 * Brand — the app icon and wordmark, and the only link back to the front page.
 *
 * Written into parts/header.html rather than assembled from site-logo and
 * site-title, both of which render literally nothing until somebody fills them
 * in under Settings and the Customizer. Nobody had, so the header's left-hand
 * group was empty markup and no page had a link home. The one link every page
 * needs should not depend on a field in wp-admin.
 */
.mnt-brand {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	flex: none;
	text-decoration: none;
	color: var(--wp--preset--color--text);
	font-weight: 600;
	letter-spacing: var(--wp--custom--tracking--heading);
}

.mnt-brand:hover {
	text-decoration: none;
	color: var(--wp--preset--color--text);
}

/*
 * The app icon is a pure-white glyph on transparency — correct on the dark
 * theme, invisible on the light one. It has no colour to preserve, so a
 * straight inversion turns it black rather than doing anything clever.
 * Swap in a two-tone icon and this filter is the thing to delete.
 */
.mnt-brand__mark {
	width: 28px;
	height: 28px;
	flex: none;
	filter: invert(1);
	transition: transform var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

.mnt-brand:hover .mnt-brand__mark {
	transform: scale(1.06);
}

/*
 * On the narrowest phones the wordmark is the first thing that can go: the
 * icon alone still identifies the site and still links home, and the row has
 * a hamburger and a theme toggle to fit beside it.
 */
@media (max-width: 380px) {
	.mnt-brand__name { display: none; }
}

/* ==========================================================================
   10b. Details / FAQ
   ========================================================================== */

.wp-block-details summary {
	cursor: pointer;
	font-weight: 600;
	list-style: none;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--40);
}

.wp-block-details summary::-webkit-details-marker { display: none; }

.wp-block-details summary::after {
	content: "";
	flex: none;
	width: 9px;
	height: 9px;
	border-right: 2px solid var(--wp--preset--color--text-faint);
	border-bottom: 2px solid var(--wp--preset--color--text-faint);
	transform: rotate(45deg) translate(-2px, -2px);
	transition: transform var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

.wp-block-details[open] summary::after {
	transform: rotate(-135deg) translate(-2px, -2px);
}

.wp-block-details summary:hover { color: var(--wp--preset--color--primary); }
.wp-block-details summary:hover::after { border-color: var(--wp--preset--color--primary); }

/* ==========================================================================
   11. Footer
   ========================================================================== */

.mnt-footer {
	border-top: 1px solid var(--wp--preset--color--line);
	background: var(--wp--preset--color--base-sunken);
}

.mnt-footer a { color: var(--wp--preset--color--text-muted); }
.mnt-footer a:hover { color: var(--wp--preset--color--text); text-decoration: none; }

.mnt-footer__list {
	list-style: none;
	padding-left: 0;
	display: grid;
	gap: var(--wp--preset--spacing--20);
}

/* ==========================================================================
   12. Scroll reveal
   ========================================================================== */

.mnt-reveal {
	opacity: 0;
	transform: translateY(16px);
	transition:
		opacity var(--wp--custom--duration--slow) var(--wp--custom--ease--out),
		transform var(--wp--custom--duration--slow) var(--wp--custom--ease--out);
}

.mnt-reveal.is-visible {
	opacity: 1;
	transform: none;
}

/* Stagger children of a revealed container. */
.mnt-reveal-group > * { transition-delay: calc(var(--mnt-i, 0) * 70ms); }

/* No JS? Never hide content. */
.no-js .mnt-reveal,
html:not(.js) .mnt-reveal {
	opacity: 1;
	transform: none;
}

/* ==========================================================================
   13. Layout utilities
   ========================================================================== */

/* Full-bleed background, constrained content — for coloured sections. */
.mnt-section {
	padding-block: var(--wp--preset--spacing--90);
}

.mnt-section--lg { padding-block: var(--wp--preset--spacing--100); }
.mnt-section--flush-top { padding-block-start: 0; }

/* Asymmetric two-column split used by the alternating feature sections. */
.mnt-split {
	display: grid;
	gap: clamp(2rem, 5vw, 4.5rem);
	align-items: center;
	grid-template-columns: 1fr;
}

@media (min-width: 900px) {
	.mnt-split { grid-template-columns: 1.05fr 0.95fr; }
	.mnt-split--reverse > *:first-child { order: 2; }
}

/* Even grid of equal-height cards. */
.mnt-grid-equal {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}

.mnt-grid-equal--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }

/*
 * auto-fit only caps the column count by available width, so at 1200px a
 * 340px minimum still yields three columns and leaves a ragged final row.
 * When the variant is asked for by name, honour the name.
 */
@media (min-width: 900px) {
	.mnt-grid-equal--2 { grid-template-columns: repeat(2, 1fr); }
}

/* Bento grid — mixed-size feature cards. */
.mnt-bento {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}

@media (min-width: 900px) {
	.mnt-bento { grid-template-columns: repeat(6, 1fr); }
	.mnt-bento > .mnt-span-2 { grid-column: span 2; }
	.mnt-bento > .mnt-span-3 { grid-column: span 3; }
	.mnt-bento > .mnt-span-4 { grid-column: span 4; }
	.mnt-bento > .mnt-span-6 { grid-column: span 6; }
}

/* ==========================================================================
   14. Motion & accessibility
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	.mnt-reveal { opacity: 1; transform: none; }
	.mnt-device--tilt { transform: none; }
	.mnt-marquee__track { animation: none; }
	.mnt-fan { overflow-x: auto; }
}

@media (prefers-contrast: more) {
	.mnt-card { border-color: var(--wp--preset--color--line-strong); }
	.mnt-eyebrow,
	.mnt-checklist li { color: var(--wp--preset--color--text); }
}

.mnt-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.mnt-skip-link {
	position: absolute;
	left: 50%;
	top: 0.5rem;
	transform: translate(-50%, -200%);
	z-index: 1000;
	padding: 0.75rem 1.25rem;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--on-primary);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	transition: transform var(--wp--custom--duration--base) var(--wp--custom--ease--out);
}

.mnt-skip-link:focus { transform: translate(-50%, 0); }

/* ==========================================================================
   15. Print
   ========================================================================== */

@media print {
	.mnt-header,
	.mnt-footer,
	.mnt-grain::after { display: none; }
	body { background: #fff; color: #000; }
}

/* Trailing "see everything" cell that squares off an odd-numbered card grid. */
.mnt-method--more {
	background: transparent;
	border-style: dashed;
	border-color: var(--wp--preset--color--line-strong);
	box-shadow: none;
	justify-content: center;
}

.mnt-method--more:hover {
	background: var(--wp--preset--color--surface-raised);
	border-style: solid;
}

.mnt-method--more .mnt-method__detail {
	color: var(--wp--preset--color--text-faint);
}

/* ==========================================================================
   16. Dark theme
   ==========================================================================
   Light is the default, because that is how most people meet a web page and
   because the app itself now ships a light theme — a light site putting dark
   screenshots on a white page would be the mismatch the dark-only rule was
   written to avoid. Dark stays a first-class theme, not a courtesy: it is
   what the product looked like for its whole life, and a homelabber reading
   this at 1am should get it.

   theme.json writes the light presets onto :root, so overriding them under an
   attribute selector wins on specificity without !important and without
   touching a single component rule — every .mnt-* class keeps referring to the
   same token names and simply resolves to different values.

   Every text and status colour below clears 4.5:1 against base, surface and
   surface-raised. Do not eyeball replacements; measure them.
   ========================================================================== */

:root[data-theme="dark"] {
	color-scheme: dark;

	--wp--preset--color--base: #0D0E12;
	--wp--preset--color--base-sunken: #0B0C0F;
	--wp--preset--color--base-raised: #121318;
	--wp--preset--color--surface: #181920;
	--wp--preset--color--surface-raised: #23252E;
	--wp--preset--color--surface-overlay: #2B2E3A;

	--wp--preset--color--line: #22242D;
	--wp--preset--color--line-strong: #353B4D;
	--wp--preset--color--line-accent: #465174;

	--wp--preset--color--text: #E4E5F0;
	--wp--preset--color--text-muted: #A9AAB5;
	--wp--preset--color--text-faint: #7B839F;

	--wp--preset--color--primary: #BAC5EE;
	--wp--preset--color--primary-soft: #AAB4DA;
	--wp--preset--color--primary-container: #353B4D;
	--wp--preset--color--on-primary: #0D0E12;

	--wp--preset--color--success: #00A15D;
	--wp--preset--color--warning: #FFAE58;
	--wp--preset--color--danger: #E36688;
	--wp--preset--color--critical: #F2B8B5;

	--wp--preset--color--series-1: #4C84E7;
	--wp--preset--color--series-2: #009D87;
	--wp--preset--color--series-3: #D67D24;

	/*
	 * On a #0D0E12 background a drop shadow reads as nothing, so depth comes
	 * from a 1px top highlight instead — the trick Material 3 uses on dark
	 * surfaces. The light theme does the opposite and uses real shadows.
	 */
	--wp--preset--shadow--hairline: inset 0 1px 0 rgba(255, 255, 255, 0.045);
	--wp--preset--shadow--card: inset 0 1px 0 rgba(255, 255, 255, 0.045), 0 1px 2px rgba(0, 0, 0, 0.5);
	--wp--preset--shadow--raised: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 8px 24px -8px rgba(0, 0, 0, 0.7);
	--wp--preset--shadow--float: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 32px 80px -24px rgba(0, 0, 0, 0.85), 0 0 0 1px #23252E;
	--wp--preset--shadow--glow: 0 0 0 1px rgba(186, 197, 238, 0.35), 0 0 32px -8px rgba(186, 197, 238, 0.4);

	--wp--preset--gradient--surface-edge: linear-gradient(180deg, #1F212B 0%, #181920 42%);
	--wp--preset--gradient--hero-veil: linear-gradient(180deg, rgba(13,14,18,0) 0%, rgba(13,14,18,0.85) 65%, #0D0E12 100%);
	--wp--preset--gradient--primary-glow: radial-gradient(60% 60% at 50% 0%, rgba(186,197,238,0.16) 0%, rgba(186,197,238,0) 100%);
	--wp--preset--gradient--primary-bloom: radial-gradient(50% 50% at 50% 50%, rgba(186,197,238,0.13) 0%, rgba(186,197,238,0) 100%);
	--wp--preset--gradient--danger-glow: radial-gradient(50% 50% at 50% 50%, rgba(227,102,136,0.18) 0%, rgba(227,102,136,0) 100%);
	--wp--preset--gradient--hairline: linear-gradient(90deg, rgba(53,59,77,0) 0%, #353B4D 50%, rgba(53,59,77,0) 100%);
	--wp--preset--gradient--primary-sheen: linear-gradient(180deg, #CBD3F3 0%, #BAC5EE 100%);
}

/*
 * Component values that do not come from a token, and so do not flip with the
 * palette. Each needs a dark counterpart or it reads as washed out.
 */
:root[data-theme="dark"] ::selection {
	background: rgba(186, 197, 238, 0.28);
}

/* Light spilling onto a dark surface. See section 1 for why light gets none. */
:root[data-theme="dark"] .mnt-eyebrow::before          { box-shadow: 0 0 12px rgba(186, 197, 238, 0.8); }
:root[data-theme="dark"] .mnt-eyebrow--success::before { box-shadow: 0 0 12px rgba(0, 161, 93, 0.9); }
:root[data-theme="dark"] .mnt-eyebrow--warning::before { box-shadow: 0 0 12px rgba(255, 174, 88, 0.9); }
:root[data-theme="dark"] .mnt-eyebrow--danger::before  { box-shadow: 0 0 12px rgba(227, 102, 136, 0.9); }

:root[data-theme="dark"] .mnt-gradient-text {
	background: linear-gradient(180deg, var(--wp--preset--color--text) 30%, rgba(228, 229, 240, 0.62) 100%);
	-webkit-background-clip: text;
	background-clip: text;
}

:root[data-theme="dark"] .mnt-badge--success { background: rgba(0, 161, 93, 0.1);    border-color: rgba(0, 161, 93, 0.35); }
:root[data-theme="dark"] .mnt-badge--warning { background: rgba(255, 174, 88, 0.1);  border-color: rgba(255, 174, 88, 0.35); }
:root[data-theme="dark"] .mnt-badge--danger  { background: rgba(227, 102, 136, 0.1); border-color: rgba(227, 102, 136, 0.35); }
:root[data-theme="dark"] .mnt-badge--primary { background: rgba(186, 197, 238, 0.08); border-color: rgba(186, 197, 238, 0.3); }

:root[data-theme="dark"] .mnt-addr {
	background: rgba(0, 161, 93, 0.07);
	border-color: rgba(0, 161, 93, 0.45);
}

:root[data-theme="dark"] .mnt-card--spotlight::before {
	background: radial-gradient(420px circle at var(--mnt-mx, 50%) var(--mnt-my, 0%), rgba(186, 197, 238, 0.09), transparent 65%);
}

:root[data-theme="dark"] .wp-block-button:not(.is-style-secondary):not(.is-style-ghost):not(.is-style-outline) .wp-block-button__link:hover {
	box-shadow: 0 8px 28px -10px rgba(186, 197, 238, 0.55);
}

:root[data-theme="dark"] .mnt-grid-bg::before {
	background-image:
		linear-gradient(to right, rgba(53, 59, 77, 0.4) 1px, transparent 1px),
		linear-gradient(to bottom, rgba(53, 59, 77, 0.4) 1px, transparent 1px);
}

/*
 * The hero fan and its bottom fade. Section 6 explains why these are the two
 * places where a single value could not serve both themes.
 *
 * The third phone needs restating rather than inheriting: three is odd, and
 * the rule above it here outranks section 6's :nth-child(3) on specificity.
 * Without this line the phone the whole hero is built around would be the one
 * dimmed to 55%.
 */
:root[data-theme="dark"] .mnt-fan > *:nth-child(odd)  { opacity: 0.55; }
:root[data-theme="dark"] .mnt-fan > *:nth-child(even) { opacity: 0.8; }
:root[data-theme="dark"] .mnt-fan > *:nth-child(3)    { opacity: 1; }

:root[data-theme="dark"] .mnt-clip-bottom {
	-webkit-mask-image: linear-gradient(180deg, #000 60%, transparent 100%);
	mask-image: linear-gradient(180deg, #000 60%, transparent 100%);
}

:root[data-theme="dark"] .mnt-header::before {
	background: rgba(13, 14, 18, 0.72);
}

@supports not (backdrop-filter: blur(1px)) {
	.mnt-header::before { background: var(--wp--preset--color--base); }
}

/* The white glyph needs no help here; see section 10 for the inversion. */
:root[data-theme="dark"] .mnt-brand__mark {
	filter: none;
}

:root[data-theme="dark"] .mnt-method--more:hover {
	background: var(--wp--preset--color--surface);
}

/* ==========================================================================
   17. Theme toggle
   ========================================================================== */

.mnt-theme-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	flex: none;
	padding: 0;
	border: 1px solid var(--wp--preset--color--line-strong);
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--surface-raised);
	color: var(--wp--preset--color--text-muted);
	cursor: pointer;
	transition:
		color var(--wp--custom--duration--fast) var(--wp--custom--ease--out),
		border-color var(--wp--custom--duration--fast) var(--wp--custom--ease--out),
		background-color var(--wp--custom--duration--fast) var(--wp--custom--ease--out);
}

.mnt-theme-toggle:hover {
	color: var(--wp--preset--color--text);
	border-color: var(--wp--preset--color--line-accent);
	background: var(--wp--preset--color--surface-overlay);
}

.mnt-theme-toggle svg {
	width: 17px;
	height: 17px;
}

/*
 * Show the icon for the theme you would switch TO, not the one you are in —
 * the button is an action, not a status readout. Keyed off :not(dark) so it
 * is still correct before the boot script sets the attribute, which is also
 * the state a page renders in when the attribute never arrives at all.
 */
:root:not([data-theme="dark"]) .mnt-theme-toggle__moon { display: block; }
:root:not([data-theme="dark"]) .mnt-theme-toggle__sun  { display: none; }

:root[data-theme="dark"] .mnt-theme-toggle__moon { display: none; }
:root[data-theme="dark"] .mnt-theme-toggle__sun  { display: block; }

/* Without JS the button cannot do anything, so do not offer it. */
html:not(.js) .mnt-theme-toggle { display: none; }

/* ==========================================================================
   18. Mobile
   ==========================================================================
   The app is Android-only, so most of this traffic is a phone. These are
   corrections where a desktop-first value actively fails at 400px, not
   cosmetic polish.
   ========================================================================== */

@media (max-width: 880px) {
	/*
	 * The fan must NOT shrink on a phone. flex: 0 1 auto let five devices
	 * compress to about 60px wide each — legible on a desktop mock, useless
	 * on the device most of these visitors are holding. Fixed widths plus a
	 * snap scroller shows one readable screenshot at a time.
	 */
	.mnt-fan > * {
		flex: none !important;
	}

	.mnt-fan .mnt-device,
	.mnt-fan .mnt-device--sm,
	.mnt-fan .mnt-device--lg {
		width: min(68vw, 290px);
		max-width: none;
	}

	/* Let more of the phone show before the fade takes over. */
	.mnt-clip-bottom {
		max-height: clamp(380px, 105vw, 560px);
	}
}

@media (max-width: 599px) {
	/* 32px of padding on each side of a 412px screen is a third of the width. */
	.mnt-card {
		padding: var(--wp--preset--spacing--50);
	}

	.mnt-card--roomy {
		padding: var(--wp--preset--spacing--60);
	}

	.mnt-card--tight {
		padding: var(--wp--preset--spacing--40);
	}

	/* Vertical rhythm tuned for a wide viewport becomes a lot of scrolling. */
	.mnt-section {
		padding-block: var(--wp--preset--spacing--80);
	}

	.mnt-section--lg {
		padding-block: var(--wp--preset--spacing--90);
	}

	/* Stack the numbered steps so the heading gets the full width. */
	.mnt-step {
		gap: var(--wp--preset--spacing--40);
	}

	.mnt-step__num {
		width: 32px;
		height: 32px;
		font-size: var(--wp--preset--font-size--small);
	}

	.mnt-hero-badge,
	.mnt-badge {
		white-space: normal;
	}

	/* Full-width CTAs are easier to hit than centred pills. */
	.wp-block-buttons > .wp-block-button {
		width: 100%;
	}

	.wp-block-buttons > .wp-block-button .wp-block-button__link {
		display: block;
		width: 100%;
		text-align: center;
	}

	.mnt-terminal__body {
		font-size: 0.75rem;
		padding: var(--wp--preset--spacing--40);
	}
}

/*
 * Belt and braces for the empty-title case. The render filter removes it on
 * the front end; this covers the editor, where the block is always rendered
 * so you can click into it.
 */
.wp-block-post-title:empty {
	display: none;
}

/* ==========================================================================
   19. Pro feature list
   ========================================================================== */

.mnt-prolist {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

.mnt-prolist li {
	position: relative;
	padding-left: 1.75rem;
}

.mnt-prolist li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.4em;
	width: 14px;
	height: 8px;
	border-left: 2px solid var(--wp--preset--color--primary);
	border-bottom: 2px solid var(--wp--preset--color--primary);
	transform: rotate(-45deg);
	border-radius: 1px;
}

.mnt-prolist__name {
	display: block;
	font-weight: 600;
	color: var(--wp--preset--color--text);
	margin-bottom: 0.1875rem;
}

.mnt-prolist__note {
	display: block;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.55;
	color: var(--wp--preset--color--text-muted);
}

/*
 * Title-less pages should not open with a title's worth of space.
 *
 * The render filter removes an empty post-title element entirely, but the
 * template's section padding remains — sized on the assumption that a heading
 * follows it. When no title rendered, tighten the top so the content is not
 * pushed down past a heading that is not there.
 *
 * :has() is unsupported in older browsers, where this simply does not apply
 * and the page keeps its original (larger) spacing. Nothing breaks.
 */
main.mnt-section:not(:has(> .wp-block-post-title)) {
	padding-block-start: var(--wp--preset--spacing--50);
}

/* ==========================================================================
   20. Rendered markdown
   ==========================================================================
   Documents from Git drops GitHub's own rendered markdown HTML into
   .markdown-body and enqueues github-markdown-css alongside it — a light-only
   stylesheet from before GitHub had a dark mode. Every colour in it is a
   literal: #24292e body text, #6a737d muted, #fff table rows, #f6f8fa code.
   On the dark theme that is dark grey on dark grey; on the light one it is a
   second, unrelated set of greys sitting next to ours.

   The plugin's stylesheet is enqueued before the theme's, so matching its
   specificity is enough to win. No !important, and nothing to paste into the
   plugin's "additional CSS" box — this file is the only place it lives.

   Everything here resolves to a token, so section 16 handles the dark theme
   for free: the same rules pick up the swapped values. The exceptions are the
   code block and its syntax colours, noted where they happen.
   ========================================================================== */

.markdown-body {
	/* Permalink glyph, recoloured through a mask — see .anchor below. */
	--mnt-md-anchor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z'/%3E%3C/svg%3E");

	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--body);
	line-height: var(--wp--custom--leading--body);
	letter-spacing: var(--wp--custom--tracking--body);
	color: var(--wp--preset--color--text);
}

/* --- Headings ------------------------------------------------------------ */

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
	margin: var(--wp--preset--spacing--60) 0 var(--wp--preset--spacing--40);
	font-weight: 600;
	line-height: var(--wp--custom--leading--heading);
	letter-spacing: var(--wp--custom--tracking--heading);
	color: var(--wp--preset--color--text);
}

/*
 * A prose ramp, not the landing page's. heading-1 and heading-2 are 3.5rem and
 * 2.5rem — display sizes tuned for a full-bleed hero, and wrong inside a 760px
 * column that already spends heading-1 on the post title above. h3 downwards
 * are the real tokens; h1 and h2 step down to meet them.
 */
.markdown-body h1 { font-size: 2rem; }
.markdown-body h2 { font-size: 1.5rem; }
.markdown-body h3 { font-size: var(--wp--preset--font-size--heading-3); }
.markdown-body h4 { font-size: var(--wp--preset--font-size--lead); }
.markdown-body h5 { font-size: var(--wp--preset--font-size--body); }

.markdown-body h6 {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--text-faint);
}

.markdown-body h1,
.markdown-body h2 {
	padding-bottom: var(--wp--preset--spacing--20);
	border-bottom: 1px solid var(--wp--preset--color--line);
}

/*
 * GitHub's API wraps every heading in a .markdown-heading div and puts the
 * permalink anchor *after* the heading rather than inside it, so none of
 * github-markdown-css's anchor rules match — the icon never gets its artwork
 * and the float has nothing to clear. Rebuild it as a flex row and carry the
 * heading's vertical rhythm on the wrapper, so those margins still collapse
 * with the surrounding blocks instead of being trapped in the flex container.
 */
.markdown-body .markdown-heading {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin: var(--wp--preset--spacing--60) 0 var(--wp--preset--spacing--40);
}

.markdown-body .markdown-heading > :where(h1, h2, h3, h4, h5, h6) {
	flex: 0 1 auto;
	min-width: 0;
	margin: 0;
}

/*
 * The rule under h1 and h2 belongs to the column, not to the run of text, so
 * where there is a wrapper it carries the border and the heading gives it up —
 * otherwise a flex item shrunk to its content underlines only the words.
 *
 * Without :has() the border stays on the heading and is text-width instead of
 * full-width. Nothing breaks; it is simply a little tighter.
 */
.markdown-body .markdown-heading:has(> h1),
.markdown-body .markdown-heading:has(> h2) {
	padding-bottom: var(--wp--preset--spacing--20);
	border-bottom: 1px solid var(--wp--preset--color--line);
}

.markdown-body .markdown-heading:has(> h1) > h1,
.markdown-body .markdown-heading:has(> h2) > h2 {
	padding-bottom: 0;
	border-bottom: 0;
}

.markdown-body .anchor {
	float: none;
	flex: none;
	display: inline-flex;
	align-items: center;
	margin: 0;
	padding: 0;
	color: var(--wp--preset--color--text-faint);
	opacity: 0;
	transition: opacity var(--wp--custom--duration--fast) var(--wp--custom--ease--out);
}

.markdown-body .markdown-heading:hover .anchor,
.markdown-body :where(h1, h2, h3, h4, h5, h6):hover .anchor,
.markdown-body .anchor:focus-visible {
	opacity: 1;
}

.markdown-body .anchor:hover {
	color: var(--wp--preset--color--primary);
}

/*
 * The stylesheet's own glyph is a data-URI background-image with #1b1f23 baked
 * into the path — literally invisible here, and unreachable from CSS. Painting
 * currentColor through a mask makes it follow the theme.
 */
.markdown-body .anchor .octicon-link {
	display: block;
	width: 15px;
	height: 15px;
	visibility: visible;
	color: inherit;
	background-color: currentColor;
	background-image: none;
	-webkit-mask: var(--mnt-md-anchor) center / contain no-repeat;
	mask: var(--mnt-md-anchor) center / contain no-repeat;
}

/* --- Flow ---------------------------------------------------------------- */

.markdown-body p,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body pre,
.markdown-body table,
.markdown-body details,
.markdown-body blockquote,
.markdown-body .highlight {
	margin-top: 0;
	margin-bottom: var(--wp--preset--spacing--40);
}

.markdown-body a {
	color: var(--wp--preset--color--primary);
	text-decoration: none;
}

.markdown-body a:hover {
	color: var(--wp--preset--color--text);
	text-decoration: underline;
}

.markdown-body strong,
.markdown-body b {
	font-weight: 600;
	color: var(--wp--preset--color--text);
}

.markdown-body ul,
.markdown-body ol {
	padding-left: 1.5rem;
}

.markdown-body li + li {
	margin-top: var(--wp--preset--spacing--10);
}

.markdown-body li > p {
	margin-top: var(--wp--preset--spacing--30);
}

.markdown-body li::marker {
	color: var(--wp--preset--color--text-faint);
}

.markdown-body dl dt {
	margin-top: var(--wp--preset--spacing--40);
	font-weight: 600;
	color: var(--wp--preset--color--text);
}

.markdown-body dl dd {
	margin-bottom: var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--text-muted);
}

.markdown-body blockquote {
	padding: 0 0 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--text-muted);
	border-left: 2px solid var(--wp--preset--color--line-accent);
}

.markdown-body summary {
	cursor: pointer;
	font-weight: 600;
	color: var(--wp--preset--color--text);
}

/* Same fading hairline the Separator block's theme style uses. */
.markdown-body hr {
	height: 1px;
	margin: var(--wp--preset--spacing--60) 0;
	background: var(--wp--preset--gradient--hairline);
	border: 0;
}

/* --- Code ---------------------------------------------------------------- */

.markdown-body code,
.markdown-body tt {
	padding: 0.15em 0.4em;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.875em;
	color: var(--wp--preset--color--text);
	background: var(--wp--preset--color--surface-raised);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--xs);
}

/*
 * A code block stays dark in both themes, for the reason .mnt-terminal does:
 * this is machine output, and a terminal is a dark object. The literals are
 * the terminal's — they cannot come from tokens, because tokens flip and this
 * block deliberately does not.
 */
.markdown-body pre,
.markdown-body .highlight pre {
	padding: var(--wp--preset--spacing--50);
	overflow-x: auto;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.8125rem;
	line-height: 1.75;
	tab-size: 2;
	color: #E4E5F0;
	background: #14161C;
	border: 1px solid #23252E;
	border-radius: var(--wp--custom--radius--md);
}

/* The chip treatment is for code inside a sentence, not a whole block. */
.markdown-body pre code,
.markdown-body pre tt {
	padding: 0;
	font-size: inherit;
	color: inherit;
	background: none;
	border: 0;
	border-radius: 0;
}

/*
 * Syntax tokens, for the same reason, are literals rather than tokens: they
 * sit on that permanently dark block. Values are the dark palette's, and the
 * mapping follows rule 2 of the design system — colour means something.
 */
.markdown-body .pl-c,
.markdown-body .pl-c span {
	color: #7B839F;
	font-style: italic;
}

.markdown-body .pl-s,
.markdown-body .pl-pds,
.markdown-body .pl-s .pl-pse .pl-s1,
.markdown-body .pl-sr,
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sra,
.markdown-body .pl-sr .pl-sre,
.markdown-body .pl-corl { color: #4ADE9B; }

.markdown-body .pl-k,
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms { color: #BAC5EE; }

.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v { color: #FFAE58; }

.markdown-body .pl-e,
.markdown-body .pl-en,
.markdown-body .pl-mdr { color: #4C84E7; }

.markdown-body .pl-ent { color: #E36688; }

.markdown-body .pl-v,
.markdown-body .pl-smw { color: #D67D24; }

.markdown-body .pl-smi,
.markdown-body .pl-s .pl-s1,
.markdown-body .pl-mi,
.markdown-body .pl-mb { color: #E4E5F0; }

.markdown-body .pl-ba,
.markdown-body .pl-sg { color: #7B839F; }

.markdown-body .pl-ml { color: #FFAE58; }
.markdown-body .pl-bu { color: #E36688; }

/*
 * Diff blocks. GitHub tints these with pale washes — #f0fff4, #ffeef0 — which
 * on a dark block are light slabs. Same hues at dark-appropriate alpha.
 */
.markdown-body .pl-mi1 { color: #4ADE9B; background-color: rgba(0, 161, 93, 0.14); }
.markdown-body .pl-md  { color: #E36688; background-color: rgba(227, 102, 136, 0.14); }
.markdown-body .pl-mc  { color: #FFAE58; background-color: rgba(255, 174, 88, 0.14); }
.markdown-body .pl-mi2 { color: #E4E5F0; background-color: rgba(76, 132, 231, 0.24); }

.markdown-body .pl-ii,
.markdown-body .pl-c2 { color: #E4E5F0; background-color: rgba(227, 102, 136, 0.4); }

.markdown-body kbd {
	display: inline-block;
	padding: 0.2em 0.45em;
	font-family: var(--wp--preset--font-family--mono);
	font-size: 0.8125em;
	line-height: 1.4;
	vertical-align: middle;
	color: var(--wp--preset--color--text);
	background: var(--wp--preset--color--surface-raised);
	border: 1px solid var(--wp--preset--color--line-strong);
	border-radius: var(--wp--custom--radius--xs);
	box-shadow: inset 0 -1px 0 var(--wp--preset--color--line-strong);
}

/* --- Tables -------------------------------------------------------------- */

/* display: block is GitHub's; it is what lets a wide table scroll on a phone. */
.markdown-body table {
	display: block;
	width: 100%;
	max-width: 100%;
	overflow-x: auto;
	border-collapse: collapse;
	font-size: var(--wp--preset--font-size--small);
}

.markdown-body table th,
.markdown-body table td {
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	text-align: left;
	border: 1px solid var(--wp--preset--color--line);
}

.markdown-body table th {
	font-weight: 600;
	color: var(--wp--preset--color--text);
	background: var(--wp--preset--color--surface-raised);
}

.markdown-body table tr {
	background: transparent;
	border-top: 1px solid var(--wp--preset--color--line);
}

/*
 * Same reason as .mnt-card--interactive:hover — base-raised is #FFFFFF on the
 * light theme, which on a white page is not a stripe. surface-raised tints in
 * both directions.
 */
.markdown-body table tr:nth-child(2n) {
	background: var(--wp--preset--color--surface-raised);
}

/* --- Images -------------------------------------------------------------- */

/*
 * github-markdown-css paints white behind every image so transparent PNGs stay
 * legible on GitHub's white page. Here that is a white slab in a dark one.
 */
.markdown-body img {
	max-width: 100%;
	height: auto;
	background: none;
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--sm);
}

/* Emoji are inline glyphs, not figures. */
.markdown-body img.emoji {
	display: inline;
	border: 0;
	border-radius: 0;
}

/* --- Task lists ---------------------------------------------------------- */

.markdown-body .contains-task-list {
	padding-left: 0;
	list-style: none;
}

.markdown-body .task-list-item-checkbox {
	margin-right: 0.5em;
	accent-color: var(--wp--preset--color--primary);
}

/* --- GitHub alerts ------------------------------------------------------- */

/* > [!NOTE] and friends. Nothing uses them yet; guides will. */
.markdown-body .markdown-alert {
	padding: var(--wp--preset--spacing--40);
	margin-bottom: var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--text-muted);
	background: var(--wp--preset--color--surface);
	border-left: 3px solid var(--wp--preset--color--line-accent);
	border-radius: var(--wp--custom--radius--sm);
}

.markdown-body .markdown-alert > :last-child {
	margin-bottom: 0;
}

.markdown-body .markdown-alert-title {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin-bottom: var(--wp--preset--spacing--20);
	font-weight: 600;
	color: var(--wp--preset--color--line-accent);
}

.markdown-body .markdown-alert-note { border-left-color: var(--wp--preset--color--series-1); }
.markdown-body .markdown-alert-note .markdown-alert-title { color: var(--wp--preset--color--series-1); }

.markdown-body .markdown-alert-tip { border-left-color: var(--wp--preset--color--success); }
.markdown-body .markdown-alert-tip .markdown-alert-title { color: var(--wp--preset--color--success); }

.markdown-body .markdown-alert-important { border-left-color: var(--wp--preset--color--primary); }
.markdown-body .markdown-alert-important .markdown-alert-title { color: var(--wp--preset--color--primary); }

.markdown-body .markdown-alert-warning { border-left-color: var(--wp--preset--color--warning); }
.markdown-body .markdown-alert-warning .markdown-alert-title { color: var(--wp--preset--color--warning); }

.markdown-body .markdown-alert-caution { border-left-color: var(--wp--preset--color--danger); }
.markdown-body .markdown-alert-caution .markdown-alert-title { color: var(--wp--preset--color--danger); }

/* --- Footnotes ----------------------------------------------------------- */

.markdown-body .footnotes {
	margin-top: var(--wp--preset--spacing--60);
	padding-top: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--text-muted);
	border-top: 1px solid var(--wp--preset--color--line);
}

/* --- Plugin chrome ------------------------------------------------------- */

/*
 * The optional "last updated / view on GitHub" strip the shortcode can render.
 * Its own styling is a #345 slab with white text, which belongs to no theme.
 */
.markdown-body + div.markdown-github,
div.markdown-github {
	margin-top: var(--wp--preset--spacing--50);
	font-size: var(--wp--preset--font-size--micro);
}

div.markdown-github div.markdown-github-labels {
	padding: 0.25rem 0.625rem;
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--micro);
	line-height: 1.6;
	color: var(--wp--preset--color--text-muted);
	background: var(--wp--preset--color--surface-raised);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: var(--wp--custom--radius--pill);
}

div.markdown-github label.github-last-update {
	font-weight: 400;
	color: var(--wp--preset--color--text-faint);
}

div.markdown-github div.markdown-github-labels label.github-link a,
div.markdown-github div.markdown-github-labels label.github-link a:focus {
	color: var(--wp--preset--color--primary);
}

/* --- Mobile -------------------------------------------------------------- */

@media (max-width: 599px) {
	.markdown-body h1 { font-size: 1.625rem; }
	.markdown-body h2 { font-size: 1.375rem; }

	.markdown-body pre,
	.markdown-body .highlight pre {
		padding: var(--wp--preset--spacing--40);
		font-size: 0.75rem;
	}

	/* A gutter icon nobody can hover is only taking width. */
	.markdown-body .anchor { display: none; }
}
