/*
Theme Name: Dentists for Longevity
Theme URI: https://www.llbasel.org
Author: Longevity Lab Basel
Author URI: https://www.llbasel.org
Description: A minimal block theme for Longevity Lab Basel. Oversized IvyPresto display type, translucent scrim panels over photography, and restrained ember accents. Every section is a reusable Gutenberg block pattern.
Requires at least: 6.5
Tested up to: 6.8
Requires PHP: 7.4
Version: 1.36.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: llb-longevity
Tags: block-patterns, full-site-editing, one-column, two-columns, editor-style, custom-colors, custom-logo, block-styles, wide-blocks
*/

/* -------------------------------------------------------------------------
   1. Foundations
   ---------------------------------------------------------------------- */

:root {
	--llb-ease: cubic-bezier(0.22, 1, 0.36, 1);
	--llb-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--llb-dur: 900ms;
	--llb-rule: 1px;
}

/* -------------------------------------------------------------------------
   1b. The two settings, as tokens.

   Every section reads these. `:root` holds the Poster setting, so that is what
   a section gets unless it says otherwise. A section wearing .llb-set-loose
   (or the "Setting — Loose" block style) redefines the tokens on itself, and
   only its own subtree changes. That is the whole mechanism — the two settings
   are the same CSS with different numbers, which is why they can sit next to
   each other on one page.
   ---------------------------------------------------------------------- */

:root,
.llb-set-poster,
.is-style-llb-poster {
	--llb-text: var(--wp--preset--color--slate);
	--llb-lh: 1.62;
	--llb-measure: none;
	--llb-h2: var(--wp--preset--color--ember);
	--llb-scrim-bg: color-mix(in srgb, var(--wp--preset--color--mist) 78%, transparent);
	--llb-accent-line: var(--wp--preset--color--ember); /* overridable from Appearance > Longevity Options */
	--llb-scrim-blur: blur(2px) saturate(1.05);
	--llb-scrim-pad: clamp(1.25rem, 3vw, 2.25rem); /* trimmed to free vertical space for the title */
	--llb-scrim-dark-bg: color-mix(in srgb, var(--wp--preset--color--ink) 62%, transparent);
	--llb-hairline: block;
	--llb-media-opacity: 1;
	--llb-stage-wash: linear-gradient(180deg, rgba(14, 44, 54, 0.42) 0%, rgba(14, 44, 54, 0.18) 45%, rgba(14, 44, 54, 0.5) 100%);
	--llb-stage-ground: transparent;
	--llb-hair: var(--llb-rule);
}

.llb-set-loose,
.is-style-llb-loose {
	--llb-text: var(--wp--preset--color--tide);
	--llb-lh: 1.85;
	--llb-measure: 48ch;
	--llb-h2: var(--wp--preset--color--ink);
	--llb-scrim-bg: transparent;
	--llb-scrim-blur: none;
	--llb-scrim-pad: 0;
	--llb-scrim-dark-bg: transparent;
	--llb-hairline: none;
	--llb-media-opacity: 0.16;
	--llb-stage-wash: linear-gradient(180deg, rgba(247, 251, 253, 0.86) 0%, rgba(247, 251, 253, 0.93) 100%);
	--llb-stage-ground: var(--wp--preset--color--paper);
	--llb-hair: 0px;
}

/* Copy takes its tone, leading and measure from whichever setting encloses it.
   :where() keeps specificity at zero so an explicit block colour still wins. */
:where(body) :where(p, li, blockquote) {
	color: var(--llb-text);
	line-height: var(--llb-lh);
}

:where(body) :where(p) {
	max-width: var(--llb-measure);
}

html {
	scroll-behavior: smooth;

}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	overflow-x: hidden;
}

/* Optical correction: IvyPresto sits large and wants tight tracking. */
h1,
.llb-display {
	letter-spacing: -0.022em;
	text-wrap: balance;
}

h2,
h3,
h4,
h5,
h6 {
	text-wrap: balance;
}

p {
	text-wrap: pretty;
}

::selection {
	background: var(--wp--preset--color--ember);
	color: var(--wp--preset--color--paper);
}

/* -------------------------------------------------------------------------
   1b. Global type scale

   Every font-size preset and every heading's line height resolve through these
   variables, so Appearance > Longevity Options can retune the whole scale in
   one place — min size, max size, line height, and the viewport at which each
   stops growing — without touching a template or any page's stored content.

   Sizes hang off the *presets*, not the h1-h6 elements, because every heading
   block in this theme names a preset ("colossal", "xx-large"). A preset class
   outranks an element rule, so element-keyed variables would have been
   silently ignored on every real page.

   The clamps are authored rather than left to WordPress's fluid engine. That
   engine derives its upper viewport bound from settings.layout.wideSize in
   some versions and a flat 1600px in others; for a scale this size-sensitive
   the ambiguity is not worth inheriting. These values reproduce the current
   rendering exactly: h1 on the ramp that was signed off (ends at 2542px),
   the rest on WordPress's documented 320px -> wideSize (1248px) range.

   A per-block font size still wins over any of this: block choices are
   emitted as classes or inline styles, both of which outrank an element rule.
   ---------------------------------------------------------------------- */

:root {
	/* Sizes: one variable per font-size preset. Every heading block in this
	   theme names a preset, so these are what actually reach the page — an
	   element-level rule would be outranked by the block's own preset class. */
	--llb-fs-x-small: 0.8125rem;
	--llb-fs-small: 0.9375rem;
	--llb-fs-medium: clamp(1.0625rem, 1.0625rem + ((1vw - 0.2rem) * 0.216), 1.1875rem);
	--llb-fs-large: clamp(1.1875rem, 1.1875rem + ((1vw - 0.2rem) * 0.539), 1.5rem);
	--llb-fs-x-large: clamp(1.625rem, 1.625rem + ((1vw - 0.2rem) * 1.078), 2.25rem);
	--llb-fs-xx-large: clamp(2.125rem, 2.125rem + ((1vw - 0.2rem) * 2.371), 3.5rem);
	--llb-fs-display: clamp(2.375rem, 2.375rem + ((1vw - 0.2rem) * 5.388), 5.5rem);
	--llb-fs-colossal: clamp(2.625rem, 2.625rem + ((1vw - 0.2rem) * 4.59), 9rem);

	/* Line heights: an element concern, not a preset one — two blocks can share
	   a size and still want different leading. */
	--llb-lh-h1: 1.2;
	--llb-lh-h2: 1.08;
	--llb-lh-h3: 1.24;
	--llb-lh-h4: 1.3;
	--llb-lh-h5: 1.16;
	--llb-lh-h6: 1.16;
	--llb-lh-body: 1.62;

	/* Extra space above an anchored section, on top of the header height.
	   0 lands the section flush under the header. */
	--llb-anchor-gap: 0px;

	/* Form fields: one height and one inset for every control, so a text box
	   and a select sit on the same baseline. */
	/*
	 * 2rem = 32px, chosen for the compact look. Note this is below the 44px
	 * minimum tap target in the WCAG target-size guidance — a deliberate
	 * design decision, recorded here so it is not "fixed" by accident later.
	 * The 3px vertical inset is what is left once a 17px line box and the
	 * 1px borders are subtracted, so the text sits centred without clipping.
	 */
	--llb-sponsor-cols: 3;
	--llb-sponsor-height: 3.5rem;
	--llb-sponsor-gap: clamp(1.5rem, 4vw, 3rem);
	--llb-sponsor-lead: clamp(2.5rem, 5vw, 4rem);
	--llb-field-h: 2rem;
	--llb-field-pad-y: 3px;
	--llb-field-pad-x: 0.85rem;
	--llb-field-border: color-mix(in srgb, var(--wp--preset--color--ink) 32%, transparent);
}

/*
 * Anchor jumps must clear the sticky header, or every in-page link lands with
 * the section's heading hidden underneath it. --llb-header-h is the header's
 * real measured height (set by initHeader() in motion.js); the fallback covers
 * the moment before JS runs.
 *
 * scroll-margin on the TARGET, not scroll-padding on <html>: scroll-margin
 * works whichever element is doing the scrolling, and setting both makes the
 * two offsets stack — measured 336px of clearance instead of 168px.
 */
.wp-block-group[id],
.llb-stage[id],
section[id],
[id].alignfull {
	/*
	 * Exactly the header height and nothing more. An earlier version added
	 * 1.5rem of "breathing room" on top, which was wrong twice over: the
	 * sections already carry their own generous padding-block-start, so the
	 * air is there anyway, and the extra offset stopped the scroll short of
	 * the section boundary — leaving a sliver of the PREVIOUS section's
	 * background visible under the header, which reads as a misalignment.
	 *
	 * --llb-anchor-gap is exposed for tuning from Custom CSS without
	 * touching this rule; positive values push the section further down.
	 */
	scroll-margin-top: calc(var(--llb-header-h, 96px) + var(--llb-anchor-gap, 0px));
}

/* -------------------------------------------------------------------------
   2. Focus + accessibility floor
   ---------------------------------------------------------------------- */

:where(a, button, input, textarea, select, [tabindex]):focus-visible {
	outline: 2px solid var(--wp--preset--color--ember);
	outline-offset: 3px;
	border-radius: 1px;
}

.llb-skip-link:focus {
	position: fixed;
	top: 1rem;
	left: 1rem;
	z-index: 999;
	padding: 0.75rem 1.25rem;
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
	font-family: var(--wp--preset--font-family--heading);
	text-decoration: none;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* -------------------------------------------------------------------------
   3. Eyebrow label — small caps utility, ember rule
   ---------------------------------------------------------------------- */

.llb-eyebrow {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--wp--preset--color--ember);
	display: flex;
	align-items: center;
	gap: 0.9em;
	margin-block-end: var(--wp--preset--spacing--30);
}

.llb-eyebrow::after {
	content: "";
	flex: 1 1 auto;
	height: var(--llb-rule);
	background: currentColor;
	opacity: 0.32;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 1200ms var(--llb-ease) 200ms;
}

.llb-eyebrow.is-visible::after,
.is-visible .llb-eyebrow::after {
	transform: scaleX(1);
}

/* Column label — reads as an eyebrow but keeps the heading order intact. */
.llb-label {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 400;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--wp--preset--color--ember);
}

/* Keep the rule short when the eyebrow sits over a scrim */
.llb-scrim .llb-eyebrow::after {
	max-width: 6rem;
}

/* -------------------------------------------------------------------------
   4. The signature: scrim panel over media
   ---------------------------------------------------------------------- */

.llb-stage {
	position: relative;
	isolation: isolate;
	overflow: clip;
	background: var(--llb-stage-ground);
}

.llb-stage .llb-stage__media {
	position: absolute;
	inset: -8% 0 -8% 0;
	z-index: -2;
	margin: 0; /* it is now an Image block; figures carry default margins */
	/* Inside a constrained group, core clamps children to the content size
	   with auto margins — which strands the backdrop in a centred column and
	   leaves the group background showing either side. The inset already
	   defines the width; release the clamp. */
	max-width: none;
	width: auto;
	opacity: var(--llb-media-opacity);
	pointer-events: none; /* decorative backdrop must not swallow clicks */
}

.llb-stage__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.llb-stage__media img,
.llb-stage__media .wp-block-cover__image-background {
	width: 100%;
	height: 100%;
	object-fit: cover;
	will-change: transform;
}

/* Tonal wash so any photograph resolves into the palette */
.llb-stage::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--llb-stage-wash);
	pointer-events: none;
}

.llb-scrim {
	position: relative;
	background: var(--llb-scrim-bg);
	backdrop-filter: var(--llb-scrim-blur);
	-webkit-backdrop-filter: var(--llb-scrim-blur);
	padding: var(--llb-scrim-pad);
}

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
	.llb-scrim {
		background: rgba(211, 235, 243, 0.82);
	}
}

/* Ember hairline down the leading edge — the only ornament on the panel */
.llb-scrim::before {
	content: "";
	display: var(--llb-hairline);
	position: absolute;
	inset-block: 0;
	inset-inline-start: 0;
	width: 5px; /* bolder — was 2px */
	background: var(--llb-accent-line);
	transform: scaleY(0);
	transform-origin: top;
	transition: transform 1100ms var(--llb-ease) 350ms;
}

.llb-scrim.is-visible::before,
.is-visible > .llb-scrim::before {
	transform: scaleY(1);
}

.llb-scrim--dark {
	background: var(--llb-scrim-dark-bg);
	color: var(--wp--preset--color--mist);
}

.llb-scrim--dark :is(h1, h2, h3, h4, h5, h6) {
	color: var(--wp--preset--color--paper);
}

/*
 * Eyebrow on a dark scrim: paper, not ember.
 *
 * The dark scrim is translucent, so the card's real colour depends on the
 * photograph behind it. Over a bright frame it lightens to roughly
 * rgb(73,96,99), where ember measures 2.1:1 and no tint of ember reaches 4.5
 * without ceasing to be ember. Paper clears it on any photo the scrim is
 * likely to sit on. The brand accent survives in the trailing rule, which is
 * decoration rather than text and carries no contrast requirement.
 */
.llb-scrim--dark .llb-eyebrow {
	color: var(--wp--preset--color--paper);
}

.llb-scrim--dark .llb-eyebrow::after {
	background: var(--wp--preset--color--ember);
}

/* In the loose setting the wash under a dark scrim turns light, so the copy
   and headings must come back to the loose tones or they vanish. */
:is(.llb-set-loose, .is-style-llb-loose) .llb-scrim--dark :is(p, li) {
	color: var(--llb-text);
}

:is(.llb-set-loose, .is-style-llb-loose) .llb-scrim--dark :is(h1, h2, h3, h4, h5, h6) {
	color: var(--wp--preset--color--ink);
}

:is(.llb-set-loose, .is-style-llb-loose) :is(h2) {
	color: var(--llb-h2);
}

.llb-hero__lead {
	/* Atlanta Demi, matching H2's family/weight, white and larger. No
	   text-shadow: plain white measures 1.19:1 on the mist card, so legibility
	   here depends on the photo behind it being dark enough — that is a
	   deliberate editorial choice, managed per block rather than forced by a
	   shadow. Zero specificity, so any sidebar value wins. */
	font-family: var(--wp--preset--font-family--heading);
	font-weight: 600;
	font-style: normal;
	font-size: 2rem;
	line-height: 1.25;
	color: var(--wp--preset--color--paper);
}

/*
 * Component defaults are PLAIN class selectors, deliberately not :where().
 *
 * v1.18 wrapped these in :where() to guarantee per-block choices win. That
 * was solving a problem WordPress had already solved — preset picks from the
 * sidebar are emitted with !important (.has-x-color { ... !important }) and
 * custom values as inline styles, so they beat any class selector regardless.
 * What :where() actually did was drop these below theme.json's own ELEMENT
 * rules (h1 { color } at 0,0,1 beats 0,0,0), which flipped the hero headline
 * to ink on the front end while the editor canvas — whose selector prefixing
 * differs — kept showing the intended colour. Two pipelines, two winners.
 * Plain classes restore one winner everywhere; user choices still override.
 */

/* -------------------------------------------------------------------------
   5. Hero — oversized type that overhangs the scrim
   ---------------------------------------------------------------------- */

.llb-hero {
	/* Fits the screen under the sticky header: --llb-header-h is measured and
	   set by initHeader() in motion.js; the 96px fallback covers the instant
	   before JS runs. */
	min-height: calc(100svh - var(--llb-header-h, 96px));
	display: flex;
	align-items: center;
	padding-block: var(--wp--preset--spacing--30);
}

.llb-hero__title {
	position: relative;
	z-index: 2;
	color: var(--wp--preset--color--mist);
	margin-block-end: var(--wp--preset--spacing--60); /* clear air above the card, not an overhang */
	mix-blend-mode: normal;
}

/*
 * The headline escapes its 46rem column and runs the wide measure (78rem),
 * poster-fashion. Both rules need (0,2,0) to beat core's constrained-layout
 * child clamp. The scrim below stays at 46rem — only the title breaks out.
 */
.llb-hero .llb-hero__title {
	/* 100vw includes the scrollbar and overflows; the parent's width does not. */
	max-width: 78rem;
	width: 100%;
}

/*
 * Rendered through a page, the hero is the first block inside post-content
 * and core hands it a block-gap top margin — a paper stripe between the
 * sticky header and the image. Close it for any stage section that leads.
 */
.wp-block-post-content > .llb-stage:first-child,
main > .llb-stage:first-child {
	margin-block-start: 0;
}

main#llb-content,
main#llb-content > .wp-block-post-content {
	margin-block-start: 0;
}

.llb-hero .llb-scrim {
	max-width: 46rem;
	padding-block-start: clamp(1.25rem, 2.5vw, 2rem);
}

@media (max-width: 781px) {
	.llb-hero__title {
		margin-block-end: var(--wp--preset--spacing--40);
	}
}

/* -------------------------------------------------------------------------
   5b. Loose setting — the page-five "Dentist Circle" register.
       No panel. Type sits straight on the paper, in two unequal columns,
       and the display statement closes the page instead of opening it.
   ---------------------------------------------------------------------- */

.llb-loose {
	--llb-loose-gap: clamp(2rem, 5vw, 5rem);
}

.llb-loose__title {
	max-width: 22ch; /* forces the poster's tall, narrow title block */
	margin-block-end: clamp(2.5rem, 6vw, 5rem);
}

.llb-loose__cols {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--llb-loose-gap);
	align-items: start;
	/* Page five runs ~48 characters per column and leaves a wide right
	   margin. Capping the pair, rather than the page, reproduces both. */
	max-width: 58rem;
}

@media (max-width: 781px) {
	.llb-loose__cols {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Columns rag freely — no equal-height boxes, no rules, no cards. */
.llb-loose__col > * + * {
	margin-block-start: var(--wp--preset--spacing--40);
}

.llb-loose__col p {
	max-width: 48ch;
}

.llb-loose__lead {
	font-family: var(--wp--preset--font-family--heading);
	font-weight: 600;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.35;
}

.llb-loose__figure {
	margin-block-start: var(--wp--preset--spacing--50) !important;
}

.llb-loose__figure img {
	width: 100%;
	aspect-ratio: 3 / 4;
	object-fit: cover;
	display: block;
}

.llb-loose__ask {
	color: var(--wp--preset--color--ember);
	font-style: italic;
}

/* The closing statement — the page's weight is at the bottom here. */
.llb-loose__closer {
	margin-block-start: clamp(3.5rem, 9vw, 8rem);
	max-width: 30ch;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 600;
	/* Page five's closing line sits at roughly half its title: the weight is
	   at the top, and the statement answers it quietly from the bottom. */
	font-size: var(--wp--preset--font-size--x-large);
	line-height: 1.14;
	color: var(--wp--preset--color--ink);
}

.llb-loose__foot {
	margin-block-start: var(--wp--preset--spacing--50);
	display: flex;
	justify-content: space-between;
	align-items: flex-end;
	gap: var(--wp--preset--spacing--40);
	flex-wrap: wrap;
}

/* -------------------------------------------------------------------------
   6. Split-line reveal (hero H1) — the orchestrated moment
   ---------------------------------------------------------------------- */

/*
 * overflow:hidden here is load-bearing — it is the mask for the slide-up
 * reveal below, not a mistake. Switching it to visible would show the
 * sliding duplicate text mid-animation instead of a clean wipe.
 *
 * The real bug: h1's line-height (0.94, deliberately tight poster leading)
 * makes the line box shorter than IvyPresto's natural ascender/descender
 * extent, so glyphs like "p" clip top and bottom by ~0.22em each side.
 * Padding widens the clip box; equal negative margin cancels it back out
 * so line-to-line spacing is unchanged. */
/*
 * The mask is only needed while the line is sliding into place. Once
 * .llb-split carries is-visible, the inner span is at rest and there is
 * nothing left to hide — so overflow goes back to visible and the descender
 * is simply ink, not something that needs clipping. Padding-based widening
 * was tried here first but a fixed line-height means adjacent lines' equal
 * negative margins collapse (per normal CSS margin-collapsing between block
 * siblings), adding the padding back into the visible line spacing instead
 * of cancelling it.
 */
/*
 * The mask must stay in place for the whole slide-up — releasing it at the
 * start (when is-visible is added) would remove the mask before the text has
 * finished moving, showing it bleed past the line's box mid-transition. It
 * lifts only once the transform's own transition has actually finished
 * (1100ms + this line's stagger delay), by which point the glyph is at rest
 * and the only thing the taller box now reveals is the ordinary descender.
 *
 * `overflow` cannot interpolate, but a transition-delay on a non-interpolable
 * property still holds it at its start value for the full delay, then flips
 * — which is exactly the discrete "wait, then switch" behaviour wanted here.
 */
.llb-split__line {
	display: block;
	overflow: hidden;
	transition: overflow 0s linear 0s;
	transition-behavior: allow-discrete;
}

.llb-split.is-visible .llb-split__line {
	overflow: visible;
	transition-delay: calc(1100ms + (var(--llb-line, 0) * 110ms));
}

.llb-split__inner {
	display: block;
	transform: translateY(105%);
	opacity: 0;
	transition:
		transform 1100ms var(--llb-ease-out),
		opacity 700ms linear;
	transition-delay: calc(var(--llb-line, 0) * 110ms);
}

.llb-split.is-visible .llb-split__inner {
	transform: translateY(0);
	opacity: 1;
}

/* -------------------------------------------------------------------------
   7. Scroll reveals

   These hook on classes, not data-attributes. Core blocks only save the
   attributes their own save() emits, so a hand-added data-* makes Gutenberg
   report "Block contains unexpected or invalid content" the moment the block
   is opened in the editor. `className` is a supported attribute on every core
   block, so a class survives the round trip.
   ---------------------------------------------------------------------- */

.llb-reveal {
	opacity: 0;
	transform: translateY(1.75rem);
	transition:
		opacity 800ms linear var(--llb-delay, 0ms),
		transform var(--llb-dur) var(--llb-ease) var(--llb-delay, 0ms);
}

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

/*
 * The clip lives on the image, never on the observed element.
 *
 * Chrome factors clip-path into IntersectionObserver: an element clipped to
 * inset(0 0 100% 0) reports isIntersecting:false at ratio 0, so clipping the
 * figure itself deadlocks — the observer never fires, so the clip is never
 * lifted, so the image never appears. Clipping the child keeps the figure's
 * own box intact and observable.
 */
.llb-reveal-media {
	opacity: 1;
}

.llb-reveal-media :is(img, .wp-block-cover__image-background) {
	clip-path: inset(0 0 100% 0);
	transform: translateY(2.5rem) scale(1.02);
	transition:
		clip-path 1400ms var(--llb-ease-out) var(--llb-delay, 0ms),
		transform 1400ms var(--llb-ease-out) var(--llb-delay, 0ms);
}

.llb-reveal-media.is-visible :is(img, .wp-block-cover__image-background) {
	clip-path: inset(0 0 0 0);
	transform: none;
}

.llb-stagger > * {
	opacity: 0;
	transform: translateY(1.5rem);
	transition:
		opacity 700ms linear,
		transform 850ms var(--llb-ease);
}

.llb-stagger.is-visible > * {
	opacity: 1;
	transform: none;
}

.llb-stagger.is-visible > *:nth-child(1) { transition-delay: 0ms; }
.llb-stagger.is-visible > *:nth-child(2) { transition-delay: 110ms; }
.llb-stagger.is-visible > *:nth-child(3) { transition-delay: 220ms; }
.llb-stagger.is-visible > *:nth-child(4) { transition-delay: 330ms; }
.llb-stagger.is-visible > *:nth-child(5) { transition-delay: 440ms; }
.llb-stagger.is-visible > *:nth-child(6) { transition-delay: 550ms; }

/* -------------------------------------------------------------------------
   8. The Method — a real sequence, so it earns its marks
   ---------------------------------------------------------------------- */

.llb-method {
	position: relative;
	counter-reset: llb-step;
	list-style: none;
	margin: 0;
	padding: 0;
}

/*
 * Track and step numbers are pseudo-elements driven by a CSS counter, so the
 * markup is nothing but a group of plain heading + paragraph blocks — every
 * word editable in place. The .llb-method__track / .llb-method__mark element
 * rules below them are kept for pages imported before v1.21, which still
 * carry those elements.
 */
.llb-method::before {
	content: "";
	position: absolute;
	inset-block: 0.75rem 0.75rem;
	inset-inline-start: 0.6875rem;
	width: var(--llb-rule);
	background: color-mix(in srgb, var(--wp--preset--color--ink) 18%, transparent);
}

.llb-method::after {
	content: "";
	position: absolute;
	inset-block: 0.75rem 0.75rem;
	inset-inline-start: 0.6875rem;
	width: var(--llb-rule);
	background: var(--wp--preset--color--ember);
	transform: scaleY(var(--llb-progress, 0));
	transform-origin: top;
	transition: transform 120ms linear;
}

.llb-method__step::before {
	counter-increment: llb-step;
	content: counter(llb-step);
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: clamp(1.5rem, 3.2vw, 2.5rem);
	width: 1.5rem;
	height: 1.5rem;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var(--wp--preset--color--paper);
	border: var(--llb-rule) solid color-mix(in srgb, var(--wp--preset--color--ink) 28%, transparent);
	font-family: var(--wp--preset--font-family--heading);
	font-size: 0.6875rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--slate);
	transition:
		background 500ms var(--llb-ease),
		border-color 500ms var(--llb-ease),
		color 500ms var(--llb-ease);
}

.llb-method__step.is-reached::before {
	background: var(--wp--preset--color--ember);
	border-color: var(--wp--preset--color--ember);
	color: var(--wp--preset--color--paper);
}

/* When a real mark element exists (pre-v1.21 content), the counter pseudo
   must stand down or the step shows two numbers. */
.llb-method__step:has(.llb-method__mark)::before {
	content: none;
}

.llb-method:has(.llb-method__track)::before,
.llb-method:has(.llb-method__track)::after {
	content: none;
}

.llb-method__track {
	position: absolute;
	inset-block: 0.75rem 0.75rem;
	inset-inline-start: 0.6875rem;
	width: var(--llb-rule);
	background: color-mix(in srgb, var(--wp--preset--color--ink) 18%, transparent);
}

.llb-method__track::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--wp--preset--color--ember);
	transform: scaleY(var(--llb-progress, 0));
	transform-origin: top;
	transition: transform 120ms linear;
}

.llb-method__step {
	position: relative;
	padding-inline-start: clamp(2.75rem, 5vw, 4rem);
	padding-block: clamp(1.25rem, 3vw, 2.25rem);
}

.llb-method__mark {
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: clamp(1.5rem, 3.2vw, 2.5rem);
	width: 1.5rem;
	height: 1.5rem;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: var(--wp--preset--color--paper);
	border: var(--llb-rule) solid color-mix(in srgb, var(--wp--preset--color--ink) 28%, transparent);
	font-family: var(--wp--preset--font-family--heading);
	font-size: 0.6875rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--slate);
	transition:
		background 500ms var(--llb-ease),
		border-color 500ms var(--llb-ease),
		color 500ms var(--llb-ease);
}

.llb-method__step.is-reached .llb-method__mark {
	background: var(--wp--preset--color--ember);
	border-color: var(--wp--preset--color--ember);
	color: var(--wp--preset--color--paper);
}

.llb-method__step h3 {
	margin: 0 0 0.4em;
}

@media (max-width: 600px) {
	.llb-method__track {
		inset-inline-start: 0.5625rem;
	}

	.llb-method__mark {
		width: 1.25rem;
		height: 1.25rem;
		font-size: 0.625rem;
	}
}

/* -------------------------------------------------------------------------
   9. Signal cards — hairline, no boxes
   ---------------------------------------------------------------------- */

.llb-signal {
	border-block-start: var(--llb-hair) solid color-mix(in srgb, var(--wp--preset--color--ink) 22%, transparent);
	padding-block-start: var(--wp--preset--spacing--30);
	position: relative;
}

.llb-signal::before {
	content: "";
	display: var(--llb-hairline);
	position: absolute;
	inset-block-start: calc(var(--llb-rule) * -1);
	inset-inline-start: 0;
	width: 100%;
	height: var(--llb-rule);
	background: var(--wp--preset--color--ember);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 900ms var(--llb-ease);
}

.llb-signal:hover::before,
.llb-signal:focus-within::before {
	transform: scaleX(1);
}

.llb-signal h3 {
	margin: 0 0 0.35em;
}

/* -------------------------------------------------------------------------
   10. Value entries
   ---------------------------------------------------------------------- */

.llb-value {
	border-block-start: var(--llb-hair) solid color-mix(in srgb, var(--wp--preset--color--ink) 20%, transparent);
	padding-block: var(--wp--preset--spacing--40);
}

.llb-value h3 {
	margin: 0 0 0.5em;
}

/* -------------------------------------------------------------------------
   11. Buttons
   ---------------------------------------------------------------------- */

.wp-block-button__link {
	position: relative;
	overflow: hidden;
	border-radius: 0;
	font-family: var(--wp--preset--font-family--heading);
	font-weight: 600; /* Atlanta Demi — stated here so it can't drift from theme.json */
	letter-spacing: 0.06em;
	text-transform: uppercase;
	font-size: var(--wp--preset--font-size--x-small);
	padding: 1em 2em;
	transition:
		color 420ms var(--llb-ease),
		border-color 420ms var(--llb-ease);
	z-index: 0;
}

.wp-block-button__link::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--wp--preset--color--ink);
	transform: translateY(101%);
	transition: transform 520ms var(--llb-ease);
}

.wp-block-button__link:hover::before,
.wp-block-button__link:focus-visible::before {
	transform: translateY(0);
}

.wp-block-button__link:hover,
.wp-block-button__link:focus-visible {
	color: var(--wp--preset--color--paper);
}

.is-style-outline .wp-block-button__link {
	border: var(--llb-rule) solid var(--wp--preset--color--ember);
	color: var(--wp--preset--color--ink); /* ember text here was 2.78:1 on the scrim — fails AA */
	background: transparent;
}

.is-style-outline .wp-block-button__link::before {
	/* Same ember-deep fill the primary button uses at rest (theme.json
	   styles.elements.button) — "orange," but the shade already proven to
	   clear AA with light text (4.62:1), not the brighter ember that fails
	   at 2.78-3.73:1 against a light background. */
	background: var(--wp--preset--color--ember-deep);
}

.is-style-outline .wp-block-button__link:hover,
.is-style-outline .wp-block-button__link:focus-visible {
	color: var(--wp--preset--color--paper);
}

/* Quiet text link with an ember underline that sweeps in */
.llb-link {
	color: inherit;
	text-decoration: none;
	background-image: linear-gradient(var(--wp--preset--color--ember), var(--wp--preset--color--ember));
	background-size: 0% var(--llb-rule);
	background-position: 0 100%;
	background-repeat: no-repeat;
	padding-block-end: 0.15em;
	transition: background-size 480ms var(--llb-ease);
}

.llb-link:hover,
.llb-link:focus-visible {
	background-size: 100% var(--llb-rule);
}

/* -------------------------------------------------------------------------
   11b. Closing split panel
   ---------------------------------------------------------------------- */

.llb-cta__media {
	height: 100%;
	min-height: 22rem;
	margin: 0;
	overflow: hidden;
}

.llb-cta__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center 25%;
	display: block;
}

@media (min-width: 782px) {
	.llb-cta__media {
		min-height: 34rem;
	}
}

/* -------------------------------------------------------------------------
   12. Pull quote
   ---------------------------------------------------------------------- */

.llb-quote {
	text-align: center;
	max-width: 54rem;
	margin-inline: auto;
}

/* As a core pullquote block the figure arrives with core's borders and
   padding; this is our component, so strip them. */
figure.wp-block-pullquote.llb-quote {
	border: 0;
	padding: 0;
	margin-block: 0;
}

/* The ember rule, drawn by the figure itself — no span element to maintain.
   The .llb-quote__rule rules below stay for pre-v1.21 content. */
.llb-quote::before {
	content: "";
	display: block;
	width: 3rem;
	height: var(--llb-rule);
	background: var(--wp--preset--color--ember);
	margin: 0 auto var(--wp--preset--spacing--40);
	transform: scaleX(0);
	transition: transform 900ms var(--llb-ease) 200ms;
}

.llb-quote.is-visible::before {
	transform: scaleX(1);
}

.llb-quote:has(.llb-quote__rule)::before {
	content: none;
}

.llb-quote p {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--xx-large);
	line-height: 1.18;
	/* Roman, not italic: only IvyPresto SemiBold was licensed, and a faked
	   oblique on a Didone at this size shears the stress badly. */
	font-style: normal;
	margin: 0;
}

.llb-quote__rule {
	width: 3rem;
	height: var(--llb-rule);
	background: var(--wp--preset--color--ember);
	margin: 0 auto var(--wp--preset--spacing--40);
	transform: scaleX(0);
	transition: transform 900ms var(--llb-ease) 200ms;
}

.is-visible .llb-quote__rule,
.llb-quote__rule.is-visible {
	transform: scaleX(1);
}

/* -------------------------------------------------------------------------
   13. Header + footer

   The header is a solid bar above the hero, not a pane floating over it.
   An earlier version inverted its links to paper on the assumption that a
   dark stage sat behind them; the header never actually overlapped anything,
   so that was paper on paper. Solid bar, ink links, no inversion, no JS.
   ---------------------------------------------------------------------- */

.llb-header {
	position: sticky;
	top: 0;
	z-index: 50;
	background-color: var(--wp--preset--color--mist);
	border-block-end: var(--llb-rule) solid transparent;
	transition:
		background-color 400ms var(--llb-ease),
		border-color 400ms var(--llb-ease),
		box-shadow 400ms var(--llb-ease);
}

.llb-header.is-stuck {
	background-color: color-mix(in srgb, var(--wp--preset--color--mist) 92%, transparent);
	backdrop-filter: blur(10px) saturate(1.1);
	-webkit-backdrop-filter: blur(10px) saturate(1.1);
	border-block-end-color: color-mix(in srgb, var(--wp--preset--color--ink) 12%, transparent);
}

@supports not (backdrop-filter: blur(1px)) {
	.llb-header.is-stuck {
		background-color: var(--wp--preset--color--mist);
	}
}

/*
 * No blur on mobile — and this is load-bearing, not a taste call.
 *
 * backdrop-filter makes an element a containing block for every fixed-position
 * descendant. The menu panel is fixed inset:0 and lives inside the header, so
 * the moment is-stuck applied on scroll, the panel stopped resolving against
 * the viewport and collapsed into the header's own box (measured: 390x844 ->
 * 390x80), leaving the page visible underneath — the panel looked transparent.
 *
 * The header is opaque at this width anyway, so there was never anything for
 * the blur to sample.
 */
@media (max-width: 781px) {
	.llb-header.is-stuck {
		background-color: var(--wp--preset--color--mist);
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
	}
}

/*
 * The brand mark, inlined in the header rather than uploaded as a Site Logo.
 * WordPress blocks SVG uploads by default, so a media-library route would have
 * needed a plugin; inlining also lets the wordmark inherit currentColor, which
 * is what makes one file work on both the mist header and dark grounds.
 */
.llb-brand {
	display: inline-flex;
	align-items: center;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
	line-height: 0;
}

.llb-brand__mark,
.llb-brand__img {
	height: clamp(2.1rem, 3.2vw, 2.6rem);
	width: auto;
	max-width: 60vw;
	display: block;
	overflow: visible;
	object-fit: contain;
}

/* The mark is lettering only, so all of it follows the surrounding text
   colour — ink on the mist header, mist on a dark ground, one file. */
.llb-mark__word {
	fill: currentColor;
}

/* -------------------------------------------------------------------------
   13b. Navigation — classic wp_nav_menu() menus, Appearance > Menus

   No core Navigation block anywhere in this theme: menus are rendered with
   wp_nav_menu() into a plain <ul><li><a>, and the mobile toggle below is
   hand-rolled (a few lines in motion.js) because the block's own client-side
   toggle script is never enqueued without an actual Navigation block on the
   page.
   ---------------------------------------------------------------------- */

.llb-menu-wrap {
	display: flex;
	align-items: center;
}

.llb-menu {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--40);
	list-style: none;
	margin: 0;
	padding: 0;
	font-family: var(--wp--preset--font-family--heading);
}

.llb-menu .menu-item {
	margin: 0;
}

.llb-menu a {
	display: inline-block;
	position: relative;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	text-decoration: none;
	padding-block: 0.35em;
}

/* Ember underline sweeps in on hover/focus/current — the same gesture used
   for in-body links (.llb-link), applied to the menu. */
.llb-menu a::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	inset-block-end: 0;
	height: var(--llb-rule);
	background: currentColor;
	transform: scaleX(0);
	transform-origin: right;
	transition: transform 420ms var(--llb-ease);
}

.llb-menu .menu-item:hover > a::after,
.llb-menu a:focus-visible::after,
.llb-menu .current-menu-item > a::after {
	transform: scaleX(1);
	transform-origin: left;
}

/* The CTA item is marked by keeping its ember rule permanently drawn rather
   than colouring the label — ember text at 13px sits at 2.78:1 on mist,
   which fails; as a rule it is decoration and the label keeps full contrast. */
/*
 * Menu item as a filled block. Add the CSS class "llb-nav-button" to any item
 * in Appearance > Menus (enable the CSS Classes field under Screen Options if
 * you can't see it).
 *
 * ember-deep, not plain ember: the brighter ember with paper text measures
 * 3.31:1, under AA. ember-deep is 4.84:1 and is the same orange used by the
 * page buttons, so a nav button and a page button read as one family.
 */
.llb-menu li.llb-nav-button > a {
	background: var(--wp--preset--color--ember-deep);
	color: var(--wp--preset--color--paper);
	padding-inline: 1.1em;
	padding-block: 0.7em;
	transition:
		background 240ms var(--llb-ease),
		color 240ms var(--llb-ease);
}

/* The sliding underline would draw across the filled block. */
.llb-menu li.llb-nav-button > a::after {
	content: none;
}

.llb-menu li.llb-nav-button > a:hover,
.llb-menu li.llb-nav-button > a:focus-visible {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

/* current-menu-item must not repaint the label into ember on ember. */
.llb-menu li.llb-nav-button.current-menu-item > a,
.llb-menu li.llb-nav-button.current_page_item > a {
	color: var(--wp--preset--color--paper);
}

.llb-menu li.llb-nav-cta > a::after {
	background: var(--wp--preset--color--ember);
	transform: scaleX(1);
}

/* -- Header: toggle + off-canvas panel on narrow viewports -------------- */

/* Scroll lock while the panel is open. Set on <html> rather than <body> so it
   holds regardless of which element the page happens to be scrolling. */
.llb-menu-is-open {
	overflow: hidden;
}

/* Only ever an overlay control — above the breakpoint the menu is a plain row
   in the header and there is nothing to close. */
.llb-menu-close {
	display: none;
}

.llb-menu-toggle {
	display: none;
	background: none;
	border: 0;
	padding: 0.4em;
	margin: 0;
	color: inherit;
	cursor: pointer;
	line-height: 0;
}

@media (max-width: 781px) {
	.llb-menu-toggle {
		display: block;
	}

	/*
	 * The panel is fixed to the viewport. Nothing in its ancestry may set
	 * backdrop-filter, filter, transform or will-change, or it stops
	 * resolving against the viewport and collapses into that ancestor's box
	 * — see the note on .llb-header.is-stuck above.
	 */
	.llb-menu-wrap .llb-menu-panel {
		position: fixed;
		inset: 0;
		z-index: 100;
		display: flex;
		flex-direction: column;
		justify-content: center;
		padding: var(--wp--preset--spacing--60) clamp(1.5rem, 7vw, 3rem);
		background-color: var(--wp--preset--color--mist);
		visibility: hidden;
		opacity: 0;
		transition:
			opacity 300ms var(--llb-ease),
			visibility 0s linear 300ms;
	}

	.llb-menu-wrap .llb-menu-panel.is-open {
		visibility: visible;
		opacity: 1;
		transition: opacity 300ms var(--llb-ease);
	}

	.llb-menu-close {
		position: absolute;
		inset-block-start: clamp(1rem, 4vw, 1.75rem);
		inset-inline-end: clamp(1rem, 4vw, 1.75rem);
		display: flex;
		align-items: center;
		justify-content: center;
		width: 3rem;
		height: 3rem;
		padding: 0;
		background: none;
		border: 0;
		color: var(--wp--preset--color--ink);
		cursor: pointer;
		line-height: 0;
	}

	.llb-menu-close svg {
		width: 1.75rem;
		height: 1.75rem;
	}

	.llb-menu-wrap .llb-menu {
		flex-direction: column;
		align-items: flex-start;
		gap: clamp(0.75rem, 3vw, 1.25rem);
	}

	/* Each item slides up as the panel opens; the delay is set per item in
	   motion.js so the list arrives in sequence rather than all at once. */
	.llb-menu-wrap .llb-menu .menu-item {
		opacity: 0;
		transform: translateY(0.75rem);
		transition:
			opacity 420ms var(--llb-ease-out),
			transform 420ms var(--llb-ease-out);
	}

	.llb-menu-wrap .llb-menu-panel.is-open .menu-item {
		opacity: 1;
		transform: none;
		transition-delay: calc(90ms + (var(--llb-i, 0) * 45ms));
	}

	.llb-menu-wrap .llb-menu a {
		font-family: var(--wp--preset--font-family--display);
		font-size: var(--wp--preset--font-size--x-large);
		font-weight: 600;
		letter-spacing: 0.01em;
		text-transform: none;
		color: var(--wp--preset--color--ink);
		padding-block: 0.12em;
	}

	/* The CTA keeps its ember rule, drawn full width under the label. */
	.llb-menu-wrap /*
 * Menu item as a filled block. Add the CSS class "llb-nav-button" to any item
 * in Appearance > Menus (enable the CSS Classes field under Screen Options if
 * you can't see it).
 *
 * ember-deep, not plain ember: the brighter ember with paper text measures
 * 3.31:1, under AA. ember-deep is 4.84:1 and is the same orange used by the
 * page buttons, so a nav button and a page button read as one family.
 */
.llb-menu li.llb-nav-button > a {
	background: var(--wp--preset--color--ember-deep);
	color: var(--wp--preset--color--paper);
	padding-inline: 1.1em;
	padding-block: 0.7em;
	transition:
		background 240ms var(--llb-ease),
		color 240ms var(--llb-ease);
}

/* The sliding underline would draw across the filled block. */
.llb-menu li.llb-nav-button > a::after {
	content: none;
}

.llb-menu li.llb-nav-button > a:hover,
.llb-menu li.llb-nav-button > a:focus-visible {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

/* current-menu-item must not repaint the label into ember on ember. */
.llb-menu li.llb-nav-button.current-menu-item > a,
.llb-menu li.llb-nav-button.current_page_item > a {
	color: var(--wp--preset--color--paper);
}

.llb-menu li.llb-nav-cta > a::after {
		background: var(--wp--preset--color--ember);
		transform: scaleX(1);
		height: 2px;
	}
}

@media (max-width: 781px) and (prefers-reduced-motion: reduce) {
	.llb-menu-wrap .llb-menu .menu-item {
		opacity: 1;
		transform: none;
	}
}

/* -- Footer: plain lists, no toggle -------------------------------------- */

.llb-menu--footer-vertical {
	flex-direction: column;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30);
	margin-top: var(--wp--preset--spacing--30);
}

.llb-menu--footer-vertical a {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--slate);
	text-transform: none;
	letter-spacing: normal;
	padding-block: 0;
	/* One label per line. Without this a narrow footer column can break a
	   label mid-word — "Our values" rendering as "Our value / s". */
	white-space: nowrap;
}

.llb-menu--footer-vertical a::after {
	height: var(--llb-rule);
	background: var(--wp--preset--color--ember);
}

.llb-menu--footer-vertical .menu-item:hover > a,
.llb-menu--footer-vertical a:focus-visible {
	color: var(--wp--preset--color--ink);
}

.llb-footer__base {
	row-gap: var(--wp--preset--spacing--30);
}

.llb-menu--footer-legal {
	gap: var(--wp--preset--spacing--40);
}

.llb-menu--footer-legal a {
	font-size: var(--wp--preset--font-size--x-small);
}

/* -------------------------------------------------------------------------
   13c. Language switcher — empty unless a translation plugin is active
   ---------------------------------------------------------------------- */

.llb-lang__list {
	display: flex;
	align-items: center;
	gap: 0.6em;
	list-style: none;
	margin: 0;
	padding: 0;
}

.llb-lang__item + .llb-lang__item::before {
	content: "";
	display: inline-block;
	width: var(--llb-rule);
	height: 0.8em;
	margin-inline-end: 0.6em;
	background: currentColor;
	opacity: 0.28;
	vertical-align: -0.05em;
}

.llb-lang__link {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	text-decoration: none;
	color: var(--wp--preset--color--slate);
	transition: color 320ms var(--llb-ease);
}

.llb-lang__link:hover,
.llb-lang__link:focus-visible {
	color: var(--wp--preset--color--ink);
}

/* The current language is marked with ember, the same accent the rest of the
   theme uses for "you are here". */
.llb-lang__link.is-current {
	color: var(--wp--preset--color--ink);
	border-block-end: var(--llb-rule) solid var(--wp--preset--color--ember);
	padding-block-end: 0.2em;
}

.llb-lang--plugin {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--x-small);
}

/* -------------------------------------------------------------------------
   14. Editor parity
   ---------------------------------------------------------------------- */

.editor-styles-wrapper .llb-reveal,
.editor-styles-wrapper .llb-reveal-media,
.editor-styles-wrapper .llb-reveal-media img,
.editor-styles-wrapper .llb-stagger > *,
.editor-styles-wrapper .llb-split__inner {
	opacity: 1 !important;
	transform: none !important;
	clip-path: none !important;
}

.editor-styles-wrapper .llb-scrim::before,
.editor-styles-wrapper .llb-eyebrow::after,
.editor-styles-wrapper .llb-quote__rule,
.editor-styles-wrapper .llb-quote::before {
	transform: none !important;
}

.editor-styles-wrapper .llb-method::after {
	transform: scaleY(1) !important;
}

/*
 * In the editor the backdrop must be clickable, or it cannot be selected and
 * replaced. pointer-events:none is a front-end-only concern (stops the
 * decorative image intercepting text selection); in the canvas it would make
 * the image impossible to click.
 */
.editor-styles-wrapper .llb-stage__media,
.editor-styles-wrapper .llb-stage__media img {
	pointer-events: auto !important;
}

/* -------------------------------------------------------------------------
   15. Reduced motion — no exceptions
   ---------------------------------------------------------------------- */

@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;
	}

	.llb-reveal,
	.llb-reveal-media,
	.llb-stagger > *,
	.llb-split__inner {
		opacity: 1;
		transform: none;
		clip-path: none;
	}

	/* Must match the specificity of the rule that applies the clip (0,2,0).
	   `.llb-reveal-media img` is only (0,1,1) and loses, which would leave a
	   reduced-motion reader with a permanently clipped, invisible image. */
	.llb-reveal-media :is(img, .wp-block-cover__image-background) {
		clip-path: none;
		transform: none;
	}

	.llb-stage__media img {
		transform: none !important;
	}
}

/*
 * The method's right-hand column: image pinned to the top, closing paragraph
 * to the bottom.
 *
 * The column previously used verticalAlignment "bottom", which pushes the
 * whole column to the foot of the row and left the top empty. Dropping that
 * lets the column stretch to full row height, and space-between then holds
 * the image against the top edge and the paragraph against the bottom —
 * something the block editor's column alignment cannot express on its own.
 */
.llb-method__aside {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--50);
}

.llb-method__media {
	margin: 0;
}

.llb-method__media img {
	display: block;
	width: 100%;
	height: auto;
}

/* Stacked on narrow screens there is no row height to distribute, so the
   space-between has nothing to do and normal flow reads better. */
@media (max-width: 781px) {
	.llb-method__aside {
		display: block;
	}

	.llb-method__media {
		margin-block-end: var(--wp--preset--spacing--40);
	}
}

/* -------------------------------------------------------------------------
   10b. Column order + image centring on mobile

   WordPress stacks columns in SOURCE order when they collapse; reordering
   them in the editor does not change that on the front end. Add the class
   "llb-media-first" to a two-column row (Advanced > Additional CSS classes on
   the Columns block) and its SECOND column moves above the first below the
   breakpoint — so a text/image row on desktop becomes image/text on a phone,
   without touching the desktop order.
   ---------------------------------------------------------------------- */

@media (max-width: 781px) {
	.wp-block-columns.llb-media-first {
		/* The stacked columns are already flex column direction at this width;
		   ordering the children is enough. */
		display: flex;
		flex-direction: column;
	}

	.wp-block-columns.llb-media-first > .wp-block-column:nth-child(2) {
		order: -1;
	}

	/*
	 * When the columns stack, the column blockGap becomes vertical space. On a
	 * two-column text/image row that leaves a large gap between the image and
	 * the text below it. Tighten it — but only for this reordered layout, so
	 * other stacked columns keep their spacing. --llb-media-gap is exposed for
	 * tuning from Custom CSS.
	 */
	.wp-block-columns.llb-media-first {
		row-gap: var(--llb-media-gap, 1.25rem) !important;
	}

	/*
	 * Centre images once the layout is single-column. A resized figure
	 * (explicit pixel width) is left-aligned by core; a reveal image sits in
	 * a column that is now full width. Both should be centred on a phone.
	 */
	.wp-block-image.is-resized,
	.wp-block-image.is-resized img,
	.llb-reveal-media,
	.llb-figure {
		margin-inline: auto !important;
	}

	.llb-reveal-media img,
	.llb-figure img {
		margin-inline: auto;
	}
}

/* -------------------------------------------------------------------------
   10c. Sponsor / partner logo row

   Column count comes from Appearance > Longevity Options > Sponsor logos,
   published as --llb-sponsor-cols. The default lives here so an untouched
   site needs no generated CSS at all.

   No greyscale or opacity filter is applied. Sponsor and partner logos are
   usually governed by brand guidelines that forbid recolouring, so muting
   them is a decision for whoever holds those agreements — not a default.
   ---------------------------------------------------------------------- */

.llb-sponsors {
	/*
	 * Flex, not grid. A grid keeps empty tracks, so two logos in a three-track
	 * row sit hard left with a hole on the right. Flex with justify-content
	 * centre keeps a part-filled row optically centred, which is what a
	 * sponsor row nearly always is.
	 */
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: var(--llb-sponsor-gap);
}

.llb-sponsors > .wp-block-image {
	margin: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	/* Each slot still takes exactly one column's width, so logos line up in a
	   full row — the centring only shows on the last, incomplete row. */
	flex: 0 1 calc(
		(100% - (var(--llb-sponsor-cols) - 1) * var(--llb-sponsor-gap))
		/ var(--llb-sponsor-cols)
	);
}

.llb-sponsors img {
	display: block;
	margin-inline: auto;
	width: auto;
	max-width: 100%;
	max-height: var(--llb-sponsor-height, 3.5rem);
	object-fit: contain;
}

/*
 * Air between the eyebrow rule and the logos. Set on the eyebrow rather than
 * the logo row, because the row carries an inline margin from the pattern and
 * an inline style cannot be overridden from a stylesheet without !important —
 * this way an already-placed sponsor row picks the spacing up too.
 */
.llb-eyebrow:has(+ .llb-sponsors) {
	margin-block-end: var(--llb-sponsor-lead);
}

/*
 * Unreplaced placeholder slots never reach visitors. They stay visible in the
 * editor, faded, so they can still be found and replaced.
 */
.llb-sponsors > .wp-block-image:has(img[src$="logo-placeholder.svg"]) {
	display: none;
}

.editor-styles-wrapper .llb-sponsors > .wp-block-image:has(img[src$="logo-placeholder.svg"]) {
	display: flex;
	opacity: 0.55;
}

/*
 * Below the breakpoints the chosen count is ignored: four logos across a phone
 * would render each one unreadably small. Setting the variable locally beats
 * the inherited :root value without needing !important.
 */
@media (max-width: 781px) {
	.llb-sponsors {
		--llb-sponsor-cols: 2;
	}
}

@media (max-width: 460px) {
	.llb-sponsors {
		--llb-sponsor-cols: 1;
	}
}

/* -------------------------------------------------------------------------
   11a. Forminator fields

   Forminator scopes its own rules with the form's module ID
   (".forminator-ui#forminator-module-123 .forminator-input"). An ID selector
   cannot be outranked by class selectors at any length, so !important is the
   only lever available here. Setting the form's Appearance > Style to "None"
   in Forminator removes those rules and makes all of this moot — but the form
   should look right whether or not that setting has been touched.
   ---------------------------------------------------------------------- */

.forminator-ui .forminator-input,
.forminator-ui .forminator-textarea,
.forminator-ui select.forminator-select2,
.forminator-ui select,
.forminator-custom-form .forminator-input,
.forminator-custom-form .forminator-textarea,
.forminator-custom-form select {
	box-sizing: border-box !important;
	width: 100% !important;
	/* One height for every control, so a text field lines up with the select
	   beside it. Both height and min-height: Forminator sets an explicit
	   height on inputs and selects, and overriding only min-height leaves
	   that winning. The textarea takes height:auto back below. */
	height: var(--llb-field-h) !important;
	min-height: var(--llb-field-h) !important;
	background-color: var(--wp--preset--color--paper) !important;
	background-image: none;
	color: var(--wp--preset--color--ink) !important;
	border: 1px solid var(--llb-field-border) !important;
	border-radius: 0 !important;
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: var(--wp--preset--font-size--medium) !important;
	line-height: 1.4 !important;
	padding: var(--llb-field-pad-y) var(--llb-field-pad-x) !important;
	box-shadow: none !important;
	transition:
		border-color 200ms var(--llb-ease),
		box-shadow 200ms var(--llb-ease);
}

.forminator-ui .forminator-textarea,
.forminator-custom-form .forminator-textarea {
	height: auto !important; /* must grow past the shared field height */
	min-height: 9rem !important;
	resize: vertical;
}

/* The native select arrow is drawn by the OS and cannot be recoloured, so the
   control is stripped and the chevron redrawn to match the palette. The extra
   inline-end padding keeps a long option clear of it. */
.forminator-ui select,
.forminator-custom-form select {
	appearance: none !important;
	-webkit-appearance: none !important;
	-moz-appearance: none !important;
	padding-inline-end: 2.75rem !important;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%230e2c36' stroke-width='1.6'%3E%3Cpath d='M5 8l5 5 5-5'/%3E%3C/svg%3E") !important;
	background-repeat: no-repeat !important;
	background-position: right 1rem center !important;
	background-size: 1.05rem 1.05rem !important;
}

/* The open list. Browsers render this natively and honour little beyond
   colour, but the default grey is the one thing worth overriding. */
.forminator-ui select option,
.forminator-custom-form select option {
	background-color: #ffffff;
	color: var(--wp--preset--color--ink);
}

.forminator-ui .forminator-input::placeholder,
.forminator-ui .forminator-textarea::placeholder,
.forminator-custom-form .forminator-input::placeholder,
.forminator-custom-form .forminator-textarea::placeholder {
	color: var(--wp--preset--color--slate);
	opacity: 0.7;
}

.forminator-ui .forminator-input:focus,
.forminator-ui .forminator-textarea:focus,
.forminator-ui select:focus,
.forminator-custom-form .forminator-input:focus,
.forminator-custom-form .forminator-textarea:focus,
.forminator-custom-form select:focus {
	outline: none !important;
	border-color: var(--wp--preset--color--ember) !important;
	box-shadow: inset 0 0 0 1px var(--wp--preset--color--ember) !important;
}

.forminator-ui .forminator-label,
.forminator-custom-form .forminator-label {
	display: block;
	font-family: var(--wp--preset--font-family--heading) !important;
	font-size: var(--wp--preset--font-size--x-small) !important;
	font-weight: 600 !important;
	letter-spacing: 0.14em !important;
	text-transform: uppercase !important;
	color: var(--wp--preset--color--ink) !important;
	margin-block-end: 0.55em !important;
}

/* Required marker: ember-deep, since plain ember measures 3.31:1 on paper. */
.forminator-ui .forminator-required,
.forminator-custom-form .forminator-required {
	color: var(--wp--preset--color--ember-deep) !important;
}

.forminator-ui .forminator-error-message,
.forminator-custom-form .forminator-error-message {
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: 0.9375rem !important;
	color: #a3231b !important;
}

.forminator-ui .forminator-has_error .forminator-input,
.forminator-ui .forminator-has_error .forminator-textarea,
.forminator-ui .forminator-has_error select,
.forminator-custom-form .forminator-has_error .forminator-input,
.forminator-custom-form .forminator-has_error .forminator-textarea,
.forminator-custom-form .forminator-has_error select {
	border-color: #a3231b !important;
	box-shadow: inset 0 0 0 1px #a3231b !important;
}

/*
 * select2, which Forminator uses when a dropdown is set to searchable /
 * enhanced. Worth knowing why this block exists: a native <select> popup is
 * drawn by the operating system, and macOS ignores CSS on <option>, so the
 * open list stays system grey no matter what is written here. select2 renders
 * an ordinary HTML list instead, which can be made white.
 *
 * The dropdown is appended to <body>, so these selectors cannot be scoped to
 * the form.
 */
/*
 * Deliberately NOT scoped to .select2-container--default. Forminator ships its
 * own select2 theme, so the container carries a different modifier class and
 * default-scoped rules silently miss — which left the closed control and the
 * search strip system grey while the list itself was already white.
 */
.select2-selection,
.select2-selection--single {
	display: flex !important;
	align-items: center !important;
	box-sizing: border-box !important;
	height: var(--llb-field-h) !important;
	min-height: var(--llb-field-h) !important;
	background-color: var(--wp--preset--color--paper) !important;
	background-image: none !important;
	border: 1px solid var(--llb-field-border) !important;
	border-radius: 0 !important;
	padding: 0 var(--llb-field-pad-x) !important;
	outline: none !important;
}

.select2-selection__rendered {
	padding: 0 !important;
	line-height: normal !important;
	color: var(--wp--preset--color--ink) !important;
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: var(--wp--preset--font-size--medium) !important;
	background-color: transparent !important;
}

.select2-selection__arrow {
	height: 100% !important;
	inset-inline-end: 0.6rem !important;
	background: none !important;
}

.select2-container--open .select2-selection,
.select2-container--open .select2-selection--single {
	border-color: var(--wp--preset--color--ember) !important;
	box-shadow: inset 0 0 0 1px var(--wp--preset--color--ember) !important;
}

/* The panel, the results area and the search strip are three separate
   elements; each carries its own grey by default. */
.select2-dropdown,
.select2-results,
.select2-results__options,
.select2-search--dropdown {
	background-color: #ffffff !important;
	border-radius: 0 !important;
}

.select2-dropdown {
	border: 1px solid var(--llb-field-border) !important;
}

.select2-search--dropdown {
	padding: 0.5rem !important;
}

.select2-search--dropdown .select2-search__field {
	box-sizing: border-box !important;
	width: 100% !important;
	background-color: #ffffff !important;
	border: 1px solid var(--llb-field-border) !important;
	border-radius: 0 !important;
	padding: 0.4rem var(--llb-field-pad-x) !important;
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: var(--wp--preset--font-size--medium) !important;
	color: var(--wp--preset--color--ink) !important;
}

.select2-search--dropdown .select2-search__field:focus {
	outline: none !important;
	border-color: var(--wp--preset--color--ember) !important;
}

.select2-results__option {
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: var(--wp--preset--font-size--medium) !important;
	color: var(--wp--preset--color--ink) !important;
	background-color: #ffffff !important;
	padding: 0.45rem var(--llb-field-pad-x) !important;
}

.select2-results__option--highlighted,
.select2-results__option--highlighted[aria-selected],
.select2-results__option[data-selected="true"] {
	background-color: var(--wp--preset--color--mist) !important;
	color: var(--wp--preset--color--ink) !important;
}

.select2-results__option[aria-selected="true"] {
	background-color: color-mix(in srgb, var(--wp--preset--color--mist) 55%, #ffffff) !important;
}

/*
 * Forminator's own dropdown (newer versions), which replaces select2. Its
 * rules look like:
 *
 *   .forminator-select-dropdown-container--open
 *   .forminator-custom-form-99.forminator-dropdown--basic { background: #E6E6E6 }
 *
 * The "-99" is the form's ID, so matching it literally would break the moment
 * a second form exists or the form is rebuilt. The attribute selector below
 * matches any form ID; !important covers their three-class specificity.
 */
[class*="forminator-dropdown"],
[class*="forminator-select-dropdown"],
.forminator-select-dropdown-container--open [class*="forminator-dropdown"],
.forminator-dropdown--basic,
.forminator-dropdown-list,
.forminator-dropdown-search {
	background-color: #ffffff !important;
	border-radius: 0 !important;
}

/* Their open-state border is a stock blue; ember matches the rest of the form. */
.forminator-select-dropdown-container--open [class*="forminator-dropdown"],
[class*="forminator-dropdown"]:focus,
[class*="forminator-dropdown"]:focus-within {
	border-color: var(--wp--preset--color--ember) !important;
}

[class*="forminator-dropdown"] li,
[class*="forminator-dropdown"] .forminator-option,
[class*="forminator-select-dropdown"] li {
	background-color: #ffffff !important;
	color: var(--wp--preset--color--ink) !important;
	font-family: var(--wp--preset--font-family--body) !important;
	font-size: var(--wp--preset--font-size--medium) !important;
}

[class*="forminator-dropdown"] li:hover,
[class*="forminator-dropdown"] li[aria-selected="true"],
[class*="forminator-dropdown"] li.forminator-option--selected,
[class*="forminator-dropdown"] .forminator-option:hover,
[class*="forminator-select-dropdown"] li:hover {
	background-color: var(--wp--preset--color--mist) !important;
	color: var(--wp--preset--color--ink) !important;
}

/* The search box inside their dropdown. */
[class*="forminator-dropdown"] input[type="text"],
[class*="forminator-dropdown"] input[type="search"],
.forminator-dropdown-search input {
	background-color: #ffffff !important;
	border: 1px solid var(--llb-field-border) !important;
	border-radius: 0 !important;
	color: var(--wp--preset--color--ink) !important;
	font-family: var(--wp--preset--font-family--body) !important;
}

/* -------------------------------------------------------------------------
   11a-ii. Forminator submit button

   Matches .wp-block-button__link exactly — same face, weight, tracking,
   padding, square corners, ember-deep fill, and the same ink panel that
   slides up on hover.

   !important is unavoidable here, and deliberate. Forminator scopes its own
   button rules with the module's ID (".forminator-ui#forminator-module-123
   .forminator-button-submit"), and an ID selector cannot be outranked by
   class selectors at any length. Setting the form's Appearance > Style to
   "None" in Forminator removes those rules and makes this moot, but the
   button should look right whether or not that setting has been changed.
   ---------------------------------------------------------------------- */

.forminator-ui .forminator-button-submit,
.forminator-custom-form .forminator-button-submit,
.forminator-custom-form button[type="submit"] {
	position: relative;
	overflow: hidden;
	z-index: 0;
	border: 0 !important;
	border-radius: 0 !important;
	background: var(--wp--preset--color--ember-deep) !important;
	color: var(--wp--preset--color--paper) !important;
	font-family: var(--wp--preset--font-family--heading) !important;
	font-size: var(--wp--preset--font-size--x-small) !important;
	font-weight: 600 !important;
	letter-spacing: 0.06em !important;
	text-transform: uppercase !important;
	padding: 1em 2em !important;
	line-height: 1.2 !important;
	cursor: pointer;
	transition: color 420ms var(--llb-ease);
}

/* The ink panel that rises on hover, exactly as on the page buttons. */
.forminator-ui .forminator-button-submit::before,
.forminator-custom-form .forminator-button-submit::before,
.forminator-custom-form button[type="submit"]::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--wp--preset--color--ink);
	transform: translateY(101%);
	transition: transform 520ms var(--llb-ease);
}

.forminator-ui .forminator-button-submit:hover::before,
.forminator-ui .forminator-button-submit:focus-visible::before,
.forminator-custom-form .forminator-button-submit:hover::before,
.forminator-custom-form .forminator-button-submit:focus-visible::before,
.forminator-custom-form button[type="submit"]:hover::before,
.forminator-custom-form button[type="submit"]:focus-visible::before {
	transform: translateY(0);
}

.forminator-ui .forminator-button-submit:hover,
.forminator-ui .forminator-button-submit:focus-visible,
.forminator-custom-form .forminator-button-submit:hover,
.forminator-custom-form .forminator-button-submit:focus-visible,
.forminator-custom-form button[type="submit"]:hover,
.forminator-custom-form button[type="submit"]:focus-visible {
	background: var(--wp--preset--color--ember-deep) !important;
	color: var(--wp--preset--color--paper) !important;
}

@media (prefers-reduced-motion: reduce) {
	.forminator-ui .forminator-button-submit::before,
	.forminator-custom-form .forminator-button-submit::before,
	.forminator-custom-form button[type="submit"]::before {
		transition: none;
	}
}

/* -------------------------------------------------------------------------
   11b. Modal — a form (or anything else) opened from a button

   Any link whose href points at the id of a .llb-modal opens it. The dialog
   semantics, close button, focus trap and scroll lock are added by
   initFormModal() in motion.js, so the markup stays ordinary blocks that an
   editor can open and change.
   ---------------------------------------------------------------------- */

.llb-modal {
	position: fixed;
	inset: 0;
	z-index: 200;
	display: flex;
	align-items: flex-start;
	justify-content: center;
	padding: clamp(1rem, 5vh, 4rem) 1rem;
	overflow-y: auto;
	overscroll-behavior: contain;
	background: color-mix(in srgb, var(--wp--preset--color--ink) 62%, transparent);
	/*
	 * visibility, not display:none. A third-party form inside a display:none
	 * container cannot measure itself, and Forminator's select dropdowns come
	 * out mis-sized on first open. Hidden-but-laid-out avoids that, and
	 * position:fixed keeps it out of the document flow meanwhile.
	 */
	visibility: hidden;
	opacity: 0;
	transition:
		opacity 260ms var(--llb-ease),
		visibility 0s linear 260ms;
}

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
	.llb-modal {
		background: rgba(14, 44, 54, 0.62);
	}
}

.llb-modal.is-open {
	visibility: visible;
	opacity: 1;
	transition: opacity 260ms var(--llb-ease);
}

.llb-modal__panel {
	position: relative;
	width: 100%;
	max-width: 46rem;
	background: var(--wp--preset--color--paper);
	padding: clamp(1.75rem, 4vw, 3rem);
	box-shadow: 0 24px 64px rgba(14, 44, 54, 0.28);
}

.llb-modal__close {
	position: absolute;
	inset-block-start: 0.5rem;
	inset-inline-end: 0.5rem;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	padding: 0;
	background: none;
	border: 0;
	color: var(--wp--preset--color--ink);
	cursor: pointer;
	line-height: 0;
}

.llb-modal__close svg {
	width: 1.5rem;
	height: 1.5rem;
}

/* Scroll lock, shared with the mobile menu. */
.llb-modal-is-open {
	overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
	.llb-modal {
		transition: none;
	}
}

/*
 * In the editor the modal must be an ordinary block, or the form inside it
 * could never be reached to be edited.
 */
.editor-styles-wrapper .llb-modal {
	position: static;
	visibility: visible;
	opacity: 1;
	display: block;
	background: none;
	padding: 0;
	overflow: visible;
}

.editor-styles-wrapper .llb-modal__panel {
	box-shadow: none;
	border: 1px dashed color-mix(in srgb, var(--wp--preset--color--ink) 30%, transparent);
}

/* -------------------------------------------------------------------------
   12. Panel — Ember highlight

   Applied from the block sidebar (Styles > Panel — Ember highlight) to any
   Group block, so a section can be promoted without touching a template or
   re-importing a page.

   ember-deep, not ember: plain ember carries no legible text in either
   direction (paper 3.31:1, ink 4.26:1 — both under AA). ember-deep with
   paper text is 4.84:1, and matches the buttons.
   ---------------------------------------------------------------------- */

.is-style-llb-panel-ember {
	background-color: var(--wp--preset--color--ember-deep);
	color: var(--wp--preset--color--paper);
	padding: clamp(1.75rem, 4vw, 3.5rem);
}

.is-style-llb-panel-ember :is(h1, h2, h3, h4, h5, h6),
.is-style-llb-panel-ember :is(p, li, strong) {
	color: var(--wp--preset--color--paper);
}

/* The eyebrow's ember would vanish into the panel. */
.is-style-llb-panel-ember .llb-eyebrow {
	color: var(--wp--preset--color--paper);
}

.is-style-llb-panel-ember .llb-eyebrow::after {
	background: color-mix(in srgb, var(--wp--preset--color--paper) 55%, transparent);
}

.is-style-llb-panel-ember a:not(.wp-block-button__link) {
	color: var(--wp--preset--color--paper);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/*
 * Buttons inside the panel invert: a filled ember-deep button would be
 * invisible on an ember-deep panel.
 */
.is-style-llb-panel-ember .wp-block-button__link {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ember-deep);
}

.is-style-llb-panel-ember .wp-block-button__link:hover,
.is-style-llb-panel-ember .wp-block-button__link:focus-visible {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.is-style-llb-panel-ember .is-style-outline .wp-block-button__link {
	background: transparent;
	border-color: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--paper);
}

.is-style-llb-panel-ember .is-style-outline .wp-block-button__link::before {
	background: var(--wp--preset--color--paper);
}

.is-style-llb-panel-ember .is-style-outline .wp-block-button__link:hover,
.is-style-llb-panel-ember .is-style-outline .wp-block-button__link:focus-visible {
	color: var(--wp--preset--color--ember-deep);
}
