/*
 * Russian theme — global chrome layer.
 * Colour and type tokens live in theme.json (--wp--preset--*, --wp--custom--*);
 * the semantic aliases, radii and shadows of the dark system live in the
 * :root block below. Spec: docs/superpowers/specs/2026-10-09-rediseno-oscuro-design.md
 */

/* ---------------------------------------------------------------- Canvas.
 * The page is noche with red glows behind it (.russian-backdrop, printed at
 * wp_body_open by inc/hooks/chrome.php). body is positioned AND a stacking
 * context on purpose: positioned, so the backdrop can be `absolute; inset: 0`
 * and span the whole document — the glows belong to the page and scroll away
 * with it, like any background; fixed, they followed the reader around like a
 * sticker. A stacking context, so a child at z-index -1 paints ABOVE the
 * body's own background — in the root context it would land under the opaque
 * body background and never show.
 *
 * Because body is the containing block of every absolute element with no
 * positioned ancestor, the home's absolute header measures its `top` from
 * the body — which the admin bar already pushes down through html
 * { margin-top } — so that header sits at top: 0 in both states; see the
 * header rules below. Short pages (404) used to leave an undefined band
 * under the footer: the site wrapper fills the viewport and main absorbs
 * the slack. */
html { background-color: var(--wp--preset--color--noche); }
body {
	min-height: 100svh;
	position: relative;
	isolation: isolate;
	-webkit-font-smoothing: antialiased;
}
.wp-site-blocks { display: flex; flex-direction: column; min-height: 100svh; }
.wp-site-blocks > main { flex: 1 0 auto; }

h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

/* ------------------------------------------------------------- Tokens. */
:root {
	/* Native controls, scrollbars and form widgets follow the page. `only`
	   also opts out of Chrome's auto dark theme, which would otherwise try to
	   re-invert an already dark page. */
	color-scheme: only dark;

	/* Semantic aliases over the palette. Blocks may use either; a future light
	   mode is a remap of these nine lines. */
	--russian-bg: var(--wp--preset--color--noche);
	--russian-surface: var(--wp--preset--color--carbon);
	--russian-surface-2: var(--wp--preset--color--grafito);
	--russian-line: var(--wp--preset--color--linea);
	--russian-ink: var(--wp--preset--color--blanco);
	--russian-ink-muted: var(--wp--preset--color--humo);
	--russian-accent: var(--wp--preset--color--rojo);
	--russian-accent-strong: var(--wp--preset--color--rojo-profundo);
	--russian-accent-text: var(--wp--preset--color--rojo-claro);

	/* Glass: a panel floating over a map or a photo. */
	--russian-glass: rgba(21, 21, 24, 0.74);
	--russian-glass-line: rgba(255, 255, 255, 0.1);
	--russian-glass-blur: blur(18px) saturate(1.2);

	/* Radii: controls, cards, panels. Buttons and pills are 999px. */
	--russian-radius-sm: 10px;
	--russian-radius: 16px;
	--russian-radius-lg: 20px;

	/* Shadows on a dark page are depth, not tint: black, and only on things
	   that float (hover lift, popovers, the glass panel). */
	--russian-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3);
	--russian-shadow-md: 0 10px 30px rgba(0, 0, 0, 0.45);
	--russian-shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.6);
	--russian-card-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.04);

	/* The red button's hover glow, and WhatsApp's green — the float and the
	   disc at the end of every WhatsApp button; it holds a white glyph, never
	   white text (1.98:1). */
	--russian-accent-glow: 0 10px 28px rgba(224, 45, 45, 0.3);
	--russian-btn-ink: var(--wp--preset--color--blanco);
	--russian-btn-edge: var(--wp--preset--color--rojo);
	--russian-wa-fill: #25d366;
	--russian-wa-hover: #1fb85a;
	--russian-wa-ink: var(--wp--preset--color--noche);

	/* Form controls, shared by the search panels, the finder and CF7. */
	--russian-field-bg: var(--wp--preset--color--grafito);
	--russian-field-line: var(--wp--preset--color--linea);
	--russian-field-ring: 0 0 0 3px rgba(224, 45, 45, 0.25);
}

/* -------------------------------------------------------------- Backdrop.
 * Three red glows anchored to the page: one at the top right (the mockups'
 * light), one down the left side, one near the foot on the right, placed as
 * percentages of the document so a short page and the long home both get
 * their share. Still on the inner pages — a light drifting behind a listing
 * or a form competes with the reading — and alive on the home only, where
 * there is air and photography for it to play against: a drift with a swell
 * and a soft breath of opacity, on transform and opacity alone, so the layers
 * are composited and nothing ever repaints or reflows; the browser pauses
 * them in a background tab, and prefers-reduced-motion keeps them still.
 * The spans are oversized circles so the gradient's soft edge never shows. */
.russian-backdrop {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}
.russian-backdrop__glow {
	position: absolute;
	border-radius: 50%;
	will-change: transform;
}
.russian-backdrop__glow--a {
	width: 76vmax;
	height: 76vmax;
	top: -30vmax;
	right: -24vmax;
	background: radial-gradient(circle at center, rgba(176, 30, 35, 0.55) 0%, rgba(176, 30, 35, 0.22) 36%, rgba(176, 30, 35, 0) 68%);
}
.russian-backdrop__glow--b {
	width: 64vmax;
	height: 64vmax;
	top: 42%;
	left: -28vmax;
	background: radial-gradient(circle at center, rgba(224, 45, 45, 0.26) 0%, rgba(224, 45, 45, 0.1) 40%, rgba(224, 45, 45, 0) 66%);
}
.russian-backdrop__glow--c {
	width: 56vmax;
	height: 56vmax;
	top: 84%;
	right: -22vmax;
	background: radial-gradient(circle at center, rgba(176, 30, 35, 0.4) 0%, rgba(176, 30, 35, 0.14) 40%, rgba(176, 30, 35, 0) 66%);
}
/* The home's first screen is the video, so its top glow starts where the
 * video melts into the page instead of hiding behind it. */
body.home .russian-backdrop__glow--a { top: 55vh; }

/* body.home is WordPress's own front-page class. Three periods, none a
 * multiple of another, so the trio never settles into a loop the eye can
 * learn; wide enough travel to be seen — the earlier 6vw over 32s was not. */
@media (prefers-reduced-motion: no-preference) {
	body.home .russian-backdrop__glow--a { animation: russian-glow-a 20s ease-in-out infinite alternate; }
	body.home .russian-backdrop__glow--b { animation: russian-glow-b 26s ease-in-out infinite alternate; }
	body.home .russian-backdrop__glow--c { animation: russian-glow-c 32s ease-in-out infinite alternate; }
}
@keyframes russian-glow-a {
	from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.8; }
	50% { opacity: 1; }
	to { transform: translate3d(-18vw, 12vh, 0) scale(1.25); opacity: 0.75; }
}
@keyframes russian-glow-b {
	from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.85; }
	50% { opacity: 1; }
	to { transform: translate3d(16vw, -10vh, 0) scale(1.2); opacity: 0.75; }
}
@keyframes russian-glow-c {
	from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.85; }
	50% { opacity: 1; }
	to { transform: translate3d(-14vw, -12vh, 0) scale(1.15); opacity: 0.8; }
}

/* ------------------------------------------------------- Focus visible.
 * One ring sitewide. Rojo over noche measures 4.3:1, over the green WhatsApp
 * controls it drowns, so those take the white variant. */
:where(a, button, input, select, textarea, summary, [role="button"]):focus-visible {
	outline: 2px solid var(--wp--preset--color--rojo);
	outline-offset: 2px;
}
.russian-btn--wa:focus-visible,
.russian-whatsapp:focus-visible {
	outline-color: var(--wp--preset--color--blanco);
}

/* ------------------------------------------------------ Motion defaults.
 * Interactive color shifts share one timing; transforms stay per-component. */
:where(a, button) {
	transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.wp-element-button {
	transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.16s var(--wp--custom--ease), box-shadow 0.16s var(--wp--custom--ease);
}
.wp-element-button:active { transform: scale(0.98); }

/* Resting elevation on content surfaces that float over the canvas. */
.russian-card { box-shadow: var(--russian-shadow-sm), var(--russian-card-highlight); }
.russian-finder .rf-map-wrap,
.russian-business-map,
.russian-single-map { box-shadow: var(--russian-shadow-sm); }
.russian-hours,
figure.wp-block-table { border-radius: var(--russian-radius-sm); overflow: hidden; }

/* Reduced motion: a moving hero is exactly the kind of ambient motion the
 * preference asks to remove — the dim overlay carries the hero alone. */
@media (prefers-reduced-motion: reduce) {
	.wp-block-cover__video-background { display: none; }
}

/* ------------------------------------------------------- Sticky header.
 * Everywhere but a page that opens on a hero, the bar is pinned to the top. */
header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: var(--wp--custom--z--sticky);
}
body.admin-bar header.wp-block-template-part { top: var(--wp-admin--admin-bar--height, 32px); }

/* How much of the viewport the browser chrome and the admin bar have already
 * taken. The full-height hero subtracts it; the header offsets read the admin
 * bar directly, since they need it even when there is no hero. */
body.admin-bar { --russian-chrome-top: var(--wp-admin--admin-bar--height, 32px); }

/* ------------------------------------------- Header over the home's hero.
 * On a page whose first block is a Portada (body.russian-hero-top, set in
 * inc/hooks/chrome.php) the bar lies over the video and scrolls away with
 * the page, and site-chrome.js brings it back as .is-floating.
 *
 * `absolute`, and then `fixed` when floating — never `sticky`: sticky puts
 * the element back in flow, which would push <main> down by the bar's height
 * the moment the class lands, and the page would jump. Out of flow at rest
 * means there is no reserved space for the swap to disturb. */
body.russian-hero-top header.wp-block-template-part {
	position: absolute;
	inset-inline: 0;
	/* top: 0 with or without the admin bar: body is the containing block (see
	 * Canvas) and the bar's html { margin-top } already moves the body down.
	 * Adding the bar's height here as well put the header 32px under it. */
	top: 0;
	box-shadow: none;
	/* Keeps the scrim's negative z-index inside the header. Safe for the
	 * navigation overlay: a stacking context alone is not a containing block
	 * for fixed descendants — only transform, filter and friends are. */
	isolation: isolate;
}

/* The scrim is load-bearing, not decoration, and it has to carry the contrast
 * ON ITS OWN: the hero's dim is a slider in another block's panel that an
 * editor can drag to zero. Sized for the worst case — over a pure white frame
 * with the dim at 0, the alpha where the nav sits composites to #6A6A6A and
 * white text measures 5.38:1. It fades out BELOW the bar, which is why it is a
 * pseudo-element and not a background. */
body.russian-hero-top header.wp-block-template-part::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	height: 170px;
	z-index: -1;
	background: linear-gradient(180deg, rgba(11, 11, 13, 0.78) 0%, rgba(11, 11, 13, 0.45) 45%, transparent 100%);
	pointer-events: none;
}

body.russian-hero-top .russian-site-header {
	background: transparent;
	border-bottom-color: transparent;
}

/* Floating: site-chrome.js adds .is-floating once the hero is behind us, and
 * the bar comes back opaque. `fixed` and not `sticky` — see above. The exit
 * is a second animation name rather than a transition, because dropping the
 * class returns the bar to `absolute`, which at that scroll position is simply
 * off-screen: it would vanish in one frame instead of leaving. */
body.russian-hero-top header.wp-block-template-part.is-floating {
	position: fixed;
	top: 0;
}
body.russian-hero-top.admin-bar header.wp-block-template-part.is-floating { top: var(--wp-admin--admin-bar--height, 32px); }

/* Below 601px the admin bar is not fixed — it scrolls away with the page — so
 * a floating header must sit flush at the top or it leaves a dark gap. */
@media screen and (max-width: 600px) {
	body.russian-hero-top.admin-bar header.wp-block-template-part.is-floating { top: 0; }
}

/* Floating means opaque: the over-video treatment has to stop applying. */
body.russian-hero-top header.wp-block-template-part.is-floating::before { opacity: 0; }

/* Opaque-ish and NOT blurred: backdrop-filter, like filter and transform,
 * makes the bar the containing block of the fixed navigation overlay inside
 * it, which would clip the open menu to the bar's own height. */
body.russian-hero-top header.wp-block-template-part.is-floating .russian-site-header {
	background: rgba(11, 11, 13, 0.94);
	border-bottom-color: var(--wp--preset--color--linea);
}

@media (prefers-reduced-motion: no-preference) {
	body.russian-hero-top header.wp-block-template-part.is-floating:not(.is-leaving) {
		animation: russian-header-down 0.3s var(--wp--custom--ease);
	}
	body.russian-hero-top header.wp-block-template-part.is-floating.is-leaving {
		animation: russian-header-up 0.3s var(--wp--custom--ease) forwards;
	}
}

/* The navigation's open overlay is position:fixed and lives INSIDE the header,
 * so a USED transform on the bar becomes that overlay's containing block and
 * clips it to the 73px bar — measured at 375x73 instead of 375x780 when the
 * menu was opened mid-slide. The transform only exists during the 300ms
 * animation, so cancelling the animation closes the window entirely. Core
 * marks the open state on the documentElement, not the body. !important
 * because a running animation outranks a normal declaration. */
html.has-modal-open header.wp-block-template-part {
	animation: none !important;
	transform: none !important;
}

/* `isolation: isolate` on the floating header seals a stacking context, so the
 * overlay's z-index: 100000 is resolved INSIDE it and competes as the header's
 * own 300 — under the WhatsApp float at --z-float. Lifting the whole bar past
 * the overlay layer is the fix; raising the trapped child does nothing. */
html.has-modal-open body.russian-hero-top header.wp-block-template-part {
	z-index: calc(var(--wp--custom--z--overlay) + 1);
}

@keyframes russian-header-down {
	from { transform: translateY(-100%); }
}

@keyframes russian-header-up {
	to { transform: translateY(-100%); }
}

/* Anchors inside the page must clear the bar when it is overhead. */
[id] { scroll-margin-top: 5.5rem; }

/* -------------------------------------------------------- Micro-labels.
 * The one label spec: badges, tabs, legends and footer headings converge
 * here (blocks consume the same --wp--custom--label tokens). */
.russian-label {
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--custom--label--size);
	font-weight: var(--wp--custom--label--weight);
	letter-spacing: var(--wp--custom--label--tracking);
	text-transform: uppercase;
	color: var(--wp--preset--color--humo);
}

/* ------------------------------------------------------ Social profiles.
 * One icon row, rendered by russian_social_links_html() into both the header
 * and the footer — which is why it lives here and not in either block. The
 * links are icon-only, so each carries its name in a .russian-sr span. */
.russian-social {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.russian-social__link {
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	border-radius: 50%;
	color: var(--wp--preset--color--humo);
	text-decoration: none;
}
.russian-social__link:hover { color: var(--wp--preset--color--blanco); }

/* Two classes on purpose: the generic .russian-icon sizing rule sits further
 * down this same file and would otherwise win the tie at 1em. */
.russian-social .russian-social__icon {
	width: 1.25rem;
	height: 1.25rem;
}

@media (hover: hover) and (pointer: fine) {
	.russian-social__link:hover { background: rgba(255, 255, 255, 0.08); }
}

.russian-social--footer { margin-top: 1.25rem; }

/* Six icons plus the logo and the burger do not fit a phone, and the footer
 * carries the same row a scroll away. */
@media (max-width: 899.98px) {
	.russian-social--header { display: none; }
}

/* --------------------------------------------------- Icons + a11y label.
 * Icons come from russian_icon() (inc/functions/icons.php); they inherit
 * colour and are sized per context. .russian-sr keeps the meaning of an
 * icon-only value available to screen readers without showing it — the
 * theme defines its own rather than leaning on block-library's
 * .screen-reader-text, which is not guaranteed to be enqueued. */
.russian-icon {
	width: 4em;
	height: 4em;
	fill: currentColor;
	flex: 0 0 auto;
}
/* ------------------------------------------- Hero flush under the header.
 * WordPress spaces every top-level block with blockGap and only exempts the
 * first child, so <main> inherits 1.5rem under the header. On pages that open
 * with a heading that gap is wanted; under a full-bleed hero it reads as a
 * seam. Scoped with :has() so only the hero case loses it. The second
 * selector is the same page served from a Page: the home's blocks live in
 * post_content, so the hero is one level deeper than on a template. */
.wp-site-blocks > main:has(> .russian-hero:first-child),
.wp-site-blocks > main:has(> .wp-block-post-content:first-child > .russian-hero:first-child) {
	margin-block-start: 0;
}

/* Whatever follows the hero sits flush under it. Core's flow layout gives
 * every child of post-content 1.5rem of blockGap, which under a full-bleed
 * video reads as a strip of page between the video and the next band — the
 * map band, on the home. (0,2,0) so it outranks core's (0,1,0) regardless
 * of load order; both shapes, in case the hero ever sits in a template. */
.wp-block-post-content > .russian-hero + *,
.wp-site-blocks > main > .russian-hero + * {
	margin-block-start: 0;
}

/* A page that CLOSES on a full-bleed band keeps no bottom padding: the band
 * brings its own. !important because the padding is an INLINE style on <main>
 * written by the template's block attributes. One declaration, one :has(). */
.wp-site-blocks > main:has(> .wp-block-post-content > .russian-section:last-child) {
	padding-bottom: 0 !important;
}
.wp-site-blocks > main:has(> .wp-block-post-content > .russian-section:last-child) + footer {
	margin-block-start: 0;
}

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

/* ------------------------------------------------------- Prose links.
 * theme.json paints links blanco with a rojo-claro hover; in running text the
 * underline is what tells a link from a word, so it is red from the start. */
.entry-content p a:where(:not(.wp-element-button)),
.russian-band p a:where(:not(.wp-element-button)),
.russian-footer a:where(:not(.wp-element-button)) {
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	text-decoration-color: color-mix(in srgb, var(--wp--preset--color--rojo) 60%, transparent);
}
.entry-content p a:where(:not(.wp-element-button)):hover,
.russian-band p a:where(:not(.wp-element-button)):hover,
.russian-footer a:where(:not(.wp-element-button)):hover {
	text-decoration-color: currentColor;
}

/* ------------------------------------------------------- Red button.
 * One hover for every red button in the theme: a darker red, a soft red glow
 * and a 1px lift. The old ghost hover (fill drops out, outline stays) is
 * retired with the light theme — over noche a button that loses its fill
 * reads as switched off, not as pressed.
 *
 * The 2px border is declared AT REST, transparent, so a border that any block
 * adds on hover never grows the box under the cursor. box-sizing because
 * .russian-mapband__cta is width: 100%.
 *
 * Deliberately NOT in here: the circular controls (.russian-carousel-arrow,
 * .russian-carousel-nav__pause, property-video's play, the WhatsApp float),
 * .rf-pill (the map's price pins), the badges (pills, not buttons), the
 * finder's checkbox and its sheet grabbers. The finder's own Apply buttons are
 * handled in property-finder/style.scss. */
.wp-element-button,
.russian-price__cta,
.russian-search button,
.russian-mapband__cta {
	box-sizing: border-box;
	border: 2px solid transparent;
	border-radius: 999px;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	line-height: 1.2;
	padding: 0.85rem 1.6rem;
	text-decoration: none;
	cursor: pointer;
}

/* An `a` is inline, and an inline box's VERTICAL padding paints without taking
 * any room in the line. Core never hits this because its own button is an `a`
 * inside .wp-block-button; the buttons this theme prints from a render.php are
 * bare `a.wp-element-button`. */
.wp-element-button:not(.wp-block-button__link) {
	display: inline-block;
}

/* :not(:disabled) es obligatorio: un botón deshabilitado sigue disparando
 * :hover en CSS, y sin esto el CTA del mapa —que se deshabilita solo cuando
 * ningún filtro devuelve resultados— se veía exactamente igual que uno activo
 * apenas le pasabas el mouse por encima. */
.wp-element-button:hover:not(:disabled),
.russian-price__cta:hover:not(:disabled),
.russian-search button:hover:not(:disabled),
.russian-mapband__cta:hover:not(:disabled) {
	background-color: var(--wp--preset--color--rojo-profundo);
	color: var(--wp--preset--color--blanco);
	box-shadow: var(--russian-accent-glow);
	transform: translateY(-1px);
}
.wp-element-button:disabled,
.russian-mapband__cta:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* ------------------------------------------------------ Outline button.
 * Quiet sibling of the red CTA, for secondary actions. */
.wp-block-button.is-style-outline .wp-block-button__link,
.russian-btn--outline.russian-btn--outline {
	border: 1px solid rgba(255, 255, 255, 0.22);
	color: var(--wp--preset--color--blanco);
	background: transparent;
	padding: calc(0.85rem + 1px) calc(1.6rem + 1px);
}
.wp-block-button.is-style-outline .wp-block-button__link:hover,
.russian-btn--outline.russian-btn--outline:hover {
	background: rgba(255, 255, 255, 0.06);
	border-color: rgba(255, 255, 255, 0.4);
	color: var(--wp--preset--color--blanco);
	box-shadow: none;
}

/* ------------------------------------------------------- WhatsApp button.
 * The client's mockup: a red pill with a thin white edge and the label in
 * white capitals like every other CTA, and hanging off its right end a green
 * disc with the white WhatsApp mark, ringed in white so it stands off the
 * red and reads as a badge, not as a second button. The disc is the WhatsApp signifier (the float wears the
 * same one); the pill is the brand's. Printed by russian_whatsapp_button_html()
 * only. The doubled class outranks
 * `.wp-element-button:not(.wp-block-button__link) { display: inline-block }`
 * and the ficha's own `.russian-price__cta` display. */
.russian-btn--wa.russian-btn--wa {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.85rem;
	padding: 0.85rem 0.75rem 0.85rem 1.6rem;
	background: var(--wp--preset--color--rojo);
	color: var(--wp--preset--color--blanco);
	/* The shared rule reserves a 2px transparent border on every button, so
	 * painting it costs no size: the mockup's thin white edge. */
	border-color: rgba(255, 255, 255, 0.75);
}
.russian-btn--wa.russian-btn--wa:hover:not(:disabled) {
	background: var(--wp--preset--color--rojo-profundo);
	border-color: var(--wp--preset--color--blanco);
	color: var(--wp--preset--color--blanco);
	box-shadow: var(--russian-accent-glow);
	transform: translateY(-1px);
}
.russian-btn--wa__label { white-space: nowrap; }
.russian-btn--wa__badge {
	display: grid;
	place-items: center;
	flex: none;
	width: 50px;
	height: 50px;
	/* The disc's margin box collapses to the label's line height, so the pill
	 * keeps the 50px every other pill has and the disc (56px with its ring)
	 * overhangs it by 3px above and below and sits past its end — the
	 * mockup's proportion. */
	margin: -1.15rem -1.125rem -1.15rem 0;
	border-radius: 50%;
	background: var(--russian-wa-fill);
	color: var(--wp--preset--color--blanco);
	border: 3px solid var(--wp--preset--color--blanco);
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
	transition: transform 0.16s var(--wp--custom--ease);
}
.russian-btn--wa__badge .russian-icon {
	width: 26px;
	height: 26px;
	fill: currentColor;
}
@media (hover: hover) and (pointer: fine) {
	.russian-btn--wa:hover .russian-btn--wa__badge { transform: scale(1.06); }
}
/* A WhatsApp button inside a form card's foot or the fallback stretches like
 * the submit above it would; the badge keeps its end. */
.russian-form__fallback .russian-btn--wa { justify-content: space-between; }

/* Buttons that carry a leading icon (the finder's "Ver en el mapa", the
 * bands' actions): same glyph size as the WhatsApp one. */
.russian-btn__icon {
	width: 18px;
	height: 18px;
	flex: none;
	fill: currentColor;
	vertical-align: -3px;
	margin-inline-end: 0.5rem;
}

/* ------------------------------------------------------- Section bands.
 * Every section block renders one full-bleed band. The gutter and the
 * measure its content centres on are identical between them, so they live
 * here instead of being copied into every block stylesheet; a block only
 * sets --russian-section-max when it needs a wider (or narrower) measure.
 * This file loads after the per-block CSS, so these win ties on purpose. */
.russian-section {
	padding-inline: var(--wp--custom--gutter);
}
.russian-section__inner {
	max-width: var(--russian-section-max, 1140px);
	margin-inline: auto;
}

/* Vertical rhythm is opt-in, not part of __inner: the header bar lays its
 * inner out as a flex row, where a margin-block-start on the second child is
 * a gap in the wrong axis, and the footer sets its own margins around the
 * rule. Blocks that just stack things ask for __stack. */
.russian-section__stack > * { margin-block: 0; }
.russian-section__stack > * + * { margin-block-start: 1.5rem; }

/* Heading on the left, "ver todas"-style link or button on the right. */
.russian-section__head {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
}
.russian-section__head > * { margin: 0; }

/* The mockups' opening: title in capitals, centred, a muted lead under it.
 * Used by the three bands (about, contact, tasación) and by any block that
 * asks for it; the H1 of the flat pages takes the same look below. */
.russian-section__head--center {
	display: grid;
	justify-items: center;
	text-align: center;
	gap: 0.75rem;
}
.russian-section__lead {
	margin: 0;
	max-width: 60ch;
	font-size: clamp(1.05rem, 1.5vw, 1.25rem);
	line-height: 1.5;
	color: var(--wp--preset--color--humo);
}
.russian-section__head--center .russian-section__lead { margin-inline: auto; }

/* ------------------------------------------------- Section heading mark.
 * A 1.75rem x 2px rojo stroke in the clear space above every band heading —
 * the line every section opens with. ABOVE the heading, not under it: the
 * underline slot on a .russian-section__head row is already spent by
 * .russian-section-link, and h1-h3 carry text-wrap: balance, so a wrapped
 * heading's LAST line is not its widest.
 *
 * SYMMETRIC padding: .russian-section__head is align-items: center with the
 * "Ver todas" link at the far end, so a box that grew only upward would lift
 * its own centre and leave the link floating high. Padding and not margin,
 * because __stack > * and __head > * both zero heading margins at (0,1,0).
 *
 * The ornament is a ::before INSIDE the heading, never a sibling element, so it
 * cannot become a third flex item. Reach is structural, with no :not() and no
 * opt-out class: scoping through __stack is what does it — map-band's list
 * heading sits in an __inner without __stack, about-teaser's claim, the hero
 * h1, the finder's "Filtros", the footer's labels and every card title all live
 * outside a __stack. __stack means "a band that stacks AND opens with the mark".
 *
 * The flat pages take the same mark through one selector per SHAPE of opening:
 * the page title (page.html), the archive's own H1, the zona archives' query
 * title, in-page section headings, the ficha's "Ubicación" and the 404's
 * title. The ficha's own title opens on .russian-backlink instead, and a
 * card's heading is never a direct child of a prose group. */
:root {
	--russian-mark-w: 1.75rem;
	--russian-mark-h: 2px;
	--russian-mark-gap: 0.75rem;
	--russian-mark-ink: var(--wp--preset--color--rojo);
}

.russian-section__stack > .wp-block-heading,
.russian-section__stack > .russian-section__head > .wp-block-heading,
.russian-section__head--center > .wp-block-heading,
body.page main > .wp-block-post-title,
body.archive main > h1.wp-block-heading,
body.archive main > .wp-block-query-title,
.entry-content > .wp-block-group > .wp-block-heading,
.russian-ficha-location > .wp-block-heading,
body.error404 main > .wp-block-heading {
	position: relative;
	padding-block: calc(var(--russian-mark-gap) + var(--russian-mark-h));
}

.russian-section__stack > .wp-block-heading::before,
.russian-section__stack > .russian-section__head > .wp-block-heading::before,
.russian-section__head--center > .wp-block-heading::before,
body.page main > .wp-block-post-title::before,
body.archive main > h1.wp-block-heading::before,
body.archive main > .wp-block-query-title::before,
.entry-content > .wp-block-group > .wp-block-heading::before,
.russian-ficha-location > .wp-block-heading::before,
body.error404 main > .wp-block-heading::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	width: var(--russian-mark-w);
	height: var(--russian-mark-h);
	background: var(--russian-mark-ink);
}

/* A page opens ONCE. When the content's very first block is itself a heading it
 * is a subtitle of the page title, not a new section; the heading keeps its
 * padding so the rhythm below it does not shift, only the stroke goes. */
.entry-content > .wp-block-group:first-child > .wp-block-heading:first-child::before {
	content: none;
}

/* Centred headings centre their mark: inset-inline: 0 plus auto inline margins
 * is how an absolutely positioned box of known width centres itself; at
 * (0,3,1) it supersedes the inset-inline-start above. */
.russian-section__stack > .wp-block-heading.has-text-align-center::before,
.russian-section__head--center > .wp-block-heading::before,
body.page main > .wp-block-post-title::before,
body.archive main > h1.wp-block-heading::before,
body.archive main > .wp-block-query-title::before {
	inset-inline: 0;
	margin-inline: auto;
}

/* --------------------------------------------------------- Title style.
 * The mockups set every page and band title in bold capitals. Applied by the
 * same structure that places the mark, so a block opens the way the system
 * does by construction; card and panel titles (h3 inside a card) never take
 * it. Page titles and archive H1s are centred like the mockups' openings; the
 * in-band headings keep their row with the "Ver todas" link on the right. */
.russian-section__stack > .wp-block-heading,
.russian-section__stack > .russian-section__head > .wp-block-heading,
.russian-section__head--center > .wp-block-heading,
body.page main > .wp-block-post-title,
body.archive main > h1.wp-block-heading,
body.archive main > .wp-block-query-title,
.entry-content > .wp-block-group > .wp-block-heading,
.russian-ficha-location > .wp-block-heading,
body.error404 main > .wp-block-heading,
.russian-title {
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 800;
	line-height: 1.05;
	letter-spacing: -0.015em;
	text-transform: uppercase;
}
body.page main > .wp-block-post-title,
body.archive main > h1.wp-block-heading,
body.archive main > .wp-block-query-title {
	font-size: var(--wp--preset--font-size--x-large);
	text-align: center;
	margin-inline: auto;
	max-width: 24ch;
}
/* A lead right under a page title, written as a paragraph with this class by
 * the seed or the archive template. */
.russian-page-lead {
	text-align: center;
	max-width: 60ch;
	margin: 0 auto;
	font-size: clamp(1.05rem, 1.5vw, 1.25rem);
	line-height: 1.5;
	color: var(--wp--preset--color--humo);
}

/* -------------------------------------------------------- Section link.
 * "Ver todas" style CTA sitting right of a section heading. White type with
 * the red on the edge — the arrow and the underline — never on the word:
 * these links sit straight on the page, where the backdrop's glow passes
 * behind them, and red type over a red-tinted ground went muddy (client,
 * 2026-10-09). The underline is a guide at rest and full red on hover. */
.russian-section-link {
	display: inline-flex;
	align-items: baseline;
	gap: 0.4rem;
	font-size: 0.9375rem;
	font-weight: 600;
	color: var(--wp--preset--color--blanco);
	text-decoration: none;
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--rojo) 45%, transparent);
	padding-bottom: 2px;
	transition: border-color 0.15s ease;
}
.russian-section-link::after {
	content: "\2192";
	color: var(--wp--preset--color--rojo-claro);
	transition: translate 0.18s var(--wp--custom--ease);
}
.russian-section-link:hover { border-color: var(--wp--preset--color--rojo); color: var(--wp--preset--color--blanco); }
@media (hover: hover) and (pointer: fine) {
	.russian-section-link:hover::after { translate: 3px 0; }
}

/* ------------------------------------------------------- Ficha chrome.
 * Quiet wayfinding link above the property title, and the Ubicación group
 * that collapses entirely when the map block renders nothing (no coords). */
.russian-backlink {
	margin-bottom: 0;
}
.russian-backlink a {
	font-size: var(--wp--custom--label--size);
	font-weight: var(--wp--custom--label--weight);
	letter-spacing: var(--wp--custom--label--tracking);
	text-transform: uppercase;
	color: var(--wp--preset--color--humo);
	text-decoration: none;
}
.russian-backlink a:hover { color: var(--wp--preset--color--blanco); }
.russian-ficha-location:not(:has(.russian-single-map)) { display: none; }

/* ----------------------------------------------------- Header navigation.
 * Links at 78% white, full white on hover with a hairline that slides in from
 * the left. Current page: the word in rojo-claro and the line in rojo — the
 * one red accent the header carries, the way the mockups draw it. */
.wp-block-navigation .wp-block-navigation-item__content {
	position: relative;
	padding-block: 0.3rem;
	color: rgba(255, 255, 255, 0.78);
}
.wp-block-navigation .wp-block-navigation-item__content:hover { color: var(--wp--preset--color--blanco); }
.wp-block-navigation .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 2px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.22s var(--wp--custom--ease);
}
@media (hover: hover) and (pointer: fine) {
	.wp-block-navigation .wp-block-navigation-item__content:hover::after,
	.wp-block-navigation .wp-block-navigation-item__content:focus-visible::after { transform: scaleX(1); }
}
.wp-block-navigation .wp-block-navigation-item__content[aria-current="page"] {
	color: var(--wp--preset--color--rojo-claro);
}
.wp-block-navigation .wp-block-navigation-item__content[aria-current="page"]::after {
	transform: scaleX(1);
	background: var(--wp--preset--color--rojo);
}

/* The mobile overlay speaks its own language (display capitals, staggered) —
 * the underline stays out; the current page shows in rojo-claro instead. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content::after { display: none; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content[aria-current="page"] {
	color: var(--wp--preset--color--rojo-claro);
}

@media (prefers-reduced-motion: reduce) {
	.wp-block-navigation .wp-block-navigation-item__content::after { transition: none; }
}

/* Core ships both menu buttons as a bare 24x24 glyph with no padding, which is
 * the whole hit area. Padding grows the box to 44x44 and the equal negative
 * margin hands the layout back, so the glyph does not move by a pixel. */
.russian-site-header .wp-block-navigation__responsive-container-open,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
	padding: 10px;
	margin: -10px;
	color: var(--wp--preset--color--blanco);
}

/* -------------------------------------------- Mobile navigation overlay.
 * The overlay's colours come from the navigation block's own
 * overlayBackgroundColor / overlayTextColor (site-header/render.php sets
 * noche / blanco); this only lays the words out. */
.wp-block-navigation__responsive-container.is-menu-open {
	padding: 5.5rem var(--wp--custom--gutter) 3rem;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
	padding-top: 0;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container {
	gap: 1.1rem;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--sans);
	font-size: 1.9rem;
	font-weight: 800;
	line-height: 1.2;
	letter-spacing: -0.015em;
	text-transform: uppercase;
	color: var(--wp--preset--color--blanco);
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item {
	animation: russian-nav-in 0.35s var(--wp--custom--ease) backwards;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(2) { animation-delay: 0.05s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(3) { animation-delay: 0.1s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(4) { animation-delay: 0.15s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(5) { animation-delay: 0.2s; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item:nth-child(6) { animation-delay: 0.25s; }

@keyframes russian-nav-in {
	from {
		opacity: 0;
		transform: translateY(10px);
	}
}

/* ------------------------------------------------- Content-page prose. */
/* Editorial tables: hairline row rules instead of the default cell boxes. */
.wp-block-table table {
	border-collapse: collapse;
	width: 100%;
	border: 0;
}
.wp-block-table td,
.wp-block-table th {
	border: 0;
	border-bottom: 1px solid var(--wp--preset--color--linea);
	padding: 0.75rem 1rem 0.75rem 0;
	text-align: left;
}
.wp-block-table tr:first-child td,
.wp-block-table tr:first-child th {
	border-top: 1px solid var(--wp--preset--color--linea);
}
/* Contact columns (legacy content): room between the text and the map. */
.russian-contact-cols { gap: 2.5rem; }

/* Pull-quote as an editorial statement: bold, left aligned, hairlines. */
.wp-block-pullquote {
	border-top: 1px solid var(--wp--preset--color--linea);
	border-bottom: 1px solid var(--wp--preset--color--linea);
	margin: 0;
	padding: var(--wp--preset--spacing--40) 0;
	text-align: left;
}
.wp-block-pullquote blockquote { margin: 0; }
.wp-block-pullquote p {
	font-family: var(--wp--preset--font-family--sans);
	font-size: 1.5rem;
	font-weight: 700;
	line-height: 1.35;
	letter-spacing: -0.01em;
	font-style: normal;
	margin: 0;
}

/* Numbered process steps (tasaciones): the order carries information. */
ol.russian-steps {
	list-style: none;
	counter-reset: russian-step;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 1.1rem;
}
ol.russian-steps li {
	counter-increment: russian-step;
	position: relative;
	padding-left: 3.4rem;
	min-height: 2.3rem;
}
ol.russian-steps li::before {
	content: counter(russian-step);
	position: absolute;
	left: 0;
	top: -0.15rem;
	width: 2.25rem;
	height: 2.25rem;
	display: grid;
	place-items: center;
	border: 1px solid var(--wp--preset--color--linea);
	border-radius: 50%;
	background: var(--wp--preset--color--grafito);
	font-weight: 700;
	font-size: 0.95rem;
	color: var(--wp--preset--color--blanco);
}

/* ------------------------------------------------------- Form controls.
 * The one field spec. Scoped to .russian-form so the finder, the map band and
 * the search bar — which each own their controls — are not touched here; the
 * three bands print their CF7 form inside a .russian-form wrapper. */
.russian-form label,
.russian-form .russian-form__label {
	display: block;
	font-size: 0.875rem;
	font-weight: 500;
	color: var(--wp--preset--color--humo);
	margin: 0 0 0.4rem;
}
.russian-form .wpcf7-form-control-wrap { display: block; }
.russian-form input:not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
.russian-form select,
.russian-form textarea,
.russian-field {
	box-sizing: border-box;
	width: 100%;
	padding: 0.75rem 0.95rem;
	border: 1px solid var(--russian-field-line);
	border-radius: var(--russian-radius-sm);
	background: var(--russian-field-bg);
	color: var(--wp--preset--color--blanco);
	font: inherit;
	line-height: 1.4;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.russian-form textarea { min-height: 7.5rem; resize: vertical; }
.russian-form ::placeholder { color: var(--wp--preset--color--humo); opacity: 1; }
.russian-form select {
	appearance: none;
	padding-right: 2.4rem;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23A4A4AC' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 0.95rem center;
	cursor: pointer;
}
.russian-form input:not([type="radio"]):not([type="checkbox"]):focus-visible,
.russian-form select:focus-visible,
.russian-form textarea:focus-visible {
	outline: none;
	border-color: var(--wp--preset--color--rojo);
	box-shadow: var(--russian-field-ring);
}
.russian-form .wpcf7-not-valid {
	border-color: var(--wp--preset--color--rojo);
}
.russian-form__row { margin: 0 0 1rem; }
.russian-form__row:last-child { margin-bottom: 0; }

/* Segmented control: CF7's radio list dressed as one track. Each option is a
 * label wrapping a real radio, so keyboard and screen readers see a radio
 * group; the track is what sighted users see. */
.russian-form .russian-segment .wpcf7-radio,
.russian-segment__track {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 1fr;
	gap: 3px;
	padding: 3px;
	border-radius: 999px;
	background: var(--russian-field-bg);
	border: 1px solid var(--russian-field-line);
}
.russian-form .russian-segment .wpcf7-list-item {
	margin: 0;
	display: block;
}
.russian-form .russian-segment .wpcf7-list-item label {
	position: relative;
	display: block;
	margin: 0;
	text-align: center;
	cursor: pointer;
}
.russian-form .russian-segment input[type="radio"] {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	opacity: 0;
	cursor: pointer;
}
.russian-form .russian-segment .wpcf7-list-item-label {
	display: block;
	padding: 0.6rem 0.75rem;
	border-radius: 999px;
	font-size: 0.9375rem;
	font-weight: 500;
	color: var(--wp--preset--color--blanco);
	transition: background-color 0.15s ease, color 0.15s ease;
}
.russian-form .russian-segment input[type="radio"]:checked + .wpcf7-list-item-label {
	background: var(--wp--preset--color--rojo);
	color: var(--wp--preset--color--blanco);
	font-weight: 600;
}
.russian-form .russian-segment input[type="radio"]:focus-visible + .wpcf7-list-item-label {
	box-shadow: var(--russian-field-ring);
}

/* Submit: the shared red button, full width inside a card. */
.russian-form input[type="submit"],
.russian-form .wpcf7-submit {
	display: block;
	width: 100%;
	box-sizing: border-box;
	border: 2px solid transparent;
	border-radius: 999px;
	padding: 0.9rem 1.6rem;
	background: var(--wp--preset--color--rojo);
	color: var(--wp--preset--color--blanco);
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color 0.15s ease, box-shadow 0.16s var(--wp--custom--ease), transform 0.16s var(--wp--custom--ease);
}
.russian-form .wpcf7-submit:hover:not(:disabled) {
	background: var(--wp--preset--color--rojo-profundo);
	box-shadow: var(--russian-accent-glow);
	transform: translateY(-1px);
}
.russian-form .wpcf7-submit:disabled { opacity: 0.6; cursor: wait; }

/* CF7 feedback. Its stylesheet is not loaded (wpcf7_load_css → false); these
 * are the only CF7 classes the theme needs to dress. */
.russian-form .wpcf7-spinner {
	display: inline-block;
	width: 1rem;
	height: 1rem;
	margin: 0 0 0 0.75rem;
	vertical-align: middle;
	border: 2px solid rgba(255, 255, 255, 0.25);
	border-top-color: var(--wp--preset--color--blanco);
	border-radius: 50%;
	visibility: hidden;
	animation: russian-spin 0.8s linear infinite;
}
.russian-form .wpcf7-form.submitting .wpcf7-spinner { visibility: visible; }
@keyframes russian-spin { to { transform: rotate(360deg); } }
.russian-form .wpcf7-not-valid-tip {
	display: block;
	margin-top: 0.35rem;
	font-size: 0.8125rem;
	color: var(--wp--preset--color--rojo-claro);
}
.russian-form .wpcf7-response-output {
	margin: 1rem 0 0;
	padding: 0.8rem 1rem;
	border: 1px solid var(--wp--preset--color--linea);
	border-radius: var(--russian-radius-sm);
	font-size: 0.9rem;
	line-height: 1.45;
	color: var(--wp--preset--color--blanco);
}
.russian-form .wpcf7-form.init .wpcf7-response-output { display: none; }
.russian-form .wpcf7-form.sent .wpcf7-response-output {
	border-color: rgba(37, 211, 102, 0.5);
	background: rgba(37, 211, 102, 0.1);
}
.russian-form .wpcf7-form.invalid .wpcf7-response-output,
.russian-form .wpcf7-form.failed .wpcf7-response-output,
.russian-form .wpcf7-form.spam .wpcf7-response-output,
.russian-form .wpcf7-form.aborted .wpcf7-response-output {
	border-color: rgba(224, 45, 45, 0.5);
	background: rgba(224, 45, 45, 0.1);
}
/* CF7's own chrome, which its stylesheet (not loaded) would hide: the
 * fieldset of hidden fields draws a default border otherwise, and the live
 * region for screen readers stays in the accessibility tree, off-screen. */
.russian-form .hidden-fields-container { display: none; }
.russian-form .screen-reader-response {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
}
/* The honeypot: off-screen, never display:none (some bots skip hidden fields). */
.russian-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ------------------------------------------------------------ Bands.
 * The three content bands (about, contact, tasación) share one shell: a
 * centred head and a two-column grid from 900px. The columns are cards or
 * figures; each band's own stylesheet dresses what is inside them. */
.russian-band { padding-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--60); }
.russian-band__grid {
	display: grid;
	/* One explicit column on phones. Left implicit, the track was `auto` and
	 * grew to the card's min-content (the button row), 22-49px past the
	 * viewport on /nosotros/ and /contacto/ at 375px. */
	grid-template-columns: minmax(0, 1fr);
	gap: 1.5rem;
	margin-block-start: 2.5rem;
	align-items: stretch;
}
@media (min-width: 900px) {
	.russian-band__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 2rem; }
	.russian-band__grid--wide-start { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
	/* Story card first, the team's videos where the photo used to be. */
	.russian-band__grid--with-team { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); align-items: start; }
	/* No photo: the card alone, centred under the centred head. It used to
	 * keep the two-column track and sit in the left half beside a hole —
	 * /nosotros/ since the about band stopped borrowing the portrait. Capped
	 * at a reading measure, not the 1140px band. */
	.russian-band__grid--solo {
		grid-template-columns: minmax(0, 48rem);
		justify-content: center;
	}
}
.russian-band__card {
	box-sizing: border-box;
	padding: clamp(1.4rem, 3vw, 2.25rem);
	background: var(--wp--preset--color--carbon);
	border: 1px solid var(--wp--preset--color--linea);
	border-radius: var(--russian-radius-lg);
	box-shadow: var(--russian-card-highlight);
}
.russian-band__card > :first-child { margin-top: 0; }
.russian-band__card > :last-child { margin-bottom: 0; }
.russian-band__card-title {
	margin: 0 0 1.25rem;
	font-size: 1.35rem;
	font-weight: 700;
	letter-spacing: -0.01em;
}
.russian-band__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin: 1.75rem 0 0;
}
/* A page whose first block is a band already opens with the page title; the
 * band then needs no top padding of its own. */
body.page main > .wp-block-post-content > .russian-band:first-child { padding-block-start: 0.5rem; }

/* ------------------------------------------------------ Reduced motion. */
@media (prefers-reduced-motion: reduce) {
	:where(a, button),
	.wp-element-button,
	.russian-whatsapp,
	.russian-tile,
	.russian-section-link,
	.russian-section-link::after {
		transition: none;
	}
	.wp-element-button:active { transform: none; }
	.wp-element-button:hover:not(:disabled) { transform: none; }
	.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item { animation: none; }
}

/* --------------------------------------------- Cooperative map gestures. */
/* Hint overlay built by assets/js/map-gestures.js inside every Leaflet
 * container. Pointer-transparent so it can never eat a marker tap; z 1040
 * clears Leaflet's controls (1000) and stays under the finder's pin sheet
 * (1100), all inside each map's own sealed stacking context. */
.russian-map-hint {
	position: absolute;
	inset: 0;
	z-index: 1040;
	display: grid;
	place-items: center;
	padding: 1rem;
	background: rgba(11, 11, 13, 0.55);
	color: #fff;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.95rem;
	font-weight: 600;
	text-align: center;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.25s ease;
}
.russian-map-hint.is-visible { opacity: 1; }

/* Leaflet chrome on a dark map: the zoom control and the attribution. The
 * tiles themselves take --russian-map-filter from inc/functions/map-tiles.php. */
.leaflet-container { background: var(--wp--preset--color--grafito); font-family: var(--wp--preset--font-family--sans); }
.leaflet-bar { border: 1px solid var(--wp--preset--color--linea) !important; box-shadow: var(--russian-shadow-sm) !important; }
.leaflet-bar a {
	background: var(--wp--preset--color--carbon) !important;
	color: var(--wp--preset--color--blanco) !important;
	border-bottom-color: var(--wp--preset--color--linea) !important;
}
.leaflet-bar a:hover { background: var(--wp--preset--color--grafito) !important; }
.leaflet-bar a.leaflet-disabled { color: var(--wp--preset--color--humo) !important; }
.leaflet-control-attribution {
	background: rgba(11, 11, 13, 0.7) !important;
	color: var(--wp--preset--color--humo) !important;
	font-size: 10px;
}
.leaflet-control-attribution a { color: var(--wp--preset--color--blanco) !important; }
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
	background: var(--wp--preset--color--carbon) !important;
	color: var(--wp--preset--color--blanco) !important;
	box-shadow: var(--russian-shadow-md) !important;
}
.leaflet-popup-content-wrapper { border: 1px solid var(--wp--preset--color--linea); border-radius: var(--russian-radius-sm) !important; }
.leaflet-container a.leaflet-popup-close-button { color: var(--wp--preset--color--humo) !important; }

/* Fullscreen finder map: lock the page behind the overlay. :has() keeps the
 * lock symmetric with the state class by construction — no JS cleanup. */
html:has(.russian-finder.is-fullscreen) { overflow: hidden; }
html:has(.russian-finder.is-fullscreen) body { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
	.russian-map-hint { transition: none; }
}

/* ------------------------------------------------------- Scroll reveal.
 * Ported from the hiplaces theme, whose motion this borrows deliberately.
 * assets/js/reveal.js adds .is-inview when a target crosses into view and
 * staggers siblings with an inline transition-delay; this file owns the two
 * states and nothing else.
 *
 * DOUBLE-GATED, and both gates are load-bearing:
 *   html.js   — written in the head by russian_chrome_js_class(), with a
 *               watchdog that takes it back off if reveal.js never arrives.
 *               Without JS the page renders finished, with no hidden state.
 *   no-preference — a visitor who asked for less motion gets the final layout
 *               and zero transitions, which is the whole of SC 2.3.3 here.
 *
 * Only opacity and transform animate. Nothing in this section moves layout, so
 * a reveal can never reflow the page under a reader, and every target is
 * composited rather than repainted. 1s on the theme's own ease: the client
 * watched 0.7s and asked for the slower feel. */
:root {
	--russian-reveal-duration: 1s;
	--russian-reveal-ease: var(--wp--custom--ease);
	/* Openings travel less than bodies: a heading that slides as far as the
	 * card under it arrives second and reads as the slower of the two. */
	--russian-reveal-rise: 20px;
	--russian-reveal-rise-body: 28px;
	/* The one lateral entrance: the zone cover flies in from the left while
	 * the index rows beside it rise one by one. */
	--russian-reveal-slide: 72px;
}

/* The zone band runs slower than the site's 1s: a sideways flight needs more
 * time than a rise to be read as a flight. Scoped here, not changed globally. */
.russian-zone-cards {
	--russian-reveal-duration: 1.4s;
}

@media (prefers-reduced-motion: no-preference) {
	/* :where() so the whole target list contributes NOTHING to specificity and
	 * the two rules below stay at html.js alone — (0,1,1) — while the reveal
	 * sits at (0,2,1) and wins on one class. Written flat, the longest hidden
	 * selector here reaches (0,3,1) and .is-inview loses to its own initial
	 * state. Keep this list and REVEAL_SELECTORS in reveal.js in step. */
	html.js :where(
		.russian-section__stack > .wp-block-heading,
		.russian-section__stack > .russian-section__head,
		.russian-section__head--center,
		.russian-mapband__list > .russian-section__head,
		.wp-block-post-title,
		.russian-page-lead,
		.wp-block-query-title,
		body.archive main > h1.wp-block-heading,
		.entry-content > .wp-block-group > .wp-block-heading,
		.russian-featured__grid[data-russian-carousel] .russian-featured__slide:not(.slick-cloned) > .russian-card,
		.russian-featured__grid:not([data-russian-carousel]) > *,
		.russian-mapband__panel,
		.russian-mapband__grid > .russian-mapband__slot,
		.russian-tile,
		.russian-zonas > .russian-zona--feature,
		.russian-zonas > .russian-zona__rows > li,
		.russian-cta-band .russian-section__stack > p,
		.russian-cta-band__actions,
		.russian-about__mast,
		.russian-about__grid > *,
		.russian-band__grid > *,
		.russian-team__grid > .russian-team__card,
		.russian-footer__cols > *,
		/* The flat pages' bodies: each prose BLOCK is a unit — a paragraph, a
		 * pull-quote, a figure, one numbered step, one FAQ item, the contact
		 * card, the hours table — never a line. They share their group with
		 * the heading above them, so the sibling stagger cascades the page in. */
		.entry-content > .wp-block-group > p,
		.entry-content > .wp-block-group > .wp-block-pullquote,
		.entry-content > .wp-block-group > .russian-agent-portrait,
		.entry-content > .wp-block-group > .russian-steps > li,
		.russian-faq__item,
		.russian-contact-card,
		.russian-hours,
		.wp-block-russian-business-map
	) {
		opacity: 0;
		transform: translateY(var(--russian-reveal-rise));
		transition:
			opacity var(--russian-reveal-duration) var(--russian-reveal-ease),
			transform var(--russian-reveal-duration) var(--russian-reveal-ease);
	}

	/* Bodies travel further than the opening above them. Same (0,1,1), so this
	 * wins over the rise above by source order alone. */
	html.js :where(
		.russian-featured__grid[data-russian-carousel] .russian-featured__slide:not(.slick-cloned) > .russian-card,
		.russian-featured__grid:not([data-russian-carousel]) > *,
		.russian-mapband__panel,
		.russian-mapband__grid > .russian-mapband__slot,
		.russian-tile,
		.russian-zonas > .russian-zona__rows > li,
		.russian-about__grid > *,
		.russian-band__grid > *,
		.russian-team__grid > .russian-team__card,
		.russian-footer__cols > *,
		.entry-content > .wp-block-group > p,
		.entry-content > .wp-block-group > .wp-block-pullquote,
		.entry-content > .wp-block-group > .russian-agent-portrait,
		.entry-content > .wp-block-group > .russian-steps > li,
		.russian-faq__item,
		.russian-contact-card,
		.russian-hours
	) {
		transform: translateY(var(--russian-reveal-rise-body));
	}

	/* The contact page's map only fades: Leaflet measures the container to
	 * turn a drag into a pan, and a transform on it during the first second
	 * would throw that off for a visitor who grabs the map at once. */
	html.js :where(.wp-block-russian-business-map) {
		transform: none;
	}

	/* The zone cover comes from the left. Same (0,1,1) as the two rules above,
	 * so source order is what makes this one win for the cover alone. */
	html.js :where(.russian-zonas > .russian-zona--feature) {
		transform: translateX(calc(var(--russian-reveal-slide) * -1));
	}

	/* The closing cta-band converges: the heading comes from the left, the
	 * line under it from the right, and the button only fades — three
	 * elements, three different entrances, so the band reads as assembling
	 * rather than rising. The actions row is a <p> too, hence the :not(). */
	html.js :where(.russian-cta-band .russian-section__stack > .wp-block-heading) {
		transform: translateX(calc(var(--russian-reveal-slide) * -1));
	}
	html.js :where(.russian-cta-band .russian-section__stack > p:not(.russian-cta-band__actions)) {
		transform: translateX(var(--russian-reveal-slide));
	}
	html.js :where(.russian-cta-band__actions) {
		transform: none;
		/* ...and only once the heading and the line have landed: 1s is the
		 * subtitle's 100ms stagger plus its flight, read by reveal.js in place
		 * of the sibling stagger. */
		--russian-reveal-delay: 1s;
	}

	/* The band's red mark grows from its own centre, very slowly, and does NOT
	 * ride in with the heading. It is the heading's ::before, so while the
	 * heading sits 72px to the left the mark is translated 72px to the right
	 * — net zero, it stays put — and both go to 0 on the same curve. The
	 * growth uses the separate `scale` property so it can run on its own 2.4s
	 * clock while `translate` keeps the heading's 1s. */
	html.js .russian-cta-band .russian-section__stack > .wp-block-heading::before {
		translate: var(--russian-reveal-slide) 0;
		scale: 0 1;
		transform-origin: center;
		transition:
			translate var(--russian-reveal-duration) var(--russian-reveal-ease),
			scale 2.4s var(--russian-reveal-ease);
	}
	html.js .russian-cta-band .russian-section__stack > .wp-block-heading.is-inview::before {
		translate: 0 0;
		scale: 1 1;
	}

	/* The index rows carry a shadow under their type while in flight and set
	 * it down as they land — the one place the reveal paints something other
	 * than opacity and transform. A zero shadow, not `none`: `none` does not
	 * interpolate. */
	html.js :where(.russian-zonas > .russian-zona__rows > li) {
		text-shadow: 0 12px 16px rgba(0, 0, 0, 0.5);
	}
	html.js .russian-zona__rows > li.is-inview {
		text-shadow: 0 0 0 rgba(0, 0, 0, 0);
	}

	html.js .is-inview {
		opacity: 1;
		transform: none;
	}

	/* While a target is revealing, the reveal's transition is the one that
	 * runs — whatever the block declared for its own hover. The transition
	 * that governs a change is the one on the DESTINATION state, and a block
	 * that scopes its rules under its root class reaches (0,2,0), over the
	 * hidden state's (0,1,1). (0,3,1) here outranks any block. reveal.js adds
	 * the class with .is-inview and drops it on transitionend. */
	html.js .is-inview.is-revealing {
		transition:
			opacity var(--russian-reveal-duration) var(--russian-reveal-ease),
			transform var(--russian-reveal-duration) var(--russian-reveal-ease),
			text-shadow var(--russian-reveal-duration) var(--russian-reveal-ease);
	}
}

/* ------------------------------------------------------------------ Print.
 * The ficha's "Imprimir ficha" button (russian/property-price, its view.js)
 * calls window.print(); this is the sheet it gets. Paper is white, so the
 * palette is redefined ON BODY for paper — a custom property set there
 * outranks the :root presets for everything inside it, and every carbón card
 * becomes a hairline box without a rule of its own. The chrome goes (nav,
 * social links, footer, the WhatsApp float, the backdrop glows), and so does
 * everything that only works on a screen: the lightbox, the video, the
 * Leaflet map, the carousel the DB copy of the template appends, and the
 * buttons — the print button included. The contact band goes too, and the
 * CTA row with it: .russian-price__print-contact (name, phone, email, the
 * property's URL) is the one contact line the sheet carries, under the price
 * where the CTA sat. What stays: the logo, title, badge, price, address,
 * photos, the facts with their words, amenities, description.
 *
 * `!important` on the hide list only: those blocks set their own display at
 * specificities and in a stylesheet order this file cannot see, and a print
 * sheet that lets one of them through prints a map tile over the description.
 *
 * The scroll reveal is the trap: a target that never crossed the viewport is
 * still at opacity 0, and the print engine does not scroll. (0,1,2) here
 * outranks both reveal states' (0,1,1). */
@media print {
	@page { margin: 14mm; }

	:root { color-scheme: light; }
	html { background: #fff; }
	body {
		min-height: 0;
		background: #fff;
		color: #000;
		-webkit-font-smoothing: auto;
		--wp--preset--color--noche: #fff;
		--wp--preset--color--carbon: #fff;
		--wp--preset--color--grafito: #f2f2f2;
		--wp--preset--color--linea: #bdbdbd;
		--wp--preset--color--blanco: #000;
		--wp--preset--color--humo: #444;
		--wp--preset--color--rojo-claro: var(--wp--preset--color--rojo);
		--russian-card-highlight: none;
		--russian-accent-glow: none;
	}
	.wp-site-blocks { display: block; min-height: 0; }
	main a { color: inherit; }

	html.js body * {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.russian-backdrop,
	footer.wp-block-template-part,
	.russian-whatsapp,
	.russian-backlink,
	.russian-site-header__bar > :not(.russian-logo),
	.russian-price__actions,
	.russian-price--band,
	.russian-video,
	.russian-ficha-location,
	.russian-featured,
	.russian-gallery__lightbox { display: none !important; }

	/* The header shrinks to the logo. The mark is drawn for the dark bar, so
	 * it is inverted for paper; grayscale first, so a client logo with colour
	 * in it comes out dark rather than in its complementary. */
	header.wp-block-template-part { position: static; }
	.russian-site-header { background: none; box-shadow: none; }
	.russian-logo__mark { filter: grayscale(1) invert(1); }

	/* The badge on paper: the pill outlined in ink, whichever operation. */
	.russian-price .russian-price__badge {
		background: transparent;
		border-color: #000;
		color: #000;
	}
	.russian-price .russian-price__print-contact {
		display: block;
		flex-basis: 100%;
		margin: 0.75rem 0 0;
		padding-top: 0.6rem;
		border-top: 1px solid #bdbdbd;
		font-size: 0.8125rem;
		line-height: 1.5;
		color: #444;
		overflow-wrap: anywhere;
	}

	.wp-block-post-title { break-after: avoid; }
	/* Never the gallery as a whole: at paper width it runs taller than a page
	 * and an `avoid` on it shoved the entire grid onto page 2, leaving page 1
	 * empty under the price. Rows may break; a photo may not. */
	.russian-gallery__item,
	.russian-features__facts,
	.russian-features__facts > div { break-inside: avoid; }
	.russian-gallery__item { box-shadow: 0 0 0 1px #bdbdbd; }
}
