/*
 * FULFIT — общие стили: шапка, подвал, hero-сетка, формы, слайдеры, reveal
 *
 * Часть разделённого main.css (был 11103 строки, 79% из них не
 * использовались на конкретной странице). Файл собран из целых секций
 * исходника БЕЗ изменения их порядка и содержимого.
 *
 * Подключается: на всех страницах
 * Правится вручную, как обычный CSS. Общие для всех страниц стили —
 * в main-core.css; секции ищите по прежним баннерам-комментариям.
 */

/*
 * FULFIT — layout/component styles for header, footer and the top
 * homepage sections (hero, partner strip).
 *
 * Fluid sizing: most type/spacing values use clamp() interpolated between
 * the mobile reference (Figma 360px frame) and the desktop reference
 * (Figma 1920px frame); values are frozen below 360px and above 1920px.
 * Colors/font-families/container widths reference tokens declared in
 * theme.json (CSS custom properties WordPress exposes automatically).
 */

/* =======================================================================
   АДАПТИВНЫЙ БОКОВОЙ ГУТТЕР (--ff-gutter)
   Заказчик прислал скрин с планшета: на ширинах примерно 768-1200px
   контент упирается в края экрана — боковое поле застряло на мобильных
   16px (верных для <=640px) и "перепрыгивает" сразу к десктопным
   значениям только после ~1266px, за счёт центрирования 1170px-колонки.
   Между ними — провал, где полей практически нет.

   --ff-gutter плавно интерполирует между двумя опорными точками:
   640px -> 16px (мобильный макет, менять нельзя) и 1200px -> 48px
   (дальше поле продолжает визуально расти само — за счёт центрирования
   max-width:1170px колонки, а не за счёт роста этой переменной).
   5.714vw = (48-16)/(1200-640)*100; -20.57px — сдвиг прямой, чтобы она
   проходила ровно через (640px, 16px). Контрольные точки формулы:
   <=640 -> 16px (без изменений), 768 -> ~23px, 1024 -> ~38px,
   1180 -> ~47px, >=1200 -> 48px (потолок).
   ------------------------------------------------------------------- */
:root {
	--ff-gutter: clamp(16px, 5.714vw - 20.57px, 48px);
}

/* Применение --ff-gutter к каждой секции зависит от того, как WordPress
   считает её собственную ширину:
     - align:full/align:wide секции (шапка/футер/hero/.ff-services и
       т.п.) сами тянутся во весь экран, а их 1170px/1595px-колонка
       живёт ОТДЕЛЬНО — либо на явном дочернем .xxx__inner с
       max-width, либо на дочерних элементах автоматически (WordPress
       ставит max-width:contentSize + margin-inline:auto любому
       "неалайненному" прямому потомку constrained-контейнера). Для них
       padding-inline: var(--ff-gutter) на самой секции достаточен: как
       только колонка упирается в свой max-width, паддинг на видимую
       ширину колонки уже не влияет (её позицию держит margin:auto) —
       посчитано и проверено вживую, значение на 1920 не сдвигается ни
       на px независимо от паддинга.
     - секции БЕЗ align (.ff-promise, .ff-steps, .ff-calc и т.д.) сами
       являются тем самым "неалайненным потомком" — WordPress уже
       навешивает им max-width:1170px напрямую. Тогда padding-inline
       живёт УЖЕ ВНУТРИ этой готовой 1170px-рамки и просто выгрызает
       из неё контент (сейчас так и есть: секция 1170px - 16px паддинг
       с каждой стороны = 1138px контента — небольшой, но принятый
       заказчиком дефицит относительно "чистых" 1170px, см. комментарий
       у .ff-lead-banner__card). Просто заменить 16px на --ff-gutter
       тут нельзя — на 1920px паддинг вырастет до 48px и контент
       ужмётся с 1138 до 1074px, а это уже регресс на принятом макете.
       Лечится тем, что max-width секции растёт в ЛОКСТЕПЕ с паддингом
       на ту же дельту (max-width: calc(1170px + (var(--ff-gutter) -
       16px) * 2)), так что контент внутри остаётся ровно 1138px при
       любой ширине паддинга — а видимое поле при этом всё равно растёт
       по той же кривой, что и у align:full-секций (математически то
       же самое: пока эта расширенная max-width ещё не уперлась в саму
       ширину экрана, секция остаётся "во всю ширину минус паддинг" —
       ровно то поведение, которое нужно в проблемном диапазоне
       768-1200px). У секций, где на десктопе паддинга вообще не было
       (0, не 16px — .ff-mp-section и её лендинговые тёзки, .ff-generator,
       .ff-bctypes, .ff-history, .ff-process), та же формула без
       вычитания 16px: max-width: calc(1170px + var(--ff-gutter) * 2).
       .ff-categories — особый случай: у неё уже есть своё правило
       "padding-inline: 0" от 1170px и выше (ради ровных 270px карточек
       в сетке), поэтому дефицит для неё и так нулевой — локстеп с
       max-width ей не нужен, меняется только базовое значение паддинга. */

/* Секции без align И без собственного паддинга на десктопе (текущий
   дефицит = 0, см. общий комментарий выше): .ff-generator/.ff-bctypes
   (страница "Маркировка"), .ff-history ("О нас"), .ff-process
   ("Интернет-магазины"). Мобильный гуттер у них держат дочерние
   элементы своими правилами (напр. .ff-history__timeline ниже) —
   специально ограничиваем это правило шириной >=641px, чтобы не
   задвоить их мобильный отступ поверх уже существующего.
   :not(.alignfull) на max-width — см. идентичную правку у .ff-steps
   дальше по файлу (её комментарий): без неё секция, вдруг сохранённая
   на какой-то странице как align:full, осталась бы без auto-
   центрирования от WordPress и прижалась к левому краю. */
@media (min-width: 641px) {
	.ff-generator,
	.ff-bctypes,
	.ff-history,
	.ff-process {
		padding-inline: var(--ff-gutter);
	}
	.ff-generator:not(.alignfull),
	.ff-bctypes:not(.alignfull),
	.ff-history:not(.alignfull),
	.ff-process:not(.alignfull) {
		max-width: calc(1170px + var(--ff-gutter) * 2);
	}
}

/* ---------------------------------------------------------------------
   Every custom flex/grid container below (stage-2 sections) is authored
   as a plain wp:group with no "layout" attribute, so core treats it as
   layout type "flow" and injects its own blockGap spacing: a "lobotomized
   owl" rule that adds margin-block-start to every child but the first
   (wp-includes/block-supports/layout.php). That fights our own
   gap/row-gap/column-gap on the same element — visibly so wherever a grid
   row's items have different content heights, since align-items:start
   then leaves the extra margin-pushed items sitting lower than their
   un-pushed first-of-row sibling. Zero it out (needs !important: core's
   rule has no author-facing attribute to turn off and ties on
   specificity) and let our own gap properties be the only spacing.
   ------------------------------------------------------------------- */
.ff-promise__row > *,
.ff-promise__col > *,
.ff-promise__bullets > *,
.ff-promise__bullet > *,
.ff-services__grid > *,
.ff-services__card > *,
.ff-services__card-body > *,
.ff-services__cta > *,
.ff-steps__timeline > *,
.ff-steps__step > *,
.ff-steps__content > *,
.ff-categories__grid > *,
.ff-categories__card-body > *,
.ff-lead-banner__card > *,
.ff-advantages__grid > *,
.ff-advantages__card > *,
.ff-advantages__card-icon-zone > *,
.ff-advantages__card-body > *,
.ff-mp-adv-grid > *,
.ff-mp-adv-card > *,
.ff-mp-adv-card__icon > *,
.ff-mp-adv-card__body > *,
.ff-staff__row > *,
.ff-staff__badge > *,
.ff-shipping__row > *,
.ff-shipping__text > *,
.ff-shipping__block > *,
.ff-shipping__block-head > *,
.ff-marquee__group > *,
.ff-marquee__track > *,
.ff-calc__card > *,
.ff-faq__list > *,
.ff-faq__item > *,
.ff-news__head > *,
.ff-news__grid > *,
.ff-news__card > *,
.ff-news__card-body > *,
.ff-news__teaser > *,
.ff-news__teaser-body > *,
.ff-news__teaser-text > *,
.ff-blog > * {
	margin-block-start: 0 !important;
	margin-block-end: 0 !important;
}

/* Shared motion language for every native and block-theme interactive
   control. Component-specific transitions below keep precedence because
   :where() contributes zero specificity. */
@media (prefers-reduced-motion: no-preference) {
	:where(
		a,
		button,
		input,
		select,
		textarea,
		summary,
		[role="button"],
		.wp-element-button
	) {
		transition-property:
			color,
			background-color,
			border-color,
			box-shadow,
			opacity,
			filter,
			transform,
			text-decoration-color,
			text-underline-offset;
		transition-duration: 220ms;
		transition-timing-function: ease;
	}

	:where(a):hover {
		text-underline-offset: 0.18em;
	}
}

/* ---------------------------------------------------------------------
   Mobile section rhythm: normalize the vertical gap between every
   top-level homepage section to a flat 50px below 640px, matching the
   mobile Figma frame (full.json 100:176) — every adjacent top-level
   frame pair there sits exactly 50px apart (next.y - (prev.y +
   prev.height) === 50 for all 12 seams from hero down to footer,
   including the advantages/staff pair, whose 50px lives inside their
   shared #F6F5FC background rect 133:1982, not as a white margin).

   Two things stack up to break that rhythm at every un-fixed seam (the
   .ff-shipping + .ff-faq rule further down was the first fix of this
   kind — see its own comment for the full mechanics):
     1. Every top-level section here sits on WordPress's default
        is-layout-constrained block-gap support, which injects a rogue
        24px margin-block-start on every section but the first (core's
        :where(.is-layout-flow) > * + * rule — the "lobotomized owl"
        documented at the very top of this file, just at the
        root/section level instead of inside a block).
     2. Each section also carries its own ~40px fluid padding-top/
        padding-bottom (50px for the lavender-panel sections, ~24px for
        the slimmer .ff-partners/.ff-lead-banner), meant to sit
        *between* that section's own edge and its heading/content.

   Where both sides of a seam are plain white (or transparent, showing
   the white page bg through), a reader sees ALL of that stacked —
   e.g. calc -> promise piles up 40 (calc's own bottom padding) + 24
   (rogue margin) + 40 (promise's own top padding) = 104px, over twice
   the intended 50px. Where one side of the seam owns a fill instead
   (hero/services/advantages/staff/footer — solid or near-solid
   background, not white), that side's padding is part of its visible
   block rather than part of the gap, so only one side's padding piles
   on top of the rogue margin — e.g. hero -> partners stacks
   24 + 40 = 64px. Either way the rhythm reads as jagged while
   scrolling: some seams ~50px, others ~64-104px.

   Fix per seam, adjacent-sibling selector so only that one handoff
   moves (every section keeps its base padding for its OTHER neighbor,
   and this whole block is capped at 640px so desktop never sees it):
     - Cancel the rogue margin-top (set to 0).
     - Re-target the *lower* section's padding-top with a flat px value
       (not clamped — mirrors the existing FAQ fix) so padding-top
       (lower) + [upper section's own bottom padding, only counted when
       upper is plain/white] lands on 50px.
     - Where the lower section itself owns the fill (services,
       advantages -> staff, footer), padding-top can't move the visible
       seam — margin-top is the only lever there, so it's tuned to a
       small positive value instead of cancelled.
   Two seams need no change: lead-banner -> advantages already lands
   at ~48px (within the ±4px tolerance), and shipping -> faq was
   already fixed (see below). */
@media (max-width: 640px) {
	.ff-hero + .ff-partners {
		margin-top: 0;
		padding-top: 50px;
	}

	.ff-partners + .ff-calc {
		margin-top: 0;
		padding-top: 26px;
	}

	.ff-calc + .ff-promise {
		margin-top: 0;
		padding-top: 10px;
	}

	.ff-promise + .ff-services {
		margin-top: 10px;
	}

	.ff-services + .ff-steps {
		margin-top: 0;
		padding-top: 50px;
	}

	.ff-steps + .ff-categories {
		margin-top: 0;
		padding-top: 10px;
	}

	.ff-categories + .ff-lead-banner {
		margin-top: 0;
		padding-top: 10px;
	}

	/* .ff-staff's margin-top is already 0 in its own base rule (this file,
	   page-wide) so the shared #F6F5FC panel never gets a white seam — this
	   only dials back the internal padding so the two content clusters
	   (advantages grid, staff badges) land 50px apart instead of 80px. */
	.ff-advantages + .ff-staff {
		padding-top: 10px;
	}

	.ff-staff + .ff-shipping {
		margin-top: 0;
		padding-top: 50px;
	}

	.ff-faq + .ff-news {
		margin-top: 0;
		padding-top: 10px;
	}

	/* .ff-footer is a template part, not a DOM sibling of .ff-news — it
	   renders as <footer class="wp-block-template-part"><footer
	   class="ff-footer">...</footer></footer> directly under
	   .wp-site-blocks, so no adjacent-sibling selector reaches it. The
	   outer wp-block-template-part wrapper carries its own rogue 24px
	   owl margin-top (same mechanism, applied one level up between
	   <main> and <footer> as flow siblings of .wp-site-blocks) — that's
	   the one actually setting the gap; a margin-top on .ff-footer
	   itself collapses straight into it (parent-child margin collapse:
	   the wrapper has no padding/border of its own to block it), so
	   target the wrapper directly instead. */
	footer.wp-block-template-part {
		margin-top: 10px;
	}
}

/* =======================================================================
   YANDEX REVIEWS — server-inserted before the first root .ff-faq block.
   ======================================================================= */
.ff-reviews {
	width: min(1170px, calc(100% - 2 * var(--ff-gutter)));
	margin: 70px auto 0 !important;
	text-align: center;
}
.ff-reviews__title {
	margin: 0 0 30px;
	color: var(--wp--preset--color--ink);
	font: 600 40px/48px Inter, sans-serif;
}
.ff-reviews__frame {
	position: relative;
	width: min(100%, 560px);
	margin-inline: auto;
	overflow: hidden;
	border-radius: 8px;
}
.ff-reviews__frame iframe {
	display: block;
	width: 100%;
	height: 800px;
	box-sizing: border-box;
	border: 1px solid #e6e6e6;
	border-radius: 8px;
}
.ff-reviews__attribution { position: absolute; right: 8px; bottom: 8px; left: 8px; z-index: 1; overflow: hidden; color: #b3b3b3; font: 11px/14px Arial, Helvetica, sans-serif; text-align: center; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; }
.ff-reviews.ff-anim-ready { opacity: 0; transform: translateY(22px); transition: opacity .7s var(--ff-rv-ease), transform .7s var(--ff-rv-ease); }
.ff-reviews.ff-anim-ready.is-visible { opacity: 1; transform: none; }
@media (max-width: 640px) {
	.ff-reviews { width: min(328px, calc(100% - 32px)); margin-top: 50px !important; }
	.ff-reviews__title { margin-bottom: 20px; font-size: 28px; line-height: 30px; }
	.ff-reviews__frame { border-radius: 12px; }
	.ff-reviews__frame iframe { height: 660px; }

	/* .ff-reviews is inserted immediately before the first root .ff-faq
	   group on EVERY front-end page that has one (see render_block filter
	   in inc/reviews-widget.php) — so it always displaces whatever section
	   used to sit right before .ff-faq, breaking every adjacency selector
	   tuned for that old neighbor (e.g. ".ff-shipping + .ff-faq" above no
	   longer matches on the front page). With nothing re-targeting the new
	   seam, .ff-faq falls back to the core owl margin-top:24px (not the
	   engineered 50px rhythm) AND its own base padding-top (~40px at this
	   width, clamp in the FAQ block further down) goes uncancelled too —
	   live measurement (front page, resting state, transitions disabled
	   before reading getBoundingClientRect): box-edge gap 24px, ~64px to
	   the actual "Частые вопросы" heading. Re-target the seam directly so
	   it's correct regardless of page/template: margin-top alone would
	   satisfy the 50px box-edge measurement but *increase* the real visual
	   gap to ~90px (50 + FAQ's own uncancelled ~40px padding-top) — worse
	   than the 64px it replaces — so padding-top needs zeroing too, same
	   as .page-template-page-marketplace already does for this section
	   (see MARKETPLACE OVERRIDES below), just driven from margin alone.
	   !important: matches this same specificity (0,2,0) that
	   .page-template-page-marketplace .ff-faq / .page-id-13 .ff-faq /
	   .page-id-15 .ff-faq carry further down the file — without it,
	   whichever rule is later in source wins the tie by accident of
	   ordering rather than by design. */
	.ff-reviews + .ff-faq {
		margin-top: 50px !important;
		padding-top: 0 !important;
	}
}

/* ---------------------------------------------------------------------
   Деск-ритм главной: видимые зазоры между секциями = 100px (как в макете).
   Каждая пара сейчас даёт РАЗНЫЙ зазор (owl 24px + сумма соседних pt/pb —
   у "воздушных" (белых) секций эта сумма считается видимой, у "заливных"
   в зазор входит только их владенная кромка, см. методику в шапке файла).
   Правило — margin-top ВТОРОЙ секции пары: он полностью ЗАМЕЩАЕТ (не
   складывается с) owl-margin на том же элементе (наш селектор специфичнее
   и приходит позже), поэтому значение подобрано так, чтобы (это же
   margin-top) + (сумма соседних pt/pb, уже включающая owl) - 24 = 100;
   допустимы отрицательные значения. Стык .ff-advantages -> .ff-staff НЕ
   трогаем (общая фоновая зона, margin-top:0 уже стоит намеренно, см. его
   комментарий выше). Скоуп .page-id-6, чтобы .ff-steps/.ff-faq/.ff-news
   (общие с WB классы) не задевали /wildberries/; @media строго
   min-width:641px — мобильный ритм (max-width:640px, выше) не трогаем.
   ------------------------------------------------------------------- */
@media (min-width: 641px) {
	.page-id-6 .ff-hero + .ff-partners { margin-top: 30px; }
	.page-id-6 .ff-partners + .ff-calc { margin-top: -17px; }
	.page-id-6 .ff-calc + .ff-promise { margin-top: -40px; }
	.page-id-6 .ff-promise + .ff-services { margin-top: 30px; }
	.page-id-6 .ff-services + .ff-steps { margin-top: 30px; }
	.page-id-6 .ff-steps + .ff-categories { margin-top: -40px; }
	.page-id-6 .ff-categories + .ff-lead-banner { margin-top: -10px; }
	.page-id-6 .ff-lead-banner + .ff-advantages { margin-top: 60px; }
	.page-id-6 .ff-staff + .ff-shipping { margin-top: 30px; }
	.page-id-6 .ff-shipping + .ff-faq { margin-top: -40px; }
	.page-id-6 .ff-faq + .ff-news { margin-top: -40px; }
	/* footer — не DOM-сосед .ff-news (см. комментарий в моб.-блоке выше),
	   таргетим wrapper напрямую; .page-id-6 держит его от прочих страниц. */
	.page-id-6 footer.wp-block-template-part { margin-top: 30px; }
}

/* ---------------------------------------------------------------------
   Shared: pill CTA button (header "Оставить заявку" / hero "Рассчитать
   стоимость") — gradient pill with a white circle + arrow-up-right icon.
   ------------------------------------------------------------------- */

.ff-btn-pill .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 16px;
	background: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 600;
	font-size: clamp(0.9375rem, 0.9231rem + 0.0641vw, 1rem);
	line-height: 1.21;
	border-radius: 999px;
	padding: 8px 8px 8px clamp(20px, 1.25rem + 1vw, 42px);
	text-decoration: none;
	white-space: nowrap;
}

.ff-btn-pill .wp-block-button__link::after {
	content: "";
	flex: 0 0 auto;
	width: clamp(34px, 2rem + 0.4vw, 42px);
	height: clamp(34px, 2rem + 0.4vw, 42px);
	border-radius: 50%;
	background-color: var(--wp--preset--color--white);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23854BFB' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='7' y1='17' x2='17' y2='7'/%3E%3Cpolyline points='7 7 17 7 17 17'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 45%;
}

.ff-btn-pill .wp-block-button__link:hover,
.ff-btn-pill .wp-block-button__link:focus {
	color: var(--wp--preset--color--white);
	filter: brightness(1.05);
}

/* =======================================================================
   HEADER
   ======================================================================= */

.ff-header {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(16px, 0.7rem + 1vw, 30px);
	padding-bottom: clamp(16px, 0.7rem + 1vw, 30px);
	padding-inline: var(--ff-gutter);
}

.ff-header__inner {
	width: 100%;
	max-width: 1170px;
	margin-inline: auto;
	align-items: center;
	gap: clamp(16px, 1rem + 2vw, 60px);
}

.ff-header__logo img {
	display: block;
	height: clamp(22px, 1.2rem + 1vw, 31px);
	width: auto;
}

/* Primary nav links */
.ff-header__nav {
	font-family: var(--wp--preset--font-family--inter);
	color: var(--wp--preset--color--navy);
}

/* The trailing .wp-block-navigation-item__content.wp-block-navigation-item__content
   doubling matches core's own specificity-boosted `color:inherit` reset in
   wp-block-navigation-inline-css (0,3,0) — a plain single-ancestor selector
   here would silently lose that fight and fall back to the global text color. */
.ff-header__nav .wp-block-navigation-item__content.wp-block-navigation-item__content {
	font-size: clamp(0.9375rem, 0.9231rem + 0.0641vw, 1rem);
	font-weight: 500;
	color: var(--wp--preset--color--navy);
	padding: 0;
}

.ff-header__nav .wp-block-navigation-item {
	margin-inline-end: clamp(20px, 1rem + 2vw, 40px);
}

.ff-header__nav .wp-block-navigation-item:last-child {
	margin-inline-end: 0;
}

.ff-header__nav .wp-block-navigation__submenu-icon svg {
	width: 12px;
	height: 12px;
}

.ff-header__nav .wp-block-navigation-submenu__toggle {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}

/* Dropdown panel */
.ff-header__nav .wp-block-navigation__submenu-container {
	background: var(--wp--preset--color--white);
	border-radius: 16px;
	padding: 10px;
	box-shadow: 0 16px 40px rgba(26, 26, 46, 0.14);
	min-width: 260px;
	border: none;
}

.ff-header__nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	padding: 10px 14px;
	border-radius: 10px;
	white-space: nowrap;
}

.ff-header__nav .wp-block-navigation__submenu-container .wp-block-navigation-item:hover > .wp-block-navigation-item__content {
	background: var(--wp--preset--color--bg-lavender);
	color: var(--wp--preset--color--brand);
}

/* Mobile/tablet Navigation modal.
   The menu remains the native core/navigation dialog (ref 21), so Gutenberg
   still owns its links, focus management, Escape handling and scroll lock.
   Only the presentation is replaced here. */
.ff-header__nav .wp-block-navigation__responsive-container-open {
	box-sizing: border-box;
	width: 40px;
	height: 32px;
	padding: 0;
	border: 0;
	border-radius: 8px;
	background: transparent url("../img/ui/menu.svg") center / 40px 32px no-repeat;
	color: var(--wp--preset--color--navy);
	transition: background-color 0.2s ease, box-shadow 0.2s ease;
}

.ff-header__nav .wp-block-navigation__responsive-container-open svg {
	display: none;
}

.ff-header__nav .wp-block-navigation__responsive-container-open:hover {
	background-color: var(--wp--preset--color--bg-lavender);
}

.ff-header__nav .wp-block-navigation__responsive-container-open:focus-visible,
.ff-header__nav .wp-block-navigation__responsive-container-close:focus-visible {
	outline: 0;
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.24);
}

@media (max-width: 1023px) {
	.ff-header__nav {
		order: 3;
	}

	.ff-header__cta {
		order: 2;
	}

	.ff-header__nav .wp-block-navigation__responsive-container {
		opacity: 0;
		transform: translateY(-8px);
		transition:
			opacity 0.24s ease,
			transform 0.24s ease,
			display 0.24s allow-discrete;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open {
		position: fixed;
		inset: 0;
		z-index: 100000;
		box-sizing: border-box;
		display: flex;
		width: 100%;
		height: 100dvh;
		min-height: 100%;
		padding: 0 16px calc(24px + env(safe-area-inset-bottom));
		overflow: hidden;
		background:
			linear-gradient(180deg, #ffffff 0%, #ffffff 72%, #f6f5fc 100%);
		color: var(--wp--preset--color--navy);
		opacity: 1;
		transform: none;
	}

	@starting-style {
		.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open {
			opacity: 0;
			transform: translateY(-8px);
		}
	}

	/* The core dialog does not duplicate the site logo. A decorative copy of
	   the same media-library asset preserves the Figma header row without
	   adding a second focusable element outside core's focus trap. */
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open::before {
		content: "";
		position: absolute;
		top: 14px;
		left: max(16px, calc((100vw - 704px) / 2));
		width: 156px;
		height: 28px;
		background: url("https://fulfit.ru/wp-content/uploads/2026/07/fulfit-logo.png") left center / contain no-repeat;
		pointer-events: none;
	}

	/* .responsive-container.is-menu-open is display:flex (core sets
	   flex-direction:column on it too), which makes .responsive-close a
	   flex item on the main (vertical) axis. Flex items default to
	   min-height:auto, i.e. never shrink below their content's height —
	   so with 4 top-level links + 9 expanded "Услуги" sub-links taller
	   than the viewport, .responsive-close (and the .responsive-dialog /
	   .responsive-container-content it wraps, both sized off it via
	   height:100%) was growing to full content height instead of being
	   capped at the container's box, leaving nothing for the content
	   pane's own overflow-y:auto below to actually scroll — the overflow
	   was just clipped by the outer container instead. Zeroing the
	   min-height lets it shrink to the available space, which makes the
	   100% heights downstream resolve to a real (scrollable) number. */
	.ff-header__nav .wp-block-navigation__responsive-close {
		min-height: 0;
	}

	.ff-header__nav .wp-block-navigation__responsive-dialog {
		box-sizing: border-box;
		width: min(100%, 704px);
		height: 100%;
		margin: 0 auto;
	}

	.ff-header__nav .wp-block-navigation__responsive-container-close {
		position: absolute;
		top: 7px;
		right: max(16px, calc((100vw - 704px) / 2));
		z-index: 2;
		display: grid;
		place-items: center;
		box-sizing: border-box;
		width: 42px;
		height: 42px;
		padding: 0;
		border: 0;
		border-radius: 13px;
		background: #f2edfd;
		color: var(--wp--preset--color--navy);
		transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
	}

	.ff-header__nav .wp-block-navigation__responsive-container-close:hover {
		background: #e7dffb;
		color: var(--wp--preset--color--brand-deep);
	}

	.ff-header__nav .wp-block-navigation__responsive-container-close svg {
		width: 24px;
		height: 24px;
	}

	.ff-header__nav .wp-block-navigation__responsive-container-content {
		box-sizing: border-box;
		display: flex;
		flex-direction: column;
		align-items: stretch !important;
		justify-content: flex-start;
		width: 100%;
		height: 100%;
		/* Bottom padding also clears the fixed CTA bar (see .ff-header__cta
		   rules below) so the last link can scroll fully into view above it. */
		padding: 82px 0 104px !important;
		/* Core's own style.min.css carries a same-property, higher-specificity
		   rule scoped to `.responsive-container.is-menu-open .responsive-
		   container-content` ((0,3,0), :where() zeroes the :not() it wraps)
		   that sets overflow(-y): visible — it beats this rule's (0,2,0)
		   ancestor+self selector on specificity alone, silently turning this
		   scroll pane back into a clipped, non-scrolling box. !important to win. */
		overflow-x: hidden !important;
		overflow-y: auto !important;
		overscroll-behavior: contain;
		scrollbar-width: thin;
	}

	.ff-header__nav .wp-block-navigation__responsive-container-content > .wp-block-navigation__container {
		display: flex !important;
		flex-direction: column;
		align-items: stretch !important;
		gap: 4px;
		width: 100%;
		margin: 0;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item {
		box-sizing: border-box;
		width: 100%;
		margin: 0;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__container
		> .wp-block-navigation-item
		> a.wp-block-navigation-item__content.wp-block-navigation-item__content {
		box-sizing: border-box;
		width: 100%;
		min-height: 58px;
		padding: 12px 14px;
		border-radius: 15px;
		color: var(--wp--preset--color--navy);
		font-family: var(--wp--preset--font-family--inter);
		font-size: 1.15625rem;
		font-weight: 600;
		line-height: 1.2;
		text-align: left;
		text-decoration: none;
		transition: background-color 0.2s ease, color 0.2s ease;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item__content:hover,
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item__content:focus-visible {
		outline: 0;
		background: var(--wp--preset--color--bg-lavender);
		color: var(--wp--preset--color--brand-deep);
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.current-menu-item
		> .wp-block-navigation-item__content,
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.current-menu-ancestor
		> .wp-block-navigation-submenu__toggle {
		background: #ece8ff;
		color: var(--wp--preset--color--brand-deep);
	}

	/* Hairline divider between top-level rows (Услуги/О нас/Блог/Контакты),
	   inset so it doesn't run edge-to-edge. Absolutely positioned (rather
	   than a border) so the same rule works uniformly on the plain flex
	   <li>s below *and* the has-child <li> two rules down, which is a grid
	   container with its own row tracks — an ::after with no grid-row
	   placement is taken out of grid flow entirely (same mechanism as the
	   overlay toggle button further down) and just pins to the item's own
	   bottom edge. For has-child that edge naturally tracks its animated
	   total height, so the divider lands after the whole Услуги+submenu
	   unit, between top-level items as intended, never around the submenu
	   itself. */
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__container
		> .wp-block-navigation-item:not(:last-child)::after {
		content: "";
		position: absolute;
		left: 14px;
		right: 14px;
		bottom: 0;
		height: 1px;
		background: rgba(28, 22, 51, 0.09);
		pointer-events: none;
	}

	/* "Услуги" accordion ---------------------------------------------
	   The <li class="has-child"> becomes a 2-row grid: row 1 is the
	   always-visible label+toggle line (auto height), row 2 is the
	   collapsible submenu (0fr collapsed / 1fr expanded) — the same
	   0fr/1fr row-track trick as .ff-faq__panel elsewhere in this file,
	   just with both rows living directly on the <li> itself (core gives
	   us the label, the toggle and the submenu as three direct children
	   here, with no wrapper element to hook a dedicated single-track panel
	   onto). Collapsed by default: the toggle button's server-rendered
	   aria-expanded="false" already matches row 2's 0fr, so no extra state
	   is needed to start closed.
	   align-items must be reset to stretch: core's shared
	   `.wp-block-navigation-item{align-items:center}` (meant for the
	   default flex layout) otherwise survives onto this grid container too
	   and centers the submenu instead of stretching it to fill row 2,
	   which defeats the collapse — the item just renders at its natural
	   content height, centered over a 0-height track, instead of actually
	   shrinking to it. */
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child {
		position: relative;
		display: grid !important;
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: auto 0fr;
		align-items: stretch;
		transition: grid-template-rows 0.28s ease;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child:has(
			> .wp-block-navigation-submenu__toggle[aria-expanded="true"]
		) {
		grid-template-rows: auto 1fr;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > a.wp-block-navigation-item__content {
		grid-row: 1;
		grid-column: 1;
		display: flex;
		align-items: center;
		/* Reserves room so the label/badge never runs under the absolutely
		   positioned toggle button (chevron) below. Needs !important: the
		   shared top-level row rule above sets the same padding shorthand
		   at higher specificity (it also matches this <a>). */
		padding-right: 46px !important;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > a.wp-block-navigation-item__content::after {
		content: "9";
		flex: 0 0 auto;
		margin-left: auto;
		font-family: var(--wp--preset--font-family--inter);
		font-size: 12px;
		font-weight: 600;
		color: var(--wp--preset--color--brand);
		background: var(--wp--preset--color--bg-lavender);
		padding: 3px 9px;
		border-radius: 999px;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child:has(
			> .wp-block-navigation-submenu__toggle[aria-expanded="true"]
		) > a.wp-block-navigation-item__content {
		color: #6431c9 !important;
	}

	/* Core hides this button in the mobile dialog by default (it forces
	   every submenu open inline instead — see the old always-open rule
	   this whole section replaces) and our own shared row rule above no
	   longer includes it (it needs a completely different shape here: an
	   invisible header-row-only overlay, not a stacked second 58px row).
	   Stretching this button over the *whole header row* (not just the
	   icon) is what makes "tap anywhere on the Услуги row" toggle the
	   accordion, per the approved design, not only a small chevron hit
	   target: the row's real visible label is the plain <a> underneath,
	   painted first; this button paints above it — z-index is needed
	   because overlapping same-area grid items don't reliably stack by
	   DOM order alone — with a transparent background and only the
	   chevron icon visible, so it intercepts every tap across the header
	   row while the label text and "9" badge show through untouched.
	   Deliberately NOT grid-row/grid-column + inset:0: a grid item whose
	   placement has a definite start but an auto end (which is what plain
	   `grid-row: 1` resolves to) gets an *indefinite* containing-block
	   edge on that side per spec — the auto end doesn't stop at row 1's
	   boundary, it extends to the grid container's far edge. With
	   inset:0 that silently stretched this button down over the *whole*
	   <li>, including the expanded submenu: the chevron (centered via
	   align-items) drifted into the middle of the 9-item list instead of
	   sitting on the header row, and the transparent overlay sat on top
	   of the sublinks and ate their taps as toggle clicks instead of
	   navigation. Plain top/left/right + a fixed height (matching the
	   header row <a>'s min-height above — keep both in sync) sidesteps
	   grid placement for this element entirely: with no definite grid-row
	   its containing block is just the has-child <li>'s own padding box
	   (position:relative, set above), and bottom is left auto so the box
	   never extends past the header row regardless of how tall the
	   submenu grows. */
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation-submenu__toggle {
		display: flex !important;
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: auto;
		height: 58px;
		z-index: 1;
		box-sizing: border-box;
		width: 100%;
		margin: 0;
		padding: 0 14px 0 0;
		align-items: center;
		justify-content: flex-end;
		border: 0;
		border-radius: 15px;
		background: transparent;
		color: var(--wp--preset--color--brand);
		transition: background-color 0.2s ease, color 0.2s ease;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation-submenu__toggle:hover,
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation-submenu__toggle:focus-visible {
		outline: 0;
		background: var(--wp--preset--color--bg-lavender);
		color: var(--wp--preset--color--brand-deep);
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child
		> .wp-block-navigation-submenu__toggle[aria-expanded="true"] {
		background: transparent;
		color: #6431c9;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation-submenu__toggle svg {
		transition: transform 0.26s ease;
	}

	/* Submenu panel: replaces the old "force everything open" rule with a
	   real collapse. display (none <-> flex) is the a11y-safety half of
	   the mechanism — it keeps the 9 links out of the tab order while
	   collapsed — using the same display + allow-discrete pairing already
	   relied on for the whole overlay's own open/close transition higher
	   up in this file, so display only flips to none at the *end* of the
	   collapse (content stays visible/focusable for the full animation)
	   and back to flex immediately on expand. The actual visible height
	   animation is entirely the parent grid's row 2 track (0fr/1fr)
	   above; this element just needs to be able to shrink to fit it —
	   min-height:0 (grid items default to min-height:auto, i.e. never
	   smaller than their content, the same gotcha already documented for
	   the flex .responsive-close case above) plus overflow:hidden to clip
	   the 9 links while row 2 is small.
	   Only *horizontal* box-model properties (margin-left/padding-left/
	   border-left, for the indent + rail) live on this element itself —
	   any vertical margin/padding here would floor row 2's collapsed size
	   above 0 (padding/margin count toward a grid item's automatic
	   minimum size even with min-height:0; only the min-content
	   contribution gets zeroed by overflow:hidden). Vertical breathing
	   room is added to the first/last <li> instead, which is purely
	   content as far as this element's own sizing is concerned. */
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container {
		grid-row: 2;
		grid-column: 1;
		display: none !important;
		flex-direction: column;
		gap: 2px;
		box-sizing: border-box;
		min-width: 0;
		min-height: 0;
		margin: 0 0 0 26px;
		padding: 0 0 0 12px;
		border: 0;
		border-left: 2px solid #e7dffb;
		border-radius: 0;
		background: transparent;
		box-shadow: none;
		overflow: hidden;
		opacity: 1 !important;
		position: static !important;
		transition: display 0.28s allow-discrete;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container > li:first-child {
		margin-top: 3px;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container > li:last-child {
		margin-bottom: 7px;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item.has-child:has(
			> .wp-block-navigation-submenu__toggle[aria-expanded="true"]
		) > .wp-block-navigation__submenu-container {
		display: flex !important;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__submenu-container
		.wp-block-navigation-item__content.wp-block-navigation-item__content {
		min-height: 44px;
		padding: 11px 13px;
		border-radius: 11px;
		font-size: 0.96875rem;
		font-weight: 500;
		line-height: 1.35;
		white-space: normal;
		color: #4c4667;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__submenu-container
		.wp-block-navigation-item__content.wp-block-navigation-item__content:hover,
	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__submenu-container
		.wp-block-navigation-item__content.wp-block-navigation-item__content:focus-visible {
		outline: 0;
		background: #f2edfd;
		color: #6431c9;
	}

	.ff-header__nav .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__submenu-icon {
		width: 20px;
		height: 20px;
	}

	/* Persistent "Оставить заявку" CTA while the overlay is open. Rather than
	   duplicating a new button inside wp_navigation's saved menu content
	   (a database edit outside this pass's CSS-only scope), float the
	   header's own .ff-header__cta pill — it already carries the right
	   href (forms.js keeps it pointed at #calc or the page's lead section)
	   and .ff-btn-pill styling — as a fixed bar above the overlay. :has()
	   is needed because .ff-header__cta is a flex *sibling* of .ff-header__nav
	   (both children of .ff-header__inner), not a descendant of it. */
	.ff-header:has(.wp-block-navigation__responsive-container.is-menu-open) .ff-header__cta.ff-header__cta {
		display: flex !important;
		position: fixed;
		left: 16px;
		right: 16px;
		bottom: calc(16px + env(safe-area-inset-bottom));
		z-index: 100001;
		margin: 0;
	}

	/* Soft fade so the scrollable list doesn't hard-clip right at the fixed
	   CTA bar's top edge. */
	.ff-header:has(.wp-block-navigation__responsive-container.is-menu-open) .ff-header__cta.ff-header__cta::before {
		content: "";
		position: absolute;
		left: -16px;
		right: -16px;
		bottom: 100%;
		height: 28px;
		background: linear-gradient(to top, #fff 0%, rgba(255, 255, 255, 0) 100%);
		pointer-events: none;
	}

	/* Base .ff-btn-pill padding/justify-content (space-between, 8px right /
	   ~20-42px left) is tuned for the pill's natural content width; stretched
	   to this bar's full width that strands [text+circle] on the left, same
	   issue .ff-lead-banner__form .ff-lead-form__submit already works around
	   below — mirror that fix (center, symmetric padding). The
	   .wp-block-button wrapper needs width:100% too, not just the link
	   inside it — it's the actual flex item in .ff-header__cta, so without
	   this the link's own width:100% just fills that unstretched,
	   content-sized wrapper instead of the bar. */
	.ff-header:has(.wp-block-navigation__responsive-container.is-menu-open) .ff-header__cta .wp-block-button,
	.ff-header:has(.wp-block-navigation__responsive-container.is-menu-open) .ff-header__cta .wp-block-button__link {
		width: 100%;
	}

	.ff-header:has(.wp-block-navigation__responsive-container.is-menu-open) .ff-header__cta .wp-block-button__link {
		justify-content: center;
		gap: 10px;
		min-height: 56px;
		padding-left: 8px;
		padding-right: 8px;
	}

}

@media (max-width: 767px) {
	.ff-header__cta .wp-block-button__link {
		padding-inline-start: 20px;
		gap: 10px;
	}

	.ff-header__cta .wp-block-button__link::after {
		width: 34px;
		height: 34px;
	}
}

@media (max-width: 480px) {
	/* Specificity needs to beat core's `body .is-layout-flex{display:flex}`
	   global style, hence the doubled-up selector rather than a single class. */
	.ff-header .ff-header__cta.ff-header__cta {
		display: none;
	}
}

/* Core only switches the primary nav to its burger/overlay presentation
   below 600px; at 1170px of content plus a 9-item "Услуги" dropdown, 4 top
   level links and a CTA, that leaves an awkward wrapping range roughly
   600–1023px where the inline menu no longer fits on one line (confirmed
   visually at 800px). Extend the burger breakpoint up to 1023px instead —
   both rules need to beat core's own `(min-width:600px)` display rules, so
   they carry !important the way core's near-equivalent declarations do. */
@media (min-width: 600px) and (max-width: 1023px) {
	.ff-header__nav .wp-block-navigation__responsive-container-open {
		display: flex !important;
	}

	.ff-header__nav .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none !important;
	}
}

@media (prefers-reduced-motion: reduce) {
	.ff-header__nav .wp-block-navigation__responsive-container,
	.ff-header__nav .wp-block-navigation__responsive-container-open,
	.ff-header__nav .wp-block-navigation__responsive-container-close,
	.ff-header__nav .wp-block-navigation-item__content,
	.ff-header__nav .wp-block-navigation-submenu__toggle,
	.ff-header__nav .wp-block-navigation-submenu__toggle svg,
	.ff-header__nav .wp-block-navigation-item.has-child,
	.ff-header__nav .wp-block-navigation__submenu-container {
		transition: none !important;
	}
}

/* =======================================================================
   PARTNERS STRIP (light section below the hero)
   ======================================================================= */

.ff-partners {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(1.5rem, 1.1667rem + 1.4815vw, 3.125rem);
}

.ff-partners__title {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	/* Figma desktop (38:929) text-box width is 1016px, hard-broken by the
	   designer as "Ваши продажи с одного склада" / "на всех маркетплейсах"
	   (an explicit \n in the source, not an emergent word-wrap). A small
	   buffer over the measured width keeps line 1 intact against minor
	   browser/Figma font-metric drift while staying well short of fitting
	   "на" too (see .ff-partners__title-seg below for how the 3 phrases
	   are kept from splitting mid-phrase at either breakpoint). Deficit
	   lockstep (max-width grows with --ff-gutter, see the comment at the
	   top of the file): keeps the 1008px text measure this heading had
	   at 16px padding exactly intact once the gutter grows, instead of
	   quietly narrowing it. :not(.alignfull) defensively matches
	   .ff-steps's own fix elsewhere in this file (cheap insurance,
	   not confirmed needed for this particular heading). */
	margin: 0 auto;
	padding-inline: var(--ff-gutter);
}
.ff-partners__title:not(.alignfull) {
	max-width: calc(1040px + (var(--ff-gutter) - 16px) * 2);
}

/* Each of the 3 phrases making up the heading is glued with white-space:
   nowrap so it can never split mid-phrase; the surrounding max-width (here
   and in the 767px override below) decides how many phrases share a line:
   wide enough for phrase 1 + phrase 2 together on desktop (2 lines total),
   narrow enough that mobile puts each phrase on its own line (3 lines). */
.ff-partners__title-seg {
	white-space: nowrap;
}

@media (max-width: 767px) {
	/* Figma mobile heading (103:308) is size 28/line-height 30 (not the
	   1.25 ratio used at desktop) and hard-broken into 3 lines: "Ваши
	   продажи" / "с одного склада" / "на всех маркетплейсах". As with the
	   hero H1, browser Inter metrics won't reliably reproduce a 3-way
	   split from box width alone, so all 3 phrases are nowrap-glued
	   (above) and this max-width is sized to fit the widest single phrase
	   while being well short of fitting any two adjacent phrases together. */
	.ff-partners__title {
		max-width: 340px;
		line-height: 1.0714;
	}
}

/* Seamless CSS-only marquee: the track holds two identical copies of the
   logo row (see patterns/partners-strip.php) side by side and scrolls
   exactly one copy-width to the left, looping invisibly. Edge-to-edge
   full viewport width by design — .ff-partners intentionally carries no
   horizontal padding so this band is never inset. */
.ff-marquee {
	overflow: hidden;
	background-color: var(--wp--preset--color--bg-lilac);
	margin-top: clamp(1.5rem, 1rem + 2.2222vw, 3.125rem);
}

.ff-marquee__track {
	display: flex;
	width: max-content;
	animation: ff-marquee-scroll 40s linear infinite;
}

.ff-marquee__group {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	/* Figma: gap between logos is 30px on the 360 frame (103:224) and 76px
	   on the 1920 frame (38:932) — measured from consecutive logo bboxes,
	   which line up with an exact constant gap at each reference width. */
	column-gap: clamp(1.875rem, 1.2115rem + 2.9487vw, 4.75rem);
	/* Figma: the lilac band is 111.5px tall on mobile / 155px on desktop
	   around a logo row that's 45px / 55px tall at its tallest logo, i.e.
	   ~33px / 50px of vertical padding above and below on each frame. */
	padding-block: clamp(2.0625rem, 1.8173rem + 1.0897vw, 3.125rem);
	padding-inline-end: clamp(1.875rem, 1.2115rem + 2.9487vw, 4.75rem);
}

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

@media (prefers-reduced-motion: reduce) {
	.ff-marquee__track {
		animation: none;
	}
}

/* =======================================================================
   ARTICLE TEMPLATE — templates/single.html. Post content remains pure
   Gutenberg; dynamic conversion, related posts and services are template
   blocks registered in inc/article-template.php.
   ======================================================================= */
.ff-article,
.ff-article * { box-sizing: border-box; }
.ff-article { padding: 28px 0 80px; color: #3d2947; }
.ff-article__inner { width: min(1170px, calc(100% - 2 * var(--ff-gutter))); margin-inline: auto; }
.ff-article__breadcrumb { display:flex; gap:8px; margin:0 0 50px !important; color:#a99ccf; font:14px/17px Inter,sans-serif; }
.ff-article__breadcrumb a { color:#4a3d58; text-decoration:none; }
.ff-article__layout { display:grid; grid-template-columns:minmax(0, 770px) 370px; gap:30px; align-items:start; }
.ff-article__main { min-width:0; }
.ff-article__title { max-width:770px; margin:0 0 20px !important; color:#1a1a2e; font:600 52px/1.15 Inter,sans-serif; letter-spacing:-.02em; }
.ff-article__meta { display:flex; align-items:center; gap:12px; margin:0 0 30px !important; color:#74669e; font:14px/20px Inter,sans-serif; }
.ff-article__updated { display:inline-flex; padding:8px 24px; border-radius:999px; background:#e3f5e8; color:#26944c; font:500 13px/20px Inter,sans-serif; }
.ff-article__image { max-width:770px; margin:0 auto 40px !important; overflow:hidden; border-radius:16px; }
.ff-article__image img { display:block; width:100%; max-height:470px; object-fit:cover; }
.ff-article__content { max-width:770px; margin-inline:auto; color:#3d2947; font:16px/1.6 Inter,sans-serif; }
.ff-article__content > * { margin-block:0 22px !important; }
.ff-article__content h2 { margin-top:56px !important; color:#1a1a2e; font:600 32px/40px Inter,sans-serif; }
.ff-article__content h3 { margin-top:32px !important; color:#1a1a2e; font:600 22px/30px Inter,sans-serif; }
.ff-article__content a { color:#6c37d6; }
.ff-article__content ul, .ff-article__content ol { padding-left:24px; }
.ff-article__content blockquote { padding:20px 24px; border-left:3px solid #9671ff; border-radius:0 12px 12px 0; background:#f6f5fc; }
.ff-article__content .wp-block-group { margin:30px 0 !important; padding:24px; border-radius:14px; background:#f6f5fc; }
.ff-article__content .wp-block-group > :last-child { margin-bottom:0 !important; }
.ff-article__content .ff-article__note { border-left:4px solid #9671ff; }
.ff-article__content .ff-article__numbered-card { position:relative; padding-left:82px; background:#fff; border:1px solid #ececf5; }
.ff-article__content .ff-article__numbered-card::before { position:absolute; top:24px; left:24px; display:grid; width:38px; height:38px; place-items:center; border-radius:50%; background:#f1ebff; color:#6c37d6; content:counter(ff-article-number); counter-increment:ff-article-number; font:600 16px/1 Inter,sans-serif; }
.ff-article__content { counter-reset:ff-article-number; }
.ff-article__content figure { margin:32px 0 !important; }
.ff-article__content figure img { display:block; width:100%; border-radius:14px; }
.ff-article__content figcaption { margin-top:10px; color:#74669e; font:13px/18px Inter,sans-serif; text-align:center; }
.ff-article__content .wp-block-table { overflow-x:auto; margin:32px 0 !important; border:1px solid #e5dff0; border-radius:12px; }
.ff-article__content table { width:100%; min-width:640px; border-collapse:collapse; font:14px/20px Inter,sans-serif; }
.ff-article__content th { background:#f1ebff; color:#382841; font-weight:600; text-align:left; }
.ff-article__content th, .ff-article__content td { padding:16px; border:1px solid #e5dff0; vertical-align:top; }
.ff-article__content tbody tr:nth-child(even) { background:#fbfaff; }

.ff-article-aside { position:relative; display:flex; flex-direction:column; min-height:438px; padding:30px 28px; overflow:hidden; border-radius:16px; background:radial-gradient(90% 90% at 10% 6%, #8e43ff 0%, #3a1e74 100%); color:#fff; }
.ff-article-aside__pattern { position:absolute; right:0; bottom:0; width:185px; height:165px; z-index:0; pointer-events:none; }
.ff-article-aside h2, .ff-article-aside > p, .ff-article-aside__btn { position:relative; z-index:1; }
.ff-article-aside h2 { margin:0 0 20px; color:#fff; font:600 28px/31px Inter,sans-serif; }
.ff-article-aside > p { margin:0; font:15px/21px Inter,sans-serif; }
.ff-article-aside__btn { margin-top:32px; }
.ff-article-lead { margin:70px auto !important; }
.ff-article-related { max-width:1170px; margin:70px auto 0 !important; }
.ff-article-related h2 { margin:0 0 30px; color:#1a1a2e; font:600 40px/48px Inter,sans-serif; }
.ff-article-related__grid { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:30px; }
.ff-article-related__card { display:flex; min-height:265px; flex-direction:column; padding:24px; border-radius:12px; background:#f6f5fc; }
.ff-article-related__term { align-self:flex-start; padding:8px 20px; border-radius:999px; background:#fff; color:#8e73fe; font:500 13px/20px Inter,sans-serif; }
.ff-article-related__card h3 { margin:38px 0 8px; font:600 16px/22px Inter,sans-serif; }
.ff-article-related__card h3 a { color:#3d2947; text-decoration:none; }
.ff-article-related__card p { margin:0; font:13px/18px Inter,sans-serif; }
.ff-article-related__link { margin-top:auto; padding-top:12px; color:#8e73fe; font:600 14px/18px Inter,sans-serif; text-decoration:none; }
.ff-article-services { margin-top:70px !important; }

@media (max-width: 900px) {
 .ff-article__title { font-size:44px; }
 .ff-article__layout { grid-template-columns:minmax(0, 1fr) 300px; gap:24px; }
 .ff-article-aside { padding:24px 20px; }
 .ff-article-related__grid { grid-template-columns:repeat(2, minmax(0, 1fr)); gap:20px; }
}
@media (max-width: 640px) {
 .ff-article { padding:20px 0 50px; }
 .ff-article__breadcrumb { display:none; }
 .ff-article__term { margin-bottom:16px !important; }
 .ff-article__title { margin-bottom:16px !important; font-size:28px; line-height:30px; letter-spacing:0; }
 .ff-article__layout { display:block; }
 .ff-article-aside { display:none; }
 .ff-article__meta { flex-wrap:wrap; margin-bottom:20px !important; }
 .ff-article__image { margin-bottom:30px !important; border-radius:12px; }
 .ff-article__content { font-size:15px; line-height:1.55; }
 .ff-article__content h2 { margin-top:42px !important; font-size:26px; line-height:32px; }
 .ff-article__content h3 { font-size:19px; line-height:26px; }
 .ff-article-lead, .ff-article-services { margin-top:50px !important; }
 .ff-article-related h2 { margin-bottom:20px; font-size:28px; line-height:30px; }
 .ff-article-related__grid { display:flex; gap:10px; overflow-x:auto; padding-bottom:5px; scroll-snap-type:x mandatory; }
 .ff-article-related__card { flex:0 0 271px; scroll-snap-align:start; }
}

.ff-partners__logo img {
	display: block;
	width: auto;
}

/* Per-brand logo heights, fluid between the 360px and 1920px Figma
   frames. Desktop (max) values are each mark's own natural height on the
   1920 frame (38:886 -> 46:537); mobile (min) values apply the same
   ~0.8182 scale factor established for Avito on the 103:221 frame (its
   only mark with confirmed mobile art: 27px vs 33px desktop) since the
   other 8 marks don't have independently-measured mobile boxes. Formula
   per pair: coeff = (max-min)/15.6; constant = (min - coeff*3.6)/16rem. */
.ff-partners__logo--yandex-market img {
	height: clamp(2.7614rem, 2.6198rem + 0.6294vw, 3.375rem);
}

.ff-partners__logo--wildberries img {
	height: clamp(2.4545rem, 2.3287rem + 0.5594vw, 3rem);
}

.ff-partners__logo--ozon img {
	height: clamp(1.3295rem, 1.2614rem + 0.3030vw, 1.625rem);
}

/* Figma: Avito mark (38:959 / 103:251) is 33px tall on the desktop
   frame, 27px on the mobile frame — the reference pair the scale
   factor above is derived from. */
.ff-partners__logo--avito img {
	height: clamp(1.6875rem, 1.6010rem + 0.3846vw, 2.0625rem);
}

.ff-partners__logo--letoile img {
	height: clamp(1.2784rem, 1.2135rem + 0.2914vw, 1.5625rem);
}

.ff-partners__logo--zolotoe-yabloko img {
	height: clamp(2.1989rem, 2.0861rem + 0.5012vw, 2.6875rem);
}

.ff-partners__logo--vseinstrumenty img {
	height: clamp(2.8125rem, 2.6683rem + 0.6410vw, 3.4375rem);
}

.ff-partners__logo--detskiy-mir img {
	height: clamp(2.6080rem, 2.4742rem + 0.5944vw, 3.1875rem);
}

.ff-partners__logo--lamoda img {
	height: clamp(1.4832rem, 1.4069rem + 0.3380vw, 1.8125rem);
}

/* =======================================================================
   SERVICES (auto-grid from the ff_service CPT query + purple CTA card)
   All geometry sourced from _figma/full.json — see the docblock in
   patterns/services.php for the full node-by-node breakdown.
   ======================================================================= */

.ff-services {
	position: relative;
	overflow: hidden;
	background-color: var(--wp--preset--color--bg-lavender);
	/* Figma: 100px top/bottom desktop (38:927 bg rect 4233..5439 vs content
	   108:582 4333..5339), 50px top/bottom mobile (109:674 3746..4354 vs
	   content 108:583 3796..4304). */
	padding-top: clamp(3.125rem, 2.4038rem + 3.2051vw, 6.25rem);
	padding-bottom: clamp(3.125rem, 2.4038rem + 3.2051vw, 6.25rem);
	padding-inline: var(--ff-gutter);
}

/* Two background decor shapes, absolutely positioned relative to the
   full-bleed section (not the 1170 content column) — see patterns/
   services.php docblock for the exact offset math from full.json. */
.ff-services__bg {
	position: absolute;
	inset: 0;
	max-width: none;
	margin-inline: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.ff-services__bg img {
	position: absolute;
	display: block;
	max-width: none;
}

.ff-services__bg-left {
	left: 0;
	bottom: 0;
	width: 518px;
	height: 511px;
}

.ff-services__bg-right {
	top: 0;
	right: 0;
	width: 326px;
	height: 684px;
}

@media (max-width: 640px) {
	/* Mobile node 109:669: same bg-left.svg asset, scaled down, deliberately
	   poking 15px above the section's own top edge (confirmed with the
	   client 2026-07-19) rather than sitting flush bottom-left like desktop. */
	.ff-services__bg-left {
		top: -15px;
		bottom: auto;
		left: 0;
		width: 201px;
		height: 198px;
	}

	/* No confident mobile asset for the second section-level decor node
	   (109:675 is 175x175, doesn't match bg-right's 326x684 tall-sliver
	   aspect) — omitted rather than guess a crop; see patterns/services.php.
	   Specificity note: needs to beat ".ff-services__bg img" (0,1,1), so
	   this repeats the "img" type selector rather than just the class. */
	.ff-services__bg img.ff-services__bg-right {
		display: none;
	}
}

/* Real content sits above the z-index:0 decor layer (same technique as
   .ff-calc__card > * elsewhere in this file). */
.ff-services__title,
.ff-services__grid {
	position: relative;
	z-index: 1;
	width: 100%;
	max-width: 1170px;
	margin-inline: auto;
}

.ff-services__title {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	/* Figma itemSpacing title->grid: 50px desktop / 40px mobile — identical
	   range to .ff-promise__title's own gap, same clamp reused verbatim. */
	margin: 0 auto clamp(2.5rem, 2.3558rem + 0.6410vw, 3.125rem);
}

@media (max-width: 640px) {
	/* Figma mobile title lh is 30px at the 28px reference size (ratio
	   1.0714), not the base rule's 1.25 — correct it at the same
	   breakpoint the grid itself turns into a slider. */
	.ff-services__title {
		line-height: 1.0714;
	}
}

.ff-services__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: clamp(1rem, 0.7981rem + 0.8974vw, 1.875rem);
	align-items: stretch;
}

/* The query loop adds two wrapper levels WordPress doesn't give us a class
   hook to skip (.wp-block-query > ul.wp-block-post-template > li.wp-block-
   post), which would otherwise sit between the grid and the 5 post cards
   while the CTA card is a plain sibling of the query block — breaking the
   single 3x2 grid. Flattening all three with display:contents lets the 5
   cards and the static CTA card share one grid/slider as 6 flat items. */
.ff-services__grid > .wp-block-query,
.ff-services__grid .wp-block-post-template,
.ff-services__grid .wp-block-post-template > li {
	display: contents;
}

.ff-services__card {
	display: flex;
	flex-direction: column;
	background-color: var(--wp--preset--color--white);
	border-radius: 24px;
	overflow: hidden;
	/* Figma 46:529 DROP_SHADOW: rgba(158,155,174,.2) / 0,30 offset / 40 blur. */
	box-shadow: 0 30px 40px rgba(158, 155, 174, 0.2);
}

.ff-services__card-photo {
	margin: 0;
	flex: 0 0 auto;
}

.ff-services__card-photo img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 370 / 270;
	object-fit: cover;
	border-radius: 24px 24px 0 0;
}

.ff-services__card-body {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	gap: 16px;
	/* Figma 46:579 vs card 46:548: 24px sides, 24px gap-after-photo, 24px
	   bottom — uniform, unlike the old fluid 16-24/16-32/0 padding. */
	padding: 24px;
}

.ff-services__card-title {
	margin: 0;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 500;
	font-size: clamp(1.25rem, 1.1923rem + 0.2564vw, 1.5rem);
	line-height: 1.2;
}

.ff-services__card-title a {
	color: inherit;
	text-decoration: none;
}

.ff-services__card-link {
	margin-top: auto;
	display: inline-flex;
	align-items: center;
	gap: 0;
	color: var(--wp--preset--color--brand-deep);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 500;
	font-size: 0.875rem;
	text-decoration: none;
}

.ff-services__card-link:hover {
	text-decoration: underline;
}

/* Figma "Icon/arrow-up-right" instance: 20x20, stroke #854BFB (brand)
   1.5px — real icon (assets/img/services/arrow-up-right.svg), not a
   Unicode glyph, see patterns/services.php docblock. */
.ff-services__card-link::after {
	content: "";
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	background: url("../img/services/arrow-up-right.svg") no-repeat center / contain;
}

.ff-services__cta {
	position: relative;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 16px;
	border-radius: 24px;
	/* Figma 47:651 vs card 47:648: 24px sides, 32px top. */
	padding: 32px 24px 24px;
	background: radial-gradient(80.09% 78.42% at 32.16% 21.58%, #7B34BC 0%, #361D6A 100%);
	box-shadow: 0 30px 40px rgba(212, 210, 222, 0.2);
	min-height: 320px;
}

.ff-services__cta-title {
	margin: 0;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.5rem, 1.4135rem + 0.3846vw, 1.875rem);
	line-height: 1.3;
}

.ff-services__cta-text {
	margin: 0;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.9375rem, 0.9231rem + 0.0641vw, 1rem);
	line-height: 1.5;
	opacity: 0.9;
}

.ff-services__cta-btn {
	margin-top: auto;
}

/* Figma 47:662: raw 207x207 "icon_3.svg" hangs 22px past the card's right
   edge and 42px past its bottom edge, clipped by the card's own
   clipsContent+radius to a 185x165 visible sliver flush with the
   bottom-right corner — that sliver is exactly cta-pattern.svg. */
.ff-services__cta-pattern {
	position: absolute;
	right: 0;
	bottom: 0;
	width: 185px;
	height: 165px;
	z-index: 0;
	pointer-events: none;
}

.ff-services__cta > :not(.ff-services__cta-pattern) {
	position: relative;
	z-index: 1;
}

@media (max-width: 960px) {
	.ff-services__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 640px) {
	/* Horizontal card slider — same scroll-snap technique as
	   .ff-promise__bullets above (see its comments for the full rationale). */
	.ff-services__grid {
		display: flex;
		flex-wrap: nowrap;
		gap: 10px;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		scroll-snap-type: x mandatory;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		-ms-overflow-style: none;
		padding-block: 12px 64px;
	}

	.ff-services__grid::-webkit-scrollbar {
		display: none;
	}

	.ff-services__card,
	.ff-services__cta {
		flex: 0 0 271px;
		scroll-snap-align: start;
	}

	.ff-services__cta {
		min-height: 0;
	}
}

/* =======================================================================
   STEPS (01-04 "how to start" zigzag timeline)

   Desktop: two 366px content columns either side of a 164px center gutter
   (896px total, centered in the 1170px section) holding a dashed vertical
   line + 4 dots; steps alternate content-left/number-right and
   number-left/content-right. Mobile: left rail (number + dot) with the
   dashed line running through it, text to the right. Values sourced from
   full.json (desktop 38:886 -> Frame 427319137, mobile 100:176 -> Frame
   427319146) and the client's dot/line SVGs — see patterns/steps.php.
   ======================================================================= */

.ff-steps {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
}

/* Deficit lockstep, see --ff-gutter comment at the top of the file.
   :not(.alignfull) matters here specifically: on pages where this exact
   section is saved as align:full instead (e.g. /wildberries/), core's
   own ".is-layout-constrained > .alignfull{max-width:none}" turned out
   to NOT reliably beat this rule (both (0,1,0), a bare class each —
   source order alone would let this one win) and core never gives
   .alignfull elements margin:auto either (that rule explicitly excludes
   .alignfull, alignfull isn't supposed to need centering) — the two
   combined would have left the section pinned to the left edge with a
   dead gap on the right, confirmed live before adding this exclusion.
   Excluding .alignfull here just leaves core's own max-width:none in
   full control on those pages, same self-correcting math .ff-services
   relies on. */
.ff-steps:not(.alignfull) {
	max-width: calc(1170px + (var(--ff-gutter) - 16px) * 2);
}

.ff-steps__title {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	/* Заголовок -> таймлайн: 40px@360 -> 50px@1920 (было 32/60 по замеру). */
	margin: 0 auto clamp(2.5rem, 2.3558rem + 0.641vw, 3.125rem);
}

.ff-steps__timeline {
	/* --ff-steps-num-fs shared with .ff-steps__num (font-size) and
	   .ff-steps__step::before (dot vertical position = center of the
	   number's line box), so the dot always tracks the number's own
	   optical center at any viewport width instead of needing separate
	   breakpoint offsets.
	   Row mechanic (desktop): CSS grid with a 134px row floor (Figma:
	   consecutive number tops sit exactly 134px apart; each row's own
	   content — number 60px / text block <=100px — is always shorter, so
	   minmax's "auto" only kicks in as a graceful degrade for future
	   longer copy). row-gap:0 because the 134px floor already includes
	   the whole gap — .ff-steps__step stretches (grid default
	   align-items:stretch) to fill its row track, so the dot/dashed-line
	   math below (pinned to the STEP's own top) lands identically on
	   every row regardless of content height. Mobile switches back to a
	   plain flow + explicit gap (see @media below) since there the target
	   is a constant visual gap between blocks, not a fixed row pitch. */
	--ff-steps-num-fs: clamp(1.25rem, 0.8173rem + 1.9231vw, 3.125rem);
	position: relative;
	display: grid;
	grid-auto-rows: minmax(134px, auto);
	row-gap: 0;
	max-width: 896px;
	margin-inline: auto;
}

.ff-steps__step {
	position: relative;
	display: grid;
	grid-template-columns: 1fr 1fr;
	column-gap: 164px;
	align-items: start;
}

/* CSS Grid auto-placement bug fix: on odd rows .ff-steps__num (DOM-first)
   gets grid-column:2 while .ff-steps__content (DOM-second) gets column:1 —
   since the 2nd item's column is LOWER than the 1st item's, the spec's
   auto-placement cursor advances to a new implicit row for it (the same
   heuristic that lets text "wrap" to a new line), so content silently
   dropped to row 2, one whole number-line-box (~60px) below the number.
   Even rows don't trip this (content's column is HIGHER, cursor stays put)
   — hence the bug only ever showed on steps 1/3. Pin both to row 1
   explicitly so neither ever auto-places into a second row. */
.ff-steps__num,
.ff-steps__content {
	grid-row: 1;
}

/* Dot: 16px brand-purple core + a hard-edged (no blur) light-lavender
   halo, reverse-engineered from the client's Overlay+Shadow.svg
   drop-shadow filter — feMorphology dilate (no feGaussianBlur), offset
   0/0, blur radius 0, spread 11px desktop / 5px mobile, halo color
   rgb(236,232,255) from the filter's feColorMatrix. Explicit z-index
   keeps it above the line segments below regardless of DOM order. */
.ff-steps__step::before {
	content: "";
	position: absolute;
	top: calc(var(--ff-steps-num-fs) * 0.6);
	left: 50%;
	width: 16px;
	height: 16px;
	transform: translate(-50%, -50%);
	border-radius: 50%;
	background: var(--wp--preset--color--brand-deep);
	box-shadow: 0 0 0 11px #ece8ff;
	z-index: 2;
}

/* Center dashed line: 1px, brand purple @ 20% opacity, 7px dash / 7px
   gap — traced from the client's Line 5.svg (_figma/steps/линия). Drawn
   as one segment per gap (row N's ::after reaches from row N's own dot
   center down to row N+1's dot center), so the line runs exactly from dot
   1 to dot 4 no matter how tall each row's text grows/shrinks. Desktop:
   row-gap is 0 (see .ff-steps__timeline) and .ff-steps__step stretches to
   fill its own row track, so "100%" of ITS OWN (stretched) height already
   reaches exactly the next row's top — no extra term needed. Mobile still
   flows with a real gap between blocks, so its override below adds that
   gap back (see @media). */
.ff-steps__step:not(:last-child)::after {
	content: "";
	position: absolute;
	top: calc(var(--ff-steps-num-fs) * 0.6);
	left: 50%;
	width: 1px;
	height: 100%;
	transform: translateX(-50%);
	background-image: repeating-linear-gradient(
		to bottom,
		rgba(108, 55, 214, 0.2) 0,
		rgba(108, 55, 214, 0.2) 7px,
		transparent 7px,
		transparent 14px
	);
	z-index: 0;
}

/* Zigzag alternation: odd steps (1st, 3rd) = content left / number
   right; even steps (2nd, 4th) = number left / content right. The big
   number always hugs the center gutter regardless of which side it's
   on; markup order (number, then content) stays the same for every
   step, only these placement rules change which grid column each
   lands in. */
.ff-steps__step:nth-child(odd) .ff-steps__content {
	grid-column: 1;
}

.ff-steps__step:nth-child(odd) .ff-steps__num {
	grid-column: 2;
	justify-self: start;
}

.ff-steps__step:nth-child(even) .ff-steps__num {
	grid-column: 1;
	justify-self: end;
}

.ff-steps__step:nth-child(even) .ff-steps__content {
	grid-column: 2;
}

.ff-steps__content {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.ff-steps__num {
	margin: 0;
	color: var(--wp--preset--color--brand-deep);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 700;
	font-size: var(--ff-steps-num-fs);
	line-height: 1.2;
}

.ff-steps__step-title {
	margin: 0;
	color: var(--wp--preset--color--brand-deep);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 700;
	font-size: clamp(1rem, 0.9423rem + 0.2564vw, 1.25rem);
	line-height: 1.3;
}

.ff-steps__step-desc {
	margin: 0;
	color: var(--wp--preset--color--text-muted);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.875rem, 0.8606rem + 0.0641vw, 0.9375rem);
	line-height: 1.4;
}

.ff-steps__cta {
	/* Последний блок -> кнопка: 30px@360 -> 50px@1920 (было 8/60 по замеру). */
	margin-top: clamp(1.875rem, 1.5865rem + 1.2821vw, 3.125rem);
}

@media (max-width: 767px) {
	/* Mobile keeps a plain flow (not the desktop 134px-row grid): target
	   here is a constant 20px VISUAL GAP between blocks regardless of each
	   block's own content height, which a real flex gap gives directly
	   (a fixed row-track height would instead only leave a gap when
	   content is shorter than the track, same bug the desktop fix
	   replaced). */
	.ff-steps__timeline {
		display: flex;
		flex-direction: column;
		gap: 20px;
	}

	/* Left rail: number (fixed 28px column) + dot/line, text fills the
	   rest. All four steps use the same rail-left/text-right order on
	   mobile (no zigzag), overriding the desktop odd/even placement. */
	.ff-steps__step {
		grid-template-columns: 28px 1fr;
		column-gap: 48px;
	}

	.ff-steps__step:nth-child(odd) .ff-steps__num,
	.ff-steps__step:nth-child(even) .ff-steps__num {
		grid-column: 1;
		justify-self: start;
	}

	.ff-steps__step:nth-child(odd) .ff-steps__content,
	.ff-steps__step:nth-child(even) .ff-steps__content {
		grid-column: 2;
	}

	/* Real flex gap between blocks (20px, above) means the dashed line
	   must additionally cross that gap, unlike the desktop rule (100%,
	   no separate gap term needed since row-gap:0 there). */
	.ff-steps__step:not(:last-child)::after {
		left: 45px;
		height: calc(100% + 20px);
	}

	.ff-steps__step::before {
		left: 45px;
		box-shadow: 0 0 0 5px #ece8ff;
	}

	/* Figma's mobile CTA (Frame 427319104, 297 of the 328px content
	   width) is a near-full-width pill, unlike the shared .ff-btn-pill
	   component's default content-hugging size used elsewhere on the
	   site (header/hero/other sections) — scoped to .ff-steps__cta only
	   so it doesn't change any other section's button. */
	.ff-steps__cta .wp-block-button,
	.ff-steps__cta .wp-block-button__link {
		width: 100%;
	}

	.ff-steps__cta .wp-block-button__link {
		justify-content: center;
		/* Base .ff-btn-pill padding is asymmetric (8px right, ~24px left)
		   to visually balance content-hugging pills elsewhere. Here the
		   pill is full-width + centered, so that asymmetry shifts the
		   [text + circle] group ~8px right of the button's true center.
		   Match left to right so the centered group lands on-center. */
		padding-left: 8px;
	}
}

/* First step's title ("Оставьте заявку") is 24px in the desktop Figma
   frame (38:886 -> Frame 427319137: fontSize 24 vs. 20 on the other three
   titles); mobile frame (100:176 -> Frame 427319146) uses 16 same as the
   rest, so this stays desktop-only. */
@media (min-width: 768px) {
	.ff-steps__step:first-child .ff-steps__step-title {
		font-size: 1.5rem;
	}
}

/* =======================================================================
   CATEGORIES (4x2 product-category grid)
   ======================================================================= */

.ff-categories {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
}

/* This section's own layout:constrained block already caps it at exactly
   contentSize (1170px, theme.json) and centers it — confirmed live
   (getBoundingClientRect: section width === 1170px at any viewport
   >=1170px, entry-content/body carry zero padding of their own). Below
   that cap the --ff-gutter inline padding above is load-bearing (keeps
   the grid off the viewport edge while the section is still shrinking
   with the viewport, e.g. the 960px 2-column tablet layout — see the
   --ff-gutter comment at the top of the file for why this section grows
   its padding directly instead of needing the max-width lockstep trick
   used elsewhere: this override already zeroes the padding out at
   exactly the point the section hits its cap, so there's no deficit
   left to compensate for). But once the section has actually hit its
   1170px cap, that same padding starts eating INTO the already-exact
   1170px box instead of guarding an edge — at the old flat 16px it
   shrank the grid to 1138px, which made repeat(4,1fr) solve to 262px
   cards instead of Figma's 270px (4x270 + 3x30 = 1170, no leftover for
   padding); at --ff-gutter's grown values the deficit would only be
   worse. Zero it out exactly at the cap so the grid gets the full
   1170px Figma affords it; harmless below 1170px since this rule simply
   doesn't apply there. */
@media (min-width: 1170px) {
	.ff-categories {
		padding-inline: 0;
	}
}

/* Figma desktop (38:886 -> 53:370 -> 38:1068) text-box width 669px, wraps
   naturally (real Inter metrics, no nowrap-span gluing needed) into
   "Работаем со всеми категориями" / "товаров для маркетплейсов" — safe
   from ~645px to ~830px at the 40px reference size. em (not px) so the
   same safe ratio holds across the whole fluid 28-40px clamp range above
   the 767px breakpoint, not just at the 1920px endpoint (a fixed 669px
   box would let "товаров" join line 1 around 768-1000px, where the fluid
   font-size is well under 40px — verified with the Range API). Title-to-
   grid gap 50px desktop / 40px mobile — identical to .ff-promise__title /
   .ff-services__title's own gap, same clamp reused verbatim. */
.ff-categories__title {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	max-width: 16.725em;
	margin: 0 auto clamp(2.5rem, 2.3558rem + 0.6410vw, 3.125rem);
}

@media (max-width: 767px) {
	/* Figma mobile (100:176 -> 109:779 -> 109:780): fixed 328px text box
	   (360px mobile frame minus this section's 16px inline padding on each
	   side), 28px/600, line-height 30px. Frozen (not clamped) below this
	   breakpoint so the exact 3-line split ("Работаем со всеми" /
	   "категориями товаров" / "для маркетплейсов") holds at every real
	   phone width, same technique as .ff-promise__title. */
	.ff-categories__title {
		max-width: 328px;
		font-size: 1.75rem;
		line-height: 1.0714;
	}
}

/* Figma desktop grid (109:777): GRID layout, 4 columns, gridRowGap/
   gridColumnGap both 30px — 1fr columns land on the JSON's own 270px card
   width once the 1170px content column is fully available (4x270 +
   3x30 = 1170). Gap clamp reused verbatim from .ff-services__grid (same
   16-30px range; the exact min endpoint doesn't matter in practice since
   the mobile slider below takes over long before it would be reached). */
.ff-categories__grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: clamp(1rem, 0.7981rem + 0.8974vw, 1.875rem);
}

@media (max-width: 960px) {
	.ff-categories__grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* The gap clamp above only reaches its own 30px max at a ~1920px
   viewport, same as every other fluid gap in this file — fine when the
   row's own total width is itself still fluid, but this grid's total
   width goes fixed at 1170px as soon as the section hits its max-width
   (see the padding-inline:0 override above, same 1170px breakpoint). A
   sub-30px gap against an already-fixed 1170px row would solve
   repeat(4,1fr) to slightly OVER 270px per card (e.g. ~274px at a
   1280px window) instead of Figma's exact 270px. Freeze the gap to the
   flat Figma value in lockstep with the padding override so
   4x270 + 3x30 = 1170 holds exactly at every viewport from 1170px up,
   not just at the 1920px clamp endpoint — the same "freeze to the fixed
   spec value once the fluid range is exhausted" treatment the mobile
   slider below already gets (flex:0 0 270px, gap:10px, no clamp). */
@media (min-width: 1170px) {
	.ff-categories__grid {
		gap: 30px;
	}
}

@media (max-width: 640px) {
	/* Horizontal card slider — same scroll-snap technique as
	   .ff-promise__bullets / .ff-services__grid (see their comments for the
	   full rationale, including the min-width:0 flex-shrink trap). Figma
	   mobile row (109:781): HORIZONTAL auto-layout, NO_WRAP, itemSpacing
	   10, cards fixed 270px — on the 328px visible content width that's
	   one card fully in view plus a ~48px peek of the next. */
	.ff-categories__grid {
		display: flex;
		flex-wrap: nowrap;
		min-width: 0;
		gap: 10px;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		scroll-snap-type: x mandatory;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		-ms-overflow-style: none;
	}

	.ff-categories__grid::-webkit-scrollbar {
		display: none;
	}

	.ff-categories__card {
		flex: 0 0 270px;
		scroll-snap-align: start;
	}
}

/* Card component (e.g. desktop 38:1129/38:1130, mobile 109:782/109:783):
   270x253, 12px radius, #F6F5FC (bg-lavender) fill — pixel-identical on
   both Figma reference frames, so these are constants reused at every
   breakpoint (the grid/slider media queries above only change how cards
   are laid out relative to each other, never the card itself). Height is
   an explicit 253px (not auto/min-height): the photo is positioned
   absolute and so doesn't contribute to intrinsic height, and the body's
   own content (120px) is deliberately shorter than the card to leave room
   for the photo beneath/behind it. overflow:hidden clips each oversized
   photo <img> down to its card-photo window (see below). */
.ff-categories__card {
	position: relative;
	overflow: hidden;
	height: 253px;
	border-radius: 12px;
	background-color: var(--wp--preset--color--bg-lavender);
}

/* 24px uniform inset (e.g. desktop text frame 38:1131 vs card 38:1130).
   10px gap both above the list (heading->list) and this puts it above the
   absolutely-positioned photo so real content always wins over the photo
   in the (never actually reached, see below) case of a rounding overlap. */
.ff-categories__card-body {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	gap: 10px;
	padding: 24px;
}

/* Inter 600 20px/30px (150%), constant like the body inset — confirmed
   with the Range API that every one of the 8 category headings renders on
   a single line at the ~222px available width. */
.ff-categories__card-title {
	margin: 0;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 1.25rem;
	line-height: 1.5;
}

.ff-categories__card-list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

/* Inter 400 15px/20px (133%), constant — confirmed with the Range API
   that every list item across all 8 cards (incl. the two longest,
   "Воздушно-пузырчатая плёнка" / "Упаковка по требованиям МП") renders on
   a single line at the ~222px available width, so the card body is
   reliably 120px tall (30 heading + 10 gap + 3x(20 item + 10 gap)) and
   never reaches down into the photo's own area. */
.ff-categories__card-list li {
	color: var(--wp--preset--color--text-muted);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 0.9375rem;
	line-height: 1.3333;
}

/* The photo "window": each category's photo rectangle sits flush against
   the card's own bottom-right corner in full.json (offsetRight/
   offsetBottom both ~0px on all 8 cards), so every category shares the
   same right:0;bottom:0 anchor — only the window's own width/height
   differs per category (set below). Figure is the wp:image block's own
   wrapper, reused directly as the clipping window (overflow hidden). */
.ff-categories__card-photo {
	position: absolute;
	right: 0;
	bottom: 0;
	margin: 0;
	overflow: hidden;
}

/* The <img> itself is rendered oversized and pulled up/left with a
   negative offset so that only the product (not the empty canvas padding
   around it in the source file) shows inside the window above — solved
   per category from Figma's own imageTransform crop matrix, see the
   per-category rules below and the docblock in categories.php. */
.ff-categories__card-photo img {
	position: absolute;
	display: block;
	max-width: none;
}

/* Per-category window size + oversized-photo position. Values solved from
   full.json's imageTransform for each photo (window = target crop size;
   img width/height/left/top = the same crop re-expressed as "render the
   whole source image this big, then pull it up-left by this much" so the
   window shows only the cropped region). "food" needed its img height
   corrected to a uniform scale (vs. the raw transform's independently
   solved width/height) because the WP-uploaded asset's pixel aspect ratio
   doesn't quite match what Figma's own transform assumes (confirmed via
   canvas alpha-bbox comparison against the live file) — 4 of the
   remaining 7 (cosmetics/toys/clothes/bags) are the raw transform as-is
   (all under 1.1% axis distortion).

   tools/chemistry/dishes are a THIRD case, client-reported (screenshot
   diff) as cropping product more aggressively than the Figma reference:
   re-verified the raw transform is in fact pixel-exact Figma spec (pulled
   fresh from full.json, matches the shipped values to the hundredth), and
   the live WP asset's dimensions match the Figma-exported source exactly
   too (2000x1935 / 2000x1333 / 2000x1333, no food-style aspect drift) —
   so the crop MATH was never wrong. The actual issue: for these 3 photos
   specifically, Figma's own crop window keeps only a slice of a much
   wider flat-lay (canvas alpha-bbox showed the product's opaque bbox
   overflowing the crop rect by 946px/1136px/203px on one axis — i.e.
   whole tools/bottles physically outside the shown region, confirmed by
   rendering the crop back against the source file), which reads fine in
   Figma's own canvas at full size but is genuinely too tight once
   reproduced at real card size. Re-solved these 3 by uniform-covering the
   photo's FULL canvas into the window (same width:height ratio as the
   source, so no stretch) and re-centering horizontally on the product's
   actual opaque-pixel content (tools/dishes: full alpha bbox; chemistry:
   its denser left pair of bottles specifically, since the alpha bbox
   spans the entire 2000px canvas edge-to-edge across two disconnected
   clusters and the 61px-wide window can only ever fit one of them at a
   legible size — verified via column-density run detection, not just the
   bbox extremes). Re-verified post-fix content retained inside the crop:
   tools 96.3% of its bbox width (was 50.7%), chemistry 100% of the
   chosen cluster (was 28.6% of the full bimodal spread), dishes 100% of
   its bbox (was 77.8%) — all three previously had part of the product
   physically cut off, not just "tightly framed". */
.ff-categories__card--cosmetics .ff-categories__card-photo {
	width: 71px;
	height: 109px;
}

.ff-categories__card--cosmetics .ff-categories__card-photo img {
	width: 297.58px;
	height: 296.37px;
	left: -157.24px;
	top: -116.92px;
}

.ff-categories__card--toys .ff-categories__card-photo {
	width: 116px;
	height: 109px;
}

.ff-categories__card--toys .ff-categories__card-photo img {
	width: 163.2px;
	height: 163.01px;
	left: -11.28px;
	top: -21.16px;
}

.ff-categories__card--clothes .ff-categories__card-photo {
	width: 121px;
	height: 109px;
}

.ff-categories__card--clothes .ff-categories__card-photo img {
	width: 153.2px;
	height: 152.74px;
	left: -3.87px;
	top: -8.76px;
}

.ff-categories__card--bags .ff-categories__card-photo {
	width: 122px;
	height: 109px;
}

.ff-categories__card--bags .ff-categories__card-photo img {
	width: 159.79px;
	height: 239.26px;
	left: -5.27px;
	top: -72.61px;
}

.ff-categories__card--food .ff-categories__card-photo {
	width: 75px;
	height: 103px;
}

.ff-categories__card--food .ff-categories__card-photo img {
	width: 158.94px;
	height: 211.92px;
	left: -37.51px;
	top: -59.57px;
}

.ff-categories__card--tools .ff-categories__card-photo {
	width: 104px;
	height: 109px;
}

.ff-categories__card--tools .ff-categories__card-photo img {
	width: 112.66px;
	height: 109px;
	left: -4.08px;
	top: 0;
}

.ff-categories__card--chemistry .ff-categories__card-photo {
	width: 61px;
	height: 109px;
}

.ff-categories__card--chemistry .ff-categories__card-photo img {
	width: 163.54px;
	height: 109px;
	left: -8.63px;
	top: 0;
}

.ff-categories__card--dishes .ff-categories__card-photo {
	width: 96px;
	height: 94px;
}

.ff-categories__card--dishes .ff-categories__card-photo img {
	width: 141.04px;
	height: 94px;
	left: -28.69px;
	top: 0;
}

/* =======================================================================
   LEAD BANNER (purple CTA card with the ff-lead-form)
   Figma nodes: desktop 54:443 (Frame 427319111, 1170x483), mobile 109:846
   (Frame 427319146, 328x647). Card corner-radius (36px), panel corner-
   radius (40px), and every control's height (input/button 58px, submit
   icon circle 42px, checkbox 16px) are constant across both reference
   frames — not fluid — so they are fixed px here too. Only type sizes and
   the row->column layout switch change at the 767px breakpoint.
   ======================================================================= */

.ff-lead-banner {
	padding-top: clamp(1.5rem, 1rem + 2.2222vw, 2.5rem);
	padding-bottom: clamp(1.5rem, 1rem + 2.2222vw, 2.5rem);
	padding-inline: var(--ff-gutter);
}

/* Deficit lockstep, see --ff-gutter comment at the top of the file.
   :not(.alignfull): see .ff-steps's own identical fix above. */
.ff-lead-banner:not(.alignfull) {
	max-width: calc(1170px + (var(--ff-gutter) - 16px) * 2);
}

.ff-lead-banner__card {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	border-radius: 36px;
	/* 50/89/71/89 — full.json 54:443 says 105px sides (card is 1170 wide
	   there), but .ff-lead-banner's own max-width:1170 + padding-inline:16
	   (border-box) leaves only 1138px for this card, not 1170 — that 32px
	   deficit is a pre-existing property of the section wrapper, shared by
	   every other not-yet-redesigned section, and out of scope to change
	   here. 89px (105 - 16) keeps the panel/row inside at the JSON-exact
	   960px content width instead of drifting to 928px. Top/bottom (50/71)
	   are unaffected since that deficit is horizontal only. */
	padding: 50px 89px 71px;
	background: linear-gradient(95.92deg, #7B35BC 20.72%, #B796FE 115.05%);
}

/* Two client-exported decor SVGs (ex Figma "icon_3.svg" / "Union.svg"),
   flush with the card's own left and right edges — same absolute-layer
   technique as .ff-services__bg / .ff-calc__decor elsewhere in this file.
   Sits behind .ff-lead-banner__content (z-index:0 vs 1) and shows through
   the glass panel's backdrop-blur where the two overlap. */
.ff-lead-banner__card > .ff-lead-banner__decor {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
	border-radius: inherit;
}

.ff-lead-banner__decor img {
	position: absolute;
	display: block;
	max-width: none;
}

.ff-lead-banner__decor-left {
	left: 0;
	top: 62px;
	width: 222px;
	height: 288px;
}

.ff-lead-banner__decor-right {
	right: 0;
	bottom: 32px;
	width: 221px;
	height: 319px;
}

.ff-lead-banner__content {
	position: relative;
	z-index: 1;
}

.ff-lead-banner__title {
	margin: 0 0 30px;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.21;
	text-align: center;
	/* Desktop is always the single line from Figma — the 3 spans only do
	   something under the 767px override below. */
	white-space: nowrap;
}

.ff-lead-banner__desc {
	margin: 0 auto 39px;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	/* Fixed, not fluid: the 2nd sentence's natural wrap into exactly 2
	   lines (3 total with the 1st) only reproduces Figma's 54:463 at the
	   full 15px size within the 567px box below — the fluid clamp used
	   elsewhere undershoots just enough at sub-1920 desktop widths (e.g.
	   1280) to spill a 4th line. Desktop container is capped at the same
	   1170px from 1202px viewport all the way to 1920, so a fixed value
	   is also strictly more correct here, not just safer. */
	font-size: 0.9375rem;
	line-height: 20px;
	text-align: center;
	/* Figma 54:463 text-box width — narrower than the panel on purpose. */
	max-width: 567px;
}

/* Figma bakes a hard break after "года. " on desktop only (2 separate
   text runs); the 2nd run then wraps naturally within max-width above
   into 2 more lines (3 total). Mobile has no such break in the source. */
.ff-lead-banner__desc-line--2 {
	display: block;
}

.ff-lead-form__panel {
	display: flex;
	flex-direction: column;
	background-color: rgba(180, 142, 235, 0.4);
	border: 1px solid rgba(255, 255, 255, 0.2);
	border-radius: 40px;
	/* The actual "жидкое стекло" (glassmorphism) effect — Figma's
	   BACKGROUND_BLUR effect on the "Form" frame, radius 10. */
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	padding: 24px;
}

.ff-lead-form__row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 20px;
	margin-bottom: 33px;
}

.ff-lead-form__input {
	flex: 1 1 160px;
	min-width: 120px;
	height: 58px;
	border: none;
	border-radius: 999px;
	background-color: var(--wp--preset--color--white);
	padding-inline: 24px;
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 1.125rem;
	line-height: 1.21;
	color: var(--wp--preset--color--navy);
}

.ff-lead-form__input::placeholder {
	color: var(--wp--preset--color--placeholder-gray);
}

.ff-lead-form__submit {
	flex: 0 0 270px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	height: 58px;
	border: none;
	border-radius: 999px;
	background-color: var(--wp--preset--color--btn-muted);
	/* Figma: button label is white at 70% opacity, not solid white. */
	color: rgba(255, 255, 255, 0.7);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 600;
	font-size: 1rem;
	/* 87/8/8/8 — Figma's own (unusual but deliberate) padding on this
	   button; paired with justify-content:space-between it reproduces the
	   exact text/icon positions regardless of "Отправить"'s rendered
	   width, since both children sit flush against their own padding. */
	padding: 8px 8px 8px 87px;
	cursor: pointer;
	white-space: nowrap;
}

.ff-lead-form__submit::after {
	content: "";
	flex: 0 0 auto;
	width: 42px;
	height: 42px;
	border-radius: 50%;
	background-color: var(--wp--preset--color--white);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23854BFB' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='7' y1='17' x2='17' y2='7'/%3E%3Cpolyline points='7 7 17 7 17 17'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 45%;
}

.ff-lead-form__submit:hover,
.ff-lead-form__submit:focus {
	filter: brightness(1.08);
}

.ff-lead-form__consents {
	display: flex;
	flex-direction: column;
	gap: 14px;
	margin-top: 0;
}

.ff-lead-form__checkbox {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	cursor: pointer;
}

/* Custom box (Figma: 16x16, 2px corner radius, 1px white outline,
   transparent fill) — appearance:none replaces the native control so the
   shape matches; a checked state gets a solid white fill + purple tick. */
.ff-lead-form__checkbox input[type="checkbox"] {
	appearance: none;
	-webkit-appearance: none;
	flex: 0 0 auto;
	width: 16px;
	height: 16px;
	margin: 0;
	border: 1px solid rgba(255, 255, 255, 0.9);
	border-radius: 2px;
	background-color: transparent;
	cursor: pointer;
	position: relative;
}

.ff-lead-form__checkbox input[type="checkbox"]:checked {
	background-color: var(--wp--preset--color--white);
	border-color: var(--wp--preset--color--white);
}

.ff-lead-form__checkbox input[type="checkbox"]:checked::after {
	content: "";
	position: absolute;
	left: 4px;
	top: 1px;
	width: 4px;
	height: 8px;
	border: solid var(--wp--preset--color--btn-muted);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

.ff-lead-form__checkbox input[type="checkbox"]:focus-visible {
	outline: 2px solid rgba(255, 255, 255, 0.6);
	outline-offset: 2px;
}

.ff-lead-form__checkbox span {
	flex: 1 1 auto;
	min-width: 0;
	color: rgba(255, 255, 255, 0.6);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.75rem, 0.7212rem + 0.1282vw, 0.875rem);
	line-height: 16px;
	letter-spacing: -0.12px;
}

/* Figma styleOverrideTable: the linked phrase is UNDERLINE only, same
   color/weight as its surrounding text — so just inherit + underline. */
.ff-lead-form__checkbox a {
	color: inherit;
	text-decoration: underline;
}

.ff-lead-form__checkbox a:hover,
.ff-lead-form__checkbox a:focus-visible {
	opacity: 0.8;
}

/* Tablet "dead zone" (~768–975px): .ff-lead-form__row keeps flex-wrap:wrap
   and the submit button's fixed flex:0 0 270px basis (sometimes wider
   still — e.g. the article context's longer "Обсудить подготовку" label
   overflows 270px via the flex item's automatic min-width:auto floor), so
   once the row is too narrow for both inputs + button on one line, the
   button wraps onto its own line but stays only ~270-310px wide, orphaned
   flush against the left edge with empty space to its right — the 767px
   breakpoint below (which stacks everything full-width) doesn't kick in
   until well past that. Force just the button full-width the moment it
   wraps, independent of the mobile row/input restyle below, so the two
   inputs are free to stay side by side. 975px is the larger of two
   empirically measured wrap points — the homepage CTA banner
   (.ff-lead-banner) wraps at ≤904px, the narrower .ff-article-lead panel
   wraps at ≤975px — so one breakpoint covers both. */
@media (max-width: 975px) {
	.ff-lead-form__submit {
		flex: 1 1 auto;
		width: 100%;
	}

	/* Full-width state (mobile/tablet) breaks the desktop inline-button's
	   87px-left/space-between trick (tuned for a fixed 270px pill where the
	   label and circle sit flush against opposite edges): stretched to
	   100% width, that same padding strands [text+circle] on the left with
	   empty space on the right, and with a longer label (e.g. the article
	   form's "Обсудить подготовку") on a narrow viewport the content can
	   overflow the pill and clip the circle against the card's
	   overflow:hidden edge. Scoped to .ff-lead-banner__form — both the
	   homepage CTA banner and the article form carry that class — so the
	   calculator's own full-width submit (.ff-calc__contact-submit,
	   centered separately above) and the marketplace CTA
	   (.ff-mp-cta__submit) are untouched. (0,2,0) beats the base rule's
	   (0,1,0) regardless of source order. */
	.ff-lead-banner__form .ff-lead-form__submit {
		justify-content: center;
		gap: 10px;
		padding-left: 8px;
		padding-right: 8px;
	}
}

@media (max-width: 767px) {
	.ff-lead-banner__card {
		padding: 30px 16px;
		/* Client-supplied exact Figma Dev Mode "Copy as CSS" export — used
		   verbatim on every breakpoint (previously this recomputed the
		   angle per-breakpoint from frame geometry, which was an
		   approximation; the exact export takes precedence and is
		   intentionally identical to the desktop rule above). */
		background: linear-gradient(95.92deg, #7B35BC 20.72%, #B796FE 115.05%);
	}

	/* Figma mobile banner (109:846) has no left decor at all — only a
	   (non-uniformly scaled) copy of the right one, flush bottom-right.
	   Specificity note: needs to beat ".ff-lead-banner__decor img" (0,1,1),
	   so this repeats the "img" type selector rather than just the class
	   — same fix as .ff-services__bg img.ff-services__bg-right elsewhere
	   in this file. */
	.ff-lead-banner__decor img.ff-lead-banner__decor-left {
		display: none;
	}

	.ff-lead-banner__decor-right {
		right: 0;
		bottom: 0;
		width: 192px;
		height: 217px;
	}

	.ff-lead-banner__title {
		text-align: left;
		white-space: normal;
		font-size: 1.75rem;
		margin: 0 0 16px;
	}

	/* Figma mobile H1 (109:870) hard-wraps into exactly 3 lines that don't
	   emerge from natural word-wrap at this width/font — same nowrap-span
	   problem as .ff-hero__title, solved here by making each of the 3
	   phrases its own block instead of relying on width alone. */
	.ff-lead-banner__title-part {
		display: block;
	}

	.ff-lead-banner__desc {
		text-align: left;
		max-width: none;
		margin: 0 0 20px;
		font-size: 0.875rem;
		line-height: 18px;
	}

	/* No hard break on mobile (109:871 is one continuous run) — let the
	   2nd span flow inline with the 1st so the whole sentence wraps
	   naturally into ~4 lines instead of forcing desktop's break here. */
	.ff-lead-banner__desc-line--2 {
		display: inline;
	}

	.ff-lead-form__panel {
		/* 20/20/55/20 — Figma's own (asymmetric) padding on the 109:855
		   mobile "Form" frame; more breathing room below the 2nd checkbox
		   row than above the 1st input. */
		padding: 20px 20px 55px;
	}

	.ff-lead-form__row {
		flex-direction: column;
		align-items: stretch;
		gap: 12px;
		margin-bottom: 20px;
	}

	.ff-lead-form__input,
	.ff-lead-form__submit {
		flex: 1 1 auto;
		width: 100%;
	}

	.ff-lead-form__consents {
		gap: 20px;
	}

	.ff-lead-form__checkbox span {
		font-size: 0.75rem;
		letter-spacing: normal;
	}
}

/* =======================================================================
   ADVANTAGES ("Почему с нами работают" 2x2 card grid, gradient icon zone)

   Full-bleed #F6F5FC (see patterns/advantages.php's "align":"full" note),
   deliberately the exact same background-color/technique as .ff-staff
   right after it (which only picked up "align":"full" itself — no other
   rule below touches .ff-staff) so the two sections merge into one
   continuous lavender band with no white seam: same color, no inter-
   section margin (WordPress renders adjacent alignfull sections back to
   back by default in this theme, already relied on by ff-partners ->
   ff-marquee elsewhere). That merged-band treatment is from the client's
   reference screenshot (2026-07-20) — Figma's own file still shows this
   section on a plain white background.

   Card geometry below is exact _figma/full.json pixels: desktop node
   38:886 -> 66:1008 (title 54:476, grid 66:1007, cards 54:486/487/494/
   501 — each with Rectangle 30 "card bg", Rectangle 32 "gradient zone",
   an IMAGE-fill icon rect, and Frame 31 "title+desc") and mobile node
   100:176 -> 109:905 (title 109:875, grid 109:876, cards 109:877/884/
   891/898). Every clamp() interpolates linearly between the mobile
   Figma frame width (360px) and the desktop one (1920px) — the
   convention already used for e.g. .ff-services__title elsewhere in
   this file — so a measured "16px mobile -> 24px desktop" becomes
   clamp(1rem, 0.8846rem + 0.5128vw, 1.5rem), reaching exactly 16px at a
   360px viewport and exactly 24px at 1920px.
   ======================================================================= */

.ff-advantages {
	background-color: var(--wp--preset--color--bg-lavender);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
}

.ff-advantages__title {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	/* Figma title -> grid gap: 66px desktop (66:1008 title bottom 7900 vs
	   66:1007 grid top 7966) / 40px mobile (109:875 bottom 6298 vs
	   109:876 top 6338). */
	margin: 0 auto clamp(2.5rem, 2.125rem + 1.6667vw, 4.125rem);
}

/* Each of the 2 phrases making up the heading is nowrap-glued (same
   technique as .ff-partners__title-seg) so the mobile max-width below
   can force the exact "Почему с нами" / "работают" break instead of
   relying on the browser's own word-wrap to land there. Desktop has no
   max-width, so both segments always share one line — real Inter 600
   width measured in Chrome against this theme's own font file: 506.7px
   at 40px, comfortably inside the 1170px content column. */
.ff-advantages__title-seg {
	white-space: nowrap;
}

.ff-advantages__grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	/* Figma: 30px row+col gap desktop (570-wide cards 54:486/487 30px
	   apart; 480-tall cards 54:486/494 30px apart) / 20px mobile
	   (109:877..884 stacked cards 20px apart). */
	gap: clamp(1.25rem, 1.1058rem + 0.641vw, 1.875rem);
	align-items: stretch;
}

.ff-advantages__card {
	display: flex;
	flex-direction: column;
	background-color: var(--wp--preset--color--white);
	border-radius: 24px;
	overflow: hidden;
	/* No explicit height here: at desktop (2-column grid) every card in
	   Figma is fixed to 480px regardless of its own description's 1- vs
	   2-line height (e.g. 54:486's Frame 31 is 66px tall vs 54:487's
	   86px) — CSS Grid's default align-items:stretch reproduces that for
	   free by stretching every card to match the tallest one in its row.
	   At mobile (1-column grid below) each row holds exactly one card,
	   so "stretch" is a no-op and cards fall back to their own auto
	   height — matching Figma's own per-card mobile heights, which are
	   NOT uniform either (109:877/884/891/898 are 388/362/382/366px). */
}

.ff-advantages__card-icon-zone {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	border-radius: 24px 24px 0 0;
	overflow: hidden;
	/* Client's literal Dev-Mode CSS formula (confirmed 2026-07-20) per
	   the CLAUDE.md gradient rule — applied verbatim to all 4 cards, NOT
	   recomputed from Figma's own Rectangle 32 fills, which vary slightly
	   card to card (e.g. card 1 "24 1" starts #FFFFFF, card 2 "Свои
	   склады" starts #F6EBFF; both end #E4CEF6) and are not what the
	   client wants shipped. */
	background: radial-gradient(50% 50% at 50% 50%, #F6EBFF 0%, #E4CEF6 100%);
	/* Figma Rectangle 32: 330px desktop (54:482) / 248px mobile
	   (109:882), both 24px top-only corner radius. */
	height: clamp(15.5rem, 14.3173rem + 5.2564vw, 20.625rem);
}

/* Reset the figure's default browser/core margin so it doesn't skew the
   icon-zone's own flex centering above. */
.ff-advantages__card-icon {
	margin: 0;
}

.ff-advantages__card-icon-zone img {
	display: block;
	width: auto;
	/* The one number that's actually consistent across all 4 icon rects
	   in Figma is height (300px desktop / 248px mobile) — width varies
	   293-342px desktop because each rect was individually stretched
	   over its source PNG (scaleMode STRETCH with a per-icon transform),
	   not a shared crop aspect, so it's not a reliable per-card value
	   (see the imageTransform comparison this was derived from). All 4
	   source PNGs already in the media library are 1268-1500px square-
	   ish originals (exact match for _figma/images' own files by
	   imageRef), so flex-centering a fixed-height/auto-width render of
	   each in the zone above reproduces Figma's vertical centering
	   (15px inset desktop = (330-300)/2, 0 inset mobile = 248-248)
	   without distorting any of them, at a fraction of their natural
	   pixel size (no upscaling). */
	height: clamp(15.5rem, 14.75rem + 3.3333vw, 18.75rem);
}

.ff-advantages__card-body {
	display: flex;
	flex-direction: column;
	gap: 16px;
	/* Figma Frame 31 vs its card: ~24px sides desktop (54:479 vs 54:486)
	   / 16px sides mobile (109:879 vs 109:877, exact); zone-to-text gap
	   40px desktop (54:482 bottom 8296 -> 54:479 top 8335) / 16px mobile
	   (109:882 bottom 6586 -> 109:879 top 6602); bottom padding 24px
	   desktop minimum (54:487 card: text bottom 8422 vs card bottom
	   8446) / 16px mobile exact (109:877: text bottom 6710 vs card
	   bottom 6726) — shorter descriptions just leave more blank space
	   above the card's own bottom edge (see .ff-advantages__card above,
	   no separate rule needed for that). */
	padding: clamp(1rem, 0.6538rem + 1.5385vw, 2.5rem) clamp(1rem, 0.8846rem + 0.5128vw, 1.5rem) clamp(1rem, 0.8846rem + 0.5128vw, 1.5rem);
}

.ff-advantages__card-title {
	margin: 0;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.25rem, 1.1923rem + 0.2564vw, 1.5rem);
	/* Figma: 30/24 = 1.25 desktop (54:480), 26/20 = 1.3 mobile (109:880). */
	line-height: 1.25;
}

.ff-advantages__card-desc {
	margin: 0;
	color: var(--wp--preset--color--text-muted);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.875rem, 0.8606rem + 0.0641vw, 0.9375rem);
	/* Figma: 20/15 = 1.3333 desktop (54:481), 20/14 = 1.4286 mobile (109:881). */
	line-height: 1.3333;
}

@media (max-width: 640px) {
	.ff-advantages__title {
		/* Sized to fit "Почему с нами" (measured 212.2px, real Inter 600
		   28px against this theme's own font file) with a buffer, well
		   short of fitting "работают" too (measured 354.7px combined) —
		   see .ff-advantages__title-seg above. */
		max-width: 240px;
		line-height: 1.0714;
	}

	.ff-advantages__grid {
		grid-template-columns: 1fr;
	}

	.ff-advantages__card-title {
		line-height: 1.3;
	}

	.ff-advantages__card-desc {
		line-height: 1.4286;
	}
}

/* =======================================================================
   SHIPPING ("Доставка и расчёты" — feature-list cards + truck photo)

   GEOMETRY — _figma/full.json desktop 38:886 -> 111:963 (title 38:1069,
   row 111:962, card1 "Frame 58" 38:1205, card2 "Frame 59" 38:1221, photo
   "Rectangle 20" 38:1204) and mobile 100:176 -> 111:964 (title 111:965,
   content 111:966, cards 111:968/111:984, photo "Rectangle 20" 111:997).
   Cards: #F6F5FC (bg-lavender) fill, #ECECF5 (bg-soft) 1px inset border,
   24px radius/padding — identical at both frames. Icon+title header gap
   is genuinely different per card in Figma (16px "Отгрузка", 10px
   "Способы оплаты" — confirmed identical on both reference frames, not a
   measurement artifact), reproduced via the --oplata modifier below.
   Icons are the client's exported SVGs (assets/img/shipping-otgruzka.svg
   / shipping-oplata.svg) — already self-contained 44x44 art with their
   own baked-in light-purple rounded-square gradient backdrop (matches
   Figma's "Background" node: linear-gradient #8E73FE 14%->4% opacity,
   11px corner radius), same "no extra CSS backdrop needed" treatment as
   patterns/promise.php's bullet icons. List bullets are plain CSS dots
   (Figma's own text nodes carry no bullet glyph/shape; "буллеты-точки"
   per client reference, text content unchanged). Photo column:
   object-fit:cover stretched to match the card column's full height
   desktop (row 574px both sides, 30px gap — same 20->30 clamp as
   .ff-advantages__grid's gap); mobile Rectangle 20 sits below the
   stacked cards at ~1:1 aspect (329x331), full width.
   ======================================================================= */

.ff-shipping {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
}

/* Deficit lockstep, see --ff-gutter comment at the top of the file.
   :not(.alignfull): see .ff-steps's own identical fix above. */
.ff-shipping:not(.alignfull) {
	max-width: calc(1170px + (var(--ff-gutter) - 16px) * 2);
}

.ff-shipping__title {
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	margin: 0 auto clamp(1.5rem, 1.0673rem + 1.9231vw, 3.375rem);
}

.ff-shipping__row {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	align-items: stretch;
	gap: clamp(1.25rem, 1.1058rem + 0.641vw, 1.875rem);
}

.ff-shipping__text {
	display: flex;
	flex-direction: column;
	gap: clamp(1.25rem, 1.1058rem + 0.641vw, 1.875rem);
	flex: 1 1 460px;
	max-width: 570px;
}

.ff-shipping__block {
	display: flex;
	flex-direction: column;
	gap: 16px;
	background-color: var(--wp--preset--color--bg-lavender);
	border: 1px solid var(--wp--preset--color--bg-soft);
	border-radius: 24px;
	padding: 24px;
}

.ff-shipping__block-head {
	display: flex;
	align-items: center;
	gap: 16px;
}

.ff-shipping__block--oplata .ff-shipping__block-head {
	gap: 10px;
}

.ff-shipping__block-icon {
	margin: 0;
	flex: 0 0 auto;
}

.ff-shipping__block-icon img {
	display: block;
	width: 44px;
	height: 44px;
}

.ff-shipping__block-title {
	margin: 0;
	color: var(--wp--preset--color--text-dark);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 700;
	font-size: clamp(1rem, 0.9423rem + 0.2564vw, 1.25rem);
	line-height: 1.3;
}

.ff-shipping__list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.ff-shipping__list li {
	position: relative;
	padding-left: 14px;
	color: var(--wp--preset--color--text-dark);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.875rem, 0.8606rem + 0.0641vw, 0.9375rem);
	line-height: 1.4;
}

.ff-shipping__list li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.55em;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background-color: var(--wp--preset--color--brand-soft);
}

.ff-shipping__photo {
	flex: 1 1 480px;
	max-width: 570px;
	margin: 0;
	align-self: stretch;
}

.ff-shipping__photo img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 24px;
}

@media (max-width: 640px) {
	.ff-shipping__title {
		text-align: left;
	}

	.ff-shipping__row {
		flex-direction: column;
		align-items: stretch;
	}

	.ff-shipping__text,
	.ff-shipping__photo {
		max-width: none;
	}

	.ff-shipping__photo img {
		height: auto;
		aspect-ratio: 329 / 331;
	}
}

/* =======================================================================
   FOOTER
   Figma desktop (38:886 -> 38:1442 "Frame 2534", 1920x408) and mobile
   (100:176 -> 111:1123, 360x574): full-bleed #110041 bar, content pinned
   with absolute-positioning-derived (not centered) top/bottom padding —
   70/23px desktop, 50/24px mobile. Structure mirrors the Figma auto-layout
   nesting exactly (brand | navcontact[ navs[services,nav] | contact ]) so
   each level only ever needs ONE gap value instead of juggling 3 unequal
   gaps in a single flat row.
   ======================================================================= */

.ff-footer {
	background-color: var(--wp--preset--color--footer-bg);
	padding-top: 70px;
	padding-bottom: 23px;
	padding-inline: var(--ff-gutter);
}

.ff-footer__inner {
	max-width: 1170px;
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: 73px;
}

/* None of these groups declare a block "layout" attribute (they're plain
   wp:group wrappers, purely CSS-driven below), so WordPress renders them
   as the default is-layout-flow — which injects its own
   `margin-block-start: var(--wp--style--block-gap, 24px)` on every
   non-first child via a core :where(.is-layout-flow) > * + * rule. That
   fought with every gap value below (e.g. .ff-footer__col's 2nd child —
   the link list — landed 44px from the title: 20px gap + the stray 24px
   margin). All spacing here is intentionally done with flex `gap`, so
   zero out the margin WP adds on top of it. */
.ff-footer__row > *,
.ff-footer__brand > *,
.ff-footer__navcontact > *,
.ff-footer__navs > *,
.ff-footer__col > *,
.ff-footer__contact > * {
	margin-block: 0;
}

/* Figma "Frame 2532": brand (fixed 370) + a 30px gap + the nav/contact
   cluster (770, hugged) — 370+30+770 = 1170 exactly, so the row always
   fills the content column with zero leftover; no justify-content needed. */
.ff-footer__row {
	display: flex;
	align-items: flex-start;
	gap: 30px;
}

.ff-footer__brand {
	display: flex;
	flex-direction: column;
	gap: 12px;
	width: 370px;
	flex-shrink: 0;
}

.ff-footer__logo img {
	display: block;
	height: 31px;
	width: auto;
	/* recolor the black-on-transparent logo mark to white for the dark footer */
	filter: brightness(0) invert(1);
}

.ff-footer__tagline {
	margin: 0;
	color: var(--wp--preset--color--muted-purple);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 400;
	font-size: 0.8125rem;
	line-height: 18px;
}

/* Figma hard-breaks "с 2019 года." onto its own line — an explicit \n in
   the text node, not emergent word-wrap — reproduced with a literal <br>
   in the markup (same technique as patterns/promise.php's bullet labels)
   plus nowrap here so the 2-word phrase itself can never re-split. */
.ff-footer__tagline-year {
	white-space: nowrap;
}

/* Figma "Frame 2531": the two link columns + contact block. Desktop: row,
   201px gap. Mobile: column, 44px gap (900px override below). */
.ff-footer__navcontact {
	display: flex;
	align-items: flex-start;
	gap: 201px;
}

/* Figma "Frame 88": Услуги + Навигация, always side by side — only the gap
   between them changes (101px desktop, 0 on mobile). */
.ff-footer__navs {
	display: flex;
	align-items: flex-start;
	gap: 101px;
}

.ff-footer__col {
	display: flex;
	flex-direction: column;
	gap: 20px;
}

.ff-footer__col--services {
	width: 199px;
	flex-shrink: 0;
}

.ff-footer__col--nav {
	width: 99px;
	flex-shrink: 0;
}

.ff-footer__col-title {
	margin: 0;
	color: var(--wp--preset--color--muted-purple);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 400;
	font-size: 1rem;
	line-height: 1.125;
}

.ff-footer__nav .wp-block-navigation-item__content.wp-block-navigation-item__content {
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 400;
	font-size: 0.8125rem;
	line-height: 18px;
	padding: 0;
}

.ff-footer__nav .wp-block-navigation__container {
	gap: 6px;
}

.ff-footer__nav .wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--white);
	opacity: 0.75;
}

.ff-footer__contact {
	display: flex;
	flex-direction: column;
	gap: 11px;
	width: 170px;
	flex-shrink: 0;
	text-align: right;
}

.ff-footer__phone,
.ff-footer__email {
	margin: 0;
}

.ff-footer__phone a,
.ff-footer__email a {
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 600;
	font-size: 1rem;
	line-height: 1.125;
	text-decoration: none;
}

.ff-footer__email a {
	opacity: 0.8;
}

.ff-footer__copyright {
	margin: 0;
	text-align: center;
	color: var(--wp--preset--color--footer-copy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 0.8125rem;
	line-height: 18px;
}

@media (max-width: 900px) {
	.ff-footer {
		padding-top: 50px;
		padding-bottom: 24px;
	}

	.ff-footer__inner {
		gap: 30px;
	}

	.ff-footer__row {
		flex-direction: column;
		align-items: stretch;
	}

	.ff-footer__brand {
		width: auto;
	}

	.ff-footer__tagline {
		font-size: 0.75rem;
		line-height: 16px;
	}

	.ff-footer__navcontact {
		flex-direction: column;
		align-items: stretch;
		gap: 44px;
	}

	.ff-footer__navs {
		gap: 0px;
	}

	.ff-footer__contact {
		align-self: center;
		text-align: center;
	}
}

/* Баг «колонка контактов уезжает за экран» на планшетных и узких
   десктопных ширинах: на 901-1265px --ff-gutter уже подрос настолько,
   что .ff-footer__inner (max-width:1170) сам ужимается (это ожидаемо,
   см. комментарий про --ff-gutter в начале файла), а .ff-footer__row
   всё ещё в режиме row — на column переключаемся только <=900px (блок
   выше). Раньше и brand (370px, flex-shrink:0), и navcontact (жёстко
   hugged на 770 = навы 399 + гэп 201 + контакты 170) не умели
   сжиматься вообще, поэтому 1170px макетного содержимого вылезали за
   правый край уже более узкого контейнера. Чиним сжатием по
   приоритету: сначала гэп между навигацией и контактами (201px -> пол
   24px — пол держит min-width на navcontact через сам флекс-алгоритм,
   justify-content: space-between довешивает остаток сверх пола), и
   только когда гэп уже упёрся в пол — сама колонка brand (370px -> пол
   190px, чуть шире лого 170px). Оба пола подобраны так, что при любом
   реальном сочетании окно/скроллбар переполнения не будет (проверено
   на боевом на 901px — самой тесной точке диапазона). На >=1266px
   контейнер уже сам умещает 1170 без сжатия — там снова работают
   исходные макетные величины без изменений (правило выше, без медиа). */
@media (min-width: 901px) and (max-width: 1265px) {
	.ff-footer__brand {
		flex: 0 1 370px;
		min-width: 190px;
	}

	.ff-footer__navcontact {
		flex: 0 1 770px;
		min-width: 593px;
		gap: 24px;
		justify-content: space-between;
	}
}

/* =======================================================================
   Small-viewport layout switches shared across sections
   ======================================================================= */

@media (max-width: 767px) {
	.ff-header__inner {
		flex-wrap: nowrap;
	}
}

/* =======================================================================
   SHARED LEAD FORM FEEDBACK (banner + calculator forms both use these —
   submit-button label swap lives in JS, this is the status line + the
   invalid-field highlight assets/js/forms.js toggles).
   ======================================================================= */

.ff-lead-form__status {
	margin: 10px 0 0;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.8125rem;
	line-height: 1.4;
	min-height: 1px;
}

.ff-lead-form__status--success {
	color: var(--wp--preset--color--white);
	font-weight: 600;
}

.ff-lead-form__status--error {
	color: #ffd8d8;
	font-weight: 600;
}

.ff-lead-form__input.is-invalid {
	box-shadow: 0 0 0 2px var(--wp--preset--color--accent-red) inset;
}

.ff-lead-form__checkbox.is-invalid span {
	color: var(--wp--preset--color--accent-red);
}

/* Honeypot — present in the DOM for bots to fill in, invisible and
   unreachable (aria-hidden + tabindex -1) for real visitors. */
.ff-hp-field {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

/* =======================================================================
   CALCULATOR ("Рассчитайте стоимость фулфилмента", #calc)
   ======================================================================= */

.ff-calc {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
	scroll-margin-top: 20px;
}

/* Deficit lockstep, see --ff-gutter comment at the top of the file.
   :not(.alignfull): see .ff-steps's own identical fix above. */
.ff-calc:not(.alignfull) {
	max-width: calc(1170px + (var(--ff-gutter) - 16px) * 2);
}

.ff-calc__title {
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	/* Figma's calc-heading text box (38:1070 desktop / 103:311 mobile) is a
	   fixed-width column — 510px desktop, 327px mobile — same
	   width-constrained treatment as the marketplaces heading above
	   (.ff-partners__title), just a different pixel width since this
	   heading's own text is shorter. */
	max-width: clamp(20.4375rem, 17.798rem + 11.7308vw, 31.875rem);
	margin: 0 auto clamp(1.25rem, 1.1058rem + 0.641vw, 1.875rem);
}

.ff-calc__subtitle {
	color: #555555;
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.875rem, 0.8606rem + 0.0641vw, 0.9375rem);
	line-height: 1.33;
	max-width: clamp(20.4375rem, 17.798rem + 11.7308vw, 31.875rem);
	margin: 0 auto clamp(2.5rem, 2.3558rem + 0.641vw, 3.125rem);
}

.ff-calc__card {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	max-width: 720px;
	width: 100%;
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: 26px;
	background: linear-gradient(180deg, #6537B0 0%, #361D6A 100%);
	border-radius: clamp(1.5rem, 1.3269rem + 0.7692vw, 2.25rem);
	padding: clamp(1.5rem, 1.2692rem + 1.0256vw, 2.5rem) clamp(1rem, 0.6538rem + 1.5385vw, 2.5rem);
	box-shadow: 0 30px 60px rgba(54, 29, 106, 0.25);
}

.ff-calc__card::before,
.ff-calc__card::after {
	content: "";
	position: absolute;
	border-radius: 50%;
	background: radial-gradient(circle, rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0) 70%);
	filter: blur(40px);
	z-index: 0;
	pointer-events: none;
}

.ff-calc__card::before {
	width: 280px;
	height: 280px;
	left: -10%;
	top: -12%;
}

.ff-calc__card::after {
	width: 320px;
	height: 320px;
	right: -12%;
	bottom: -18%;
}

.ff-calc__card > * {
	position: relative;
	z-index: 1;
}

/* Two decorative outline shapes exported from Figma (Icon_1.svg 349x297,
   icon_3.svg 205x316, white fill at 7% opacity baked into the SVG paths).
   Positions are the offset between each shape's absoluteBoundingBox and
   the card's own, straight from _figma/full.json — desktop node 47:674
   (top-right, flush with the card's right edge) and 47:668 (bottom-left,
   already clipped to its visible 205px sliver by the card edge in Figma
   itself). Higher specificity than ".ff-calc__card > *" so it wins over
   that rule's position/z-index. */
.ff-calc__card > .ff-calc__decor {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
	border-radius: inherit;
}

.ff-calc__decor img {
	position: absolute;
	display: block;
	max-width: none;
}

.ff-calc__decor-1 {
	top: 80px;
	right: 0;
	width: 349px;
	height: 297px;
}

.ff-calc__decor-2 {
	top: 925px;
	left: 0;
	width: 205px;
	height: 316px;
}

/* --- Step 1: category / qty / dimensions ------------------------------ */

.ff-calc__fields {
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.ff-calc__step-label {
	margin: 0;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 1rem;
}

.ff-calc__row {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 16px;
}

.ff-calc__field {
	display: flex;
	flex-direction: column;
	gap: 6px;
	min-width: 0;
}

/* This field is the lone child of its own .ff-calc__row (2-col grid) —
   without an explicit span it only fills the first 1fr track (half width).
   Pre-existing layout bug (not introduced by this pass): the 3 dimension
   inputs were being squeezed into half the card's content width instead
   of using the full row, same on both breakpoints. */
.ff-calc__field--dims {
	grid-column: 1 / -1;
}

.ff-calc__field-label {
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.8125rem;
}

.ff-calc__dims {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 12px;
}

.ff-calc__select,
.ff-calc__input,
.ff-calc__dropdown-trigger {
	width: 100%;
	min-width: 0;
	height: 48px;
	border: none;
	border-radius: 12px;
	background-color: var(--wp--preset--color--white);
	padding-inline: 16px;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 1rem;
	color: var(--wp--preset--color--navy);
	transition: box-shadow 0.15s ease;
}

.ff-calc__select::placeholder,
.ff-calc__input::placeholder {
	color: #a1a1a1;
}

/* Plain number fields, no spinner arrows — the design has no room for
   them and they clash with the custom dropdown/pill aesthetic. */
.ff-calc__input[type="number"] {
	appearance: textfield;
	-moz-appearance: textfield;
}

.ff-calc__input::-webkit-outer-spin-button,
.ff-calc__input::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.ff-calc__select:hover,
.ff-calc__input:hover,
.ff-calc__dropdown-trigger:hover {
	box-shadow: 0 0 0 1px rgba(133, 75, 251, 0.28);
}

.ff-calc__select:focus-visible,
.ff-calc__input:focus-visible,
.ff-calc__dropdown-trigger:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.4);
}

.ff-calc__dim-sum {
	margin: 2px 0 0;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 0.8125rem;
}

/* --- Custom "Категория товара" dropdown --------------------------------
   A real <select class="ff-calc__select--native"> stays in the DOM
   (styled like any other field above) as the form-fallback control;
   calculator.js progressively enhances it into this button+listbox and
   keeps the two in sync — see initCategoryDropdown() there. */

.ff-calc__dropdown {
	position: relative;
}

/* Stacking-context fix: ".ff-calc__card > *" (top of this file) gives every
   direct child of the card — .ff-calc__fields, .ff-calc__group (x2),
   .ff-calc__result, .ff-calc__contact — the SAME z-index:1. That makes each
   one its own stacking context, painted atomically in DOM order, so a
   *later* sibling (e.g. the services checklist, .ff-calc__group) always
   paints over the ENTIRETY of an earlier one (.ff-calc__fields) regardless
   of how high a z-index something nested inside .ff-calc__fields declares
   — nested z-index only wins fights inside that local stacking context, it
   cannot escape it. The open dropdown-panel below is nested three levels
   inside .ff-calc__fields and is position:absolute (so it doesn't grow
   .ff-calc__fields' own box), which means whatever card content comes
   after .ff-calc__fields in the DOM used to render on top of the open
   panel wherever the two visually overlapped — the reported "dropdown
   blends into the fields below it" bug. calculator.js toggles this class on
   the .ff-calc__fields ancestor for as long as the panel is open, bumping
   *that whole stacking context* above its card-level siblings so the panel
   (and everything else in .ff-calc__fields) reliably paints on top of them.
   Selector is written at full ".ff-calc__card > .ff-calc__fields…"
   specificity so it deterministically beats ".ff-calc__card > *" (same
   0,1,0 specificity otherwise, which would fall back to source order). */
.ff-calc__card > .ff-calc__fields.ff-calc__fields--dropdown-open {
	z-index: 20;
}

.ff-calc__dropdown-trigger {
	display: none;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	cursor: pointer;
	text-align: left;
}

.ff-calc__dropdown.is-enhanced .ff-calc__dropdown-trigger {
	display: flex;
}

.ff-calc__dropdown.is-enhanced .ff-calc__select--native {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
	padding: 0;
}

.ff-calc__dropdown-value {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ff-calc__dropdown-chevron {
	flex: 0 0 auto;
	color: #767676;
	transition: transform 0.15s ease;
}

.ff-calc__dropdown.is-open .ff-calc__dropdown-chevron {
	transform: rotate(180deg);
}

.ff-calc__dropdown.is-open .ff-calc__dropdown-trigger {
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.4);
}

.ff-calc__dropdown-panel {
	position: absolute;
	top: calc(100% + 6px);
	left: 0;
	right: 0;
	/* High relative to every other element inside .ff-calc__fields' own
	   stacking context (all z-index:auto) — combined with the
	   ".ff-calc__fields--dropdown-open" bump above, this guarantees the
	   panel paints above every field/row AND above every later card
	   section, fully opaque, never blended with what's underneath. */
	z-index: 60;
	margin: 0;
	padding: 6px;
	list-style: none;
	background-color: var(--wp--preset--color--white);
	opacity: 1;
	border-radius: 12px;
	box-shadow: 0 20px 45px rgba(26, 15, 61, 0.28), 0 4px 12px rgba(26, 15, 61, 0.15);
	max-height: 260px;
	overflow-y: auto;
}

.ff-calc__dropdown-option {
	padding: 10px 12px;
	border-radius: 8px;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.9375rem;
	color: var(--wp--preset--color--navy);
	cursor: pointer;
}

.ff-calc__dropdown-option:hover,
.ff-calc__dropdown-option:focus-visible {
	background-color: var(--wp--preset--color--bg-lavender);
	outline: none;
}

.ff-calc__dropdown-option.is-selected {
	background-color: var(--wp--preset--color--bg-soft);
	color: var(--wp--preset--color--brand-deep);
	font-weight: 600;
}

/* --- Step 2: service checklist ----------------------------------------- */

.ff-calc__group {
	list-style: none;
	margin: 0;
	padding: 0;
}

.ff-calc__group-label {
	margin: 4px 0 -6px;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 500;
	font-size: 0.875rem;
}

/* Main ("always-on") services: solid white cards, dark text — the four
   rows pre-checked by default (ff-calc__service--default). */
.ff-calc__service {
	position: relative;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px 12px;
	padding: 19px 18px;
	margin-bottom: 10px;
	border-radius: 12px;
	background-color: var(--wp--preset--color--white);
	cursor: pointer;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 400;
	font-size: 1rem;
	line-height: 1.35;
	transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.ff-calc__group > .ff-calc__service:last-child {
	margin-bottom: 0;
}

.ff-calc__service:hover {
	box-shadow: 0 6px 16px rgba(21, 12, 67, 0.14);
}

.ff-calc__service:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.45);
}

/* Price stays plain text inside the row (editors edit it in place); this
   span only carries the lighter/smaller Figma treatment. sumRubles()/
   labelOf() in calculator.js read .textContent, which flattens it, so it
   never affects parsing. */
.ff-calc__price {
	color: #999999;
	font-size: 0.8125rem;
}

.ff-calc__service::before {
	content: "";
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	border-radius: 4px;
	border: 1.5px solid #d9d4ee;
	background-color: #fff;
	background-repeat: no-repeat;
	background-position: center;
	background-size: 62%;
	transition: background-color 0.15s ease, border-color 0.15s ease;
}

.ff-calc__service.is-checked::before {
	background-color: var(--wp--preset--color--brand-soft);
	border-color: var(--wp--preset--color--brand-soft);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='5 13 10 18 19 7'/%3E%3C/svg%3E");
}

/* Additional/optional services: transparent rows with a translucent
   outline (Figma: 1px stroke rgb(232,227,255) on a fill-less card — reads
   as a soft light line against the purple gradient), white text. */
.ff-calc__group--outline .ff-calc__service {
	background-color: transparent;
	border: 1px solid #e8e3ff;
	padding: 18px 17px;
	color: var(--wp--preset--color--white);
}

.ff-calc__group--outline .ff-calc__service:hover {
	box-shadow: none;
	border-color: rgba(255, 255, 255, 0.6);
}

.ff-calc__group--outline .ff-calc__price {
	color: rgba(255, 255, 255, 0.7);
}

.ff-calc__group--outline .ff-calc__service::before {
	background-color: transparent;
	border-color: rgba(255, 255, 255, 0.55);
}

.ff-calc__group--outline .ff-calc__service.is-checked::before {
	background-color: var(--wp--preset--color--brand-soft);
	border-color: var(--wp--preset--color--brand-soft);
}

/* "Маркировка" row's ШК / ЧЗ / ШК+ЧЗ price chips — Figma renders these as
   a plain radio (small ring + dark label), not pill/chip shapes. */
.ff-calc__options {
	list-style: none;
	margin: 4px 0 0;
	padding: 0 0 0 30px;
	flex: 1 0 100%;
	display: flex;
	flex-wrap: wrap;
	column-gap: 20px;
	row-gap: 8px;
	max-height: 160px;
	overflow: hidden;
	opacity: 1;
	transform: none;
	transition:
		max-height 0.22s ease,
		opacity 0.18s ease,
		transform 0.22s ease,
		margin 0.22s ease;
}

.ff-calc.is-calculator-ready .ff-calc__options {
	opacity: 0;
	transform: translateY(-4px);
}

.ff-calc.is-calculator-ready .ff-calc__options.is-visible {
	opacity: 1;
	transform: none;
}

.ff-calc__options[hidden] {
	display: none !important;
}

.editor-styles-wrapper .ff-calc__options--conditional {
	display: flex !important;
	opacity: 1 !important;
	transform: none !important;
}

.ff-calc__group--outline .ff-calc__option {
	color: var(--wp--preset--color--white);
}

.ff-calc__group--outline .ff-calc__option::before {
	border-color: rgba(255, 255, 255, 0.72);
	background-color: transparent;
}

.ff-calc__group--outline .ff-calc__option.is-active::before {
	border-color: var(--wp--preset--color--white);
	background-color: var(--wp--preset--color--brand-soft);
}

.ff-calc__option {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	/* Visual radio+label is small (Figma: 13px dot + 14px text) but the
	   click/tap target needs to clear the ~40px minimum — vertical padding
	   grows the hit area (a *plain* padding, not padding+negative-margin,
	   so it can't overlap the price/label line sitting right above this
	   options row). */
	padding: 11px 2px;
	cursor: pointer;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-size: 0.875rem;
}

.ff-calc__option::before {
	content: "";
	flex: 0 0 auto;
	width: 13px;
	height: 13px;
	border-radius: 50%;
	border: 1px solid #767676;
	background-color: #fff;
	transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.ff-calc__option:focus-visible {
	outline: none;
}

.ff-calc__option:focus-visible::before {
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.4);
}

.ff-calc__option.is-active {
	font-weight: 500;
}

.ff-calc__option.is-active::before {
	border-color: var(--wp--preset--color--brand-soft);
	background-color: var(--wp--preset--color--brand-soft);
	box-shadow: inset 0 0 0 2.5px #fff;
}

.ff-calc__option.is-active:focus-visible::before {
	box-shadow: inset 0 0 0 2.5px #fff, 0 0 0 3px rgba(133, 75, 251, 0.4);
}

/* --- Result box ---------------------------------------------------------- */

.ff-calc__result {
	background-color: var(--wp--preset--color--white);
	border-radius: 14px;
	padding: clamp(1rem, 0.8462rem + 0.6410vw, 1.5rem);
}

.ff-calc__result-row {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	align-items: flex-start;
	gap: 12px 20px;
}

.ff-calc__result-total,
.ff-calc__result-unit {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.ff-calc__result-unit {
	text-align: right;
}

.ff-calc__result-label {
	color: #555555;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.875rem;
}

.ff-calc__result-value {
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 700;
	white-space: nowrap;
}

.ff-calc__result-value--total {
	color: var(--wp--preset--color--brand-light);
	font-size: 1.75rem;
}

.ff-calc__result-value--unit {
	color: var(--wp--preset--color--navy);
	font-size: 1.25rem;
}

/* Upsell banner: light green (Figma: subtle green gradient fill + 1px
   solid green stroke), not the brand-purple pill it was before. */
.ff-calc__upsell {
	margin: 16px 0 0;
	padding: 16px 19px;
	border-radius: 12px;
	background: linear-gradient(90deg, rgba(76, 175, 80, 0.12), rgba(76, 175, 80, 0.06));
	border: 1px solid #4caf50;
	color: #555555;
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 500;
	font-size: 0.8125rem;
	text-align: left;
}

.ff-calc__breakdown {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-top: 16px;
}

.ff-calc__breakdown:empty {
	margin-top: 0;
}

.ff-calc__breakdown-line {
	margin: 0;
	color: #343434;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.875rem;
	line-height: 1.4;
}

.ff-calc__breakdown-line--unknown {
	padding: 8px 10px;
	border-radius: 8px;
	background: #fff7e8;
	color: #7a4b00;
}

.ff-calc__result-disclaimer {
	margin: 16px 0 0;
	color: #999999;
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.8125rem;
	line-height: 1.4;
}

@media (max-width: 560px) {
	.ff-calc__result-row {
		flex-direction: column;
	}

	.ff-calc__result-unit {
		text-align: left;
	}
}

/* --- Step 3: contact form ------------------------------------------------ */

.ff-calc__contact {
	display: flex;
	flex-direction: column;
}

.ff-calc__contact-row {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin: 14px 0 16px;
}

/* Step-3 inputs sit on the purple card, not the white banner these
   classes normally live on (.ff-lead-form__input) — translucent light
   fill instead of solid white, per Figma. */
.ff-calc__contact-input {
	flex: 1 1 220px;
	min-width: 0;
	height: 48px;
	border-radius: 10px;
	background-color: rgba(255, 255, 255, 0.2);
	font-family: var(--wp--preset--font-family--inter);
	font-size: 1rem;
	color: var(--wp--preset--color--white);
}

.ff-calc__contact-input::placeholder {
	color: rgba(255, 255, 255, 0.75);
}

.ff-calc__contact-input:hover {
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35);
}

.ff-calc__contact-input:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.45);
}

/* White button with brand-purple text, no arrow icon — Figma's step-3
   button has neither the muted-purple fill nor the ::after arrow circle
   that .ff-lead-form__submit uses on the CTA banner below. */
.ff-calc__contact-submit {
	/* .ff-lead-form__submit's own <=560px override sets flex-basis:100% —
	   inside .ff-calc__contact's column flex direction that's a *height*
	   basis, which wins over the height property below and was collapsing
	   the button to its content height (~36px). Reset flex explicitly so
	   the fixed height actually applies. */
	flex: 0 0 auto;
	width: 100%;
	justify-content: center;
	margin-bottom: 16px;
	height: 52px;
	background-color: var(--wp--preset--color--white);
	color: var(--wp--preset--color--brand-deep);
	font-family: var(--wp--preset--font-family--inter);
	/* .ff-lead-form__submit's base padding (8px 8px 8px 87px) is tuned for
	   its own narrow inline banner button with justify-content:space-between;
	   here the button is full-width and centered with no ::after circle, so
	   the inherited 87px left padding pushes the centered text off-center.
	   Match the left padding to the right (8px) for true centering. */
	padding-left: 8px;
}

.ff-calc__contact-submit::after {
	content: none;
}

.ff-calc__contact-submit:hover,
.ff-calc__contact-submit:focus {
	filter: brightness(0.97);
}

.ff-calc__form-disclaimer {
	margin: 0;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-size: 0.8125rem;
	text-align: center;
}

/* Calculator mobile overrides — figures measured against the mobile
   Figma frame (100:176 -> 103:313, the same card node tree as desktop but
   under the 360px artboard): decor shapes get their own offsets (icon_1
   overflows the narrower card on the right by design — the card's own
   overflow:hidden clips it to the same kind of edge "peek" as icon_3;
   icon_3's already-thin sliver gets thinner still), a handful of chrome
   font-sizes step down a size, and the title's line-height ratio switches
   from 1.25 (desktop, 40/50) to 1.0714 (mobile, 28/30) — a unitless ratio
   can't fluidly interpolate via clamp()+vw the way the font-size above it
   does, so it's a breakpoint switch instead, same as .ff-partners__title. */
@media (max-width: 767px) {
	.ff-calc__title {
		line-height: 1.0714;
	}

	.ff-calc__decor-1 {
		top: 80px;
		right: auto;
		left: 208px;
	}

	.ff-calc__decor-2 {
		top: 925px;
		left: -274px;
	}

	.ff-calc__select,
	.ff-calc__input,
	.ff-calc__dropdown-trigger,
	.ff-calc__dropdown-value {
		font-size: 0.9375rem;
	}

	.ff-calc__service {
		font-size: 0.875rem;
	}

	.ff-calc__price {
		font-size: 0.75rem;
	}

	.ff-calc__option {
		font-size: 0.8125rem;
	}

	.ff-calc__options {
		padding-left: 0;
		column-gap: 12px;
	}

	.ff-calc__result-disclaimer {
		font-size: 0.75rem;
	}
}

/* =======================================================================
   FAQ ("Частые вопросы" accordion) — core/details markup stays plain and
   fully Gutenberg-editable (no wrapper divs, no extra spans in <summary>);
   assets/js/faq.js progressively enhances the *rendered* DOM only (wraps
   each answer in a grid-animatable panel, takes over open/close) for a
   smooth ~300ms height+fade transition and an animated "+" -> "-" morph.
   No JS -> native <details name="ff-faq"> grouping still works, instantly
   and unanimated. Card width/radius/padding/icon colour verified against
   full.json node 60:342 (desktop) / 111:1032 (mobile).
   ======================================================================= */

.ff-faq {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
}

/* Deficit lockstep, see --ff-gutter comment at the top of the file.
   :not(.alignfull): see .ff-steps's own identical fix above. */
.ff-faq:not(.alignfull) {
	max-width: calc(1170px + (var(--ff-gutter) - 16px) * 2);
}

.ff-faq__title {
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
	margin: 0 auto clamp(1.5rem, 1.0673rem + 1.9231vw, 3.375rem);
}

.ff-faq__list {
	max-width: 770px;
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: clamp(0.625rem, 0.5529rem + 0.3205vw, 0.9375rem);
}

.ff-faq__item {
	background-color: var(--wp--preset--color--white);
	border: 1px solid var(--wp--preset--color--bg-soft);
	border-radius: 12px;
	overflow: hidden;
	transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.ff-faq__item:hover {
	border-color: var(--wp--preset--color--brand-light);
	box-shadow: 0 6px 16px rgba(21, 12, 67, 0.14);
}

/* No [open] border/shadow rule on purpose — per client reference, an
   expanded card stays exactly as plain/white as a closed one at rest; it
   only picks up the brand-light border + shadow via :hover above (or the
   :focus-visible ring below), same as any closed card. */

.ff-faq__item summary {
	position: relative;
	cursor: pointer;
	list-style: none;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 19px 16px;
	color: var(--wp--preset--color--text-dark);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(0.875rem, 0.8606rem + 0.0641vw, 0.9375rem);
	line-height: 1.4;
}

.ff-faq__item summary::-webkit-details-marker {
	display: none;
}

.ff-faq__item summary:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.45);
}

/* One pseudo-element, two layered "bars" drawn via background-size: the
   horizontal bar stays fixed, the vertical one shrinks to 0 on [open] —
   an animatable "+" -> "-" morph with zero extra markup (keeps <summary>
   as plain RichText-editable text in Gutenberg). Colour = brand-light
   (#9671FF), matching the vector fill in full.json exactly. */
.ff-faq__item summary::after {
	content: "";
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	background-image:
		linear-gradient(var(--wp--preset--color--brand-light), var(--wp--preset--color--brand-light)),
		linear-gradient(var(--wp--preset--color--brand-light), var(--wp--preset--color--brand-light));
	background-repeat: no-repeat;
	background-position: center;
	background-size: 14px 2px, 2px 14px;
	transition: background-size 0.3s ease;
}

.ff-faq__item[open] summary::after {
	background-size: 14px 2px, 2px 0;
}

/* Panel wrapper — inserted at runtime by faq.js around everything after
   <summary>; never part of the saved block markup. The CSS grid
   0fr -> 1fr trick animates to the answer's natural height without JS
   ever measuring pixels. If faq.js doesn't run, this class simply never
   appears and the plain paragraph shows/hides natively (instant). */
.ff-faq__panel {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows 0.3s ease;
}

.ff-faq__panel-inner {
	min-height: 0;
	overflow: hidden;
	opacity: 0;
	transition: opacity 0.2s ease;
}

.ff-faq__item[open] .ff-faq__panel-inner {
	opacity: 1;
	transition-delay: 80ms;
}

.ff-faq__item p {
	margin: 0;
	padding: 14px 16px 19px;
	color: var(--wp--preset--color--text-muted);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(0.875rem, 0.8606rem + 0.0641vw, 0.9375rem);
	line-height: 1.55;
	max-width: 68ch;
}

@media (prefers-reduced-motion: reduce) {
	.ff-faq__item,
	.ff-faq__item summary::after,
	.ff-faq__panel,
	.ff-faq__panel-inner {
		transition: none !important;
	}
}

/* Mobile-only: tighten the Доставка-и-расчёты -> FAQ handoff specifically.
   Both sections use the same standard section padding-top/bottom clamp,
   AND — like every other top-level section here — .ff-faq sits on
   WordPress's default is-layout-constrained, which injects a 24px
   margin-block-start (same lobotomized-owl mechanism documented at the
   top of this file, just at the root/section level instead of inside a
   block). Stacked together that's 40(shipping bottom pad) + 24(rogue
   margin) + 40(faq top pad) = ~104px at the mobile clamp floor, versus
   the exact 50px gap in the mobile mockup (full.json 100:176: node
   111:964 "Доставка и расчёты" bottom y=9283 -> node 111:1032 "Частые
   вопросы" top y=9333). Scoped to this one adjacency only — other
   section-to-section gaps use the shared rogue-margin+padding combo
   untouched, pending their own review pass. */
@media (max-width: 640px) {
	.ff-shipping + .ff-faq {
		margin-top: 0;
		padding-top: 10px;
	}
}

/* =======================================================================
   NEWS ("Новости и статьи" — core/query loop, photo-less lavender teaser
   cards, 3 per row + arrow slider). GEOMETRY — see the docblock in
   patterns/news.php for the full _figma/full.json node-by-node breakdown
   (desktop 38:886 -> 60:349, mobile 100:176 -> 111:1079). Cards use their
   own .ff-news__teaser* class family, NOT .ff-news__card* — that family is
   legacy, kept only for /blog/ (see the BLOG INDEX comment below).
   ======================================================================= */

.ff-news {
	background-color: var(--wp--preset--color--white);
	padding-top: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-bottom: clamp(2.5rem, 2rem + 2.2222vw, 4.375rem);
	padding-inline: var(--ff-gutter);
}

/* Title centered via flex justify-center (not text-align alone) so it
   stays centered regardless of viewport, while the arrow pair — taken out
   of flow with position:absolute — sits flush to the section's own right
   edge at the title's vertical center. Figma reproduces this centering
   with a fixed-width text box + padding-left math (410px on a 1170 frame)
   that only works for that exact string; flex is the robust equivalent. */
.ff-news__head {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0 auto clamp(2.5rem, 2.3558rem + 0.6410vw, 3.125rem);
}

.ff-news__title {
	margin: 0;
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.5769rem + 0.7692vw, 2.5rem);
	line-height: 1.25;
	text-align: center;
}

/* Figma "Frame 80" (38:1435): 42x42 circles, gap 13, vertically centered
   on the title's line box. Hidden entirely below 640px (mobile scrolls the
   row by swipe only, same as every other card slider on this page). */
.ff-news__arrows {
	position: absolute;
	right: 0;
	top: 50%;
	transform: translateY(-50%);
	display: flex;
	align-items: center;
	gap: 13px;
}

.ff-news__arrows.is-hidden {
	display: none;
}

.ff-news__arrow {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 42px;
	height: 42px;
	border-radius: 50%;
	padding: 0;
	cursor: pointer;
	transition: opacity 0.2s ease, filter 0.2s ease;
}

.ff-news__arrow svg {
	display: block;
}

/* Left/prev: transparent, 1px #ECECF5 (bg-soft) border + same-color icon —
   Figma's "neutral" resting style, not a disabled state. */
.ff-news__arrow--prev {
	background-color: transparent;
	border: 1px solid var(--wp--preset--color--bg-soft);
	color: var(--wp--preset--color--bg-soft);
}

/* Right/next: filled #9671FF (brand-light) with a white icon — Figma's
   "active" resting style. */
.ff-news__arrow--next {
	background-color: var(--wp--preset--color--brand-light);
	border: none;
	color: var(--wp--preset--color--white);
}

.ff-news__arrow:hover:not(:disabled) {
	filter: brightness(1.06);
}

.ff-news__arrow:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(133, 75, 251, 0.35);
}

.ff-news__arrow:disabled {
	opacity: 0.4;
	cursor: default;
}

/* Real horizontal scroll-snap track on every viewport, not just mobile —
   same technique as .ff-promise__bullets (see its comment for the full
   rationale), but active at all widths here since assets/js/news.js needs
   something to scroll on desktop too once a 4th post exists. The query
   loop adds wrapper levels WordPress gives no class hook to skip
   (.wp-block-query > ul.wp-block-post-template > li.wp-block-post) —
   flattened with display:contents so the .ff-news__teaser cards are the
   track's direct flex/scroll-snap children (same fix as .ff-services__grid
   uses for its own query loop).

   position:relative is required, not cosmetic: each card's core/read-more
   link ("Читать →") carries a WP-injected <span class="screen-reader-text">
   with no explicit left/top, so its "auto" position resolves to its normal-
   flow slot in the full (unclipped) flex track — off past card 3, ~660px+
   on a 375px viewport. Without a positioned ancestor here, that span's
   containing block skips past this (position:static) element to .ff-news
   (position:relative, not clipped), escaping this element's overflow-x:auto
   clip and inflating document.documentElement.scrollWidth — the exact
   horizontal-scroll regression this comment is here to prevent a repeat of.
   .ff-services__grid already carries position:relative (for its own
   z-index stacking) which is why its identical read-more spans never
   surfaced this; this rule was copied from it but dropped that line. */
.ff-news__grid {
	position: relative;
	display: flex;
	flex-wrap: nowrap;
	gap: 30px;
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.ff-news__grid::-webkit-scrollbar {
	display: none;
}

.ff-news__grid .wp-block-post-template,
.ff-news__grid .wp-block-post-template > li {
	display: contents;
}

/* Figma Frame 76/77/78: 370x265, #F6F5FC bg, radius 12, padding 24/25/24/23
   (T/R/B/L), gap 40 between the pill and the text group below it. Cross
   -axis stretch (the flex row's default) equalizes all 3 cards' heights;
   .ff-news__teaser-link's margin-top:auto then pins "Читать →" to the
   bottom of whichever card is tallest, same as the old .ff-news__card-link. */
.ff-news__teaser {
	display: flex;
	flex-direction: column;
	flex: 0 0 370px;
	scroll-snap-align: start;
	background-color: var(--wp--preset--color--bg-lavender);
	border-radius: 12px;
	padding: 24px 25px 24px 23px;
	gap: 40px;
}

/* Figma Frame 73: 94x36 hug-width pill (align-self:flex-start keeps it
   from stretching to the card's full width like its text siblings do). */
.ff-news__teaser-tag {
	align-self: flex-start;
	margin: 0;
	background-color: var(--wp--preset--color--white);
	color: var(--wp--preset--color--brand-light);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 500;
	font-size: 0.8125rem;
	line-height: 1.25rem;
	padding: 8px 24px;
	border-radius: 999px;
}

.ff-news__teaser-body {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-height: 0;
	gap: 15px;
}

.ff-news__teaser-text {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

/* Figma title: 16px/700 desktop, 15px/700 mobile (100:176 -> 128:1762);
   line-height 22px desktop, 20px mobile — both fluid-clamped between the
   two reference frames like the rest of this file's type scale. */
.ff-news__teaser-title {
	margin: 0;
	color: var(--wp--preset--color--text-dark);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 700;
	font-size: clamp(0.9375rem, 0.9231rem + 0.0641vw, 1rem);
	line-height: clamp(1.25rem, 1.2212rem + 0.1282vw, 1.375rem);
}

.ff-news__teaser-title a {
	color: inherit;
	text-decoration: none;
}

.ff-news__teaser-title a:hover {
	text-decoration: underline;
}

/* Figma excerpt: 13px/400 desktop, 12px/400 mobile (128:1763) — line-height
   is a flat 18px on both reference frames, so it's frozen, not clamped. */
.ff-news__teaser-excerpt {
	margin: 0;
	color: var(--wp--preset--color--text-dark);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 400;
	font-size: clamp(0.75rem, 0.7356rem + 0.0641vw, 0.8125rem);
	line-height: 1.125rem;
}

.ff-news__teaser-link {
	margin-top: auto;
	padding-top: 6px;
}

.ff-news__teaser-link.wp-block-read-more,
.ff-news__teaser-link a {
	color: var(--wp--preset--color--brand-soft);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 0.875rem;
	text-decoration: none;
}

.ff-news__cta {
	margin-top: clamp(2.5rem, 2.3558rem + 0.6410vw, 3.125rem);
}

@media (max-width: 640px) {
	.ff-news__title {
		line-height: 1.0714;
	}

	.ff-news__arrows {
		display: none;
	}

	/* Figma mobile row (128:1755): gap 10, cards fixed 271px — on the
	   328px content width that's one card fully visible plus a ~47px peek
	   of the next, swipe-scrolled (arrows are hidden above). */
	.ff-news__grid {
		gap: 10px;
	}

	.ff-news__teaser {
		flex: 0 0 271px;
	}
}

/* =======================================================================
   MARKETPLACE LANDING PAGES — HERO (light theme, per-marketplace accent)
   - Используется на /wildberries/ (page 7) и будущих лендингах МП.
   - Отдельно от .ff-hero главной (тот ТЁМНЫЙ). Все классы ff-mp-*.
   - Палитра МП — в блоках .page-id-N ниже; новый МП = ещё один .page-id-N.
   - Figma: desktop 1:1974 (1920), mobile 117:1882 (360).
   ======================================================================= */

/* ---- Палитра маркетплейса (Wildberries = magenta) ----
   --mp-accent-rgb/--mp-steps-bg/--mp-btn-steps/--mp-btn-news — добавлены при
   рефакторинге MARKETPLACE OVERRIDES/STEPS на общий класс
   .page-template-page-marketplace (см. ниже): общие правила читают их через
   var(...,<WB-фолбэк>), а каждый новый лендинг МП (Ozon и т.д.) объявляет
   свой .page-id-N с этими же именами переменных и своими значениями — сами
   общие правила не меняются. */
.page-id-7 {
	--mp-accent: #DB00CB;
	--mp-accent-rgb: 219, 0, 203;
	--mp-hero-from: #FEF2FF;
	--mp-hero-to: #FAB8FF;
	--mp-cta-from: #DB00CB;
	--mp-cta-to: #B746D0;
	--mp-cta-btn: #9E0092;
	--mp-card: #FCF5F9;
	--mp-steps-bg: #FFFAFD;
	--mp-btn-steps: linear-gradient(90deg, #B747D1 0%, #D211CC 100%);
	--mp-btn-news: linear-gradient(90deg, #DB00CB 0%, #F673ED 100%);
}
/* ---- Палитра маркетплейса (Ozon = синий) ----
   Кнопки зигзага/news у Ozon сплошные синие (var с типом «цвет», не
   градиент) — общие правила ниже читают те же переменные через var(...),
   так что подмена работает без изменения самих правил. Стрелка кнопки
   зигзага (::after у .ff-btn-pill, #854BFB) НЕ перекрашивается для Ozon —
   в макете она остаётся глобальной фиолетовой, как и на главной/WB. */
.page-id-8 { /* Ozon */
	--mp-accent: #2060F6;
	--mp-accent-rgb: 32, 96, 246;
	--mp-hero-from: #F7FAFF;
	--mp-hero-to: #ABC9FF;
	--mp-cta-from: #2060F6;
	--mp-cta-to: #1B52D4;
	--mp-cta-btn: #1B52D4;
	--mp-card: #F7FAFF;
	--mp-steps-bg: #F7FAFF;
	--mp-btn-steps: #2060F6;
	--mp-btn-news: #2060F6;
}
/* ---- Палитра маркетплейса (Яндекс Маркет = оранжевый) ----
   Цвета из макета Figma node 1:2773 и присланного SVG: hero-градиент
   #FFF4DA->#FFD3C1 (paint0), CTA-градиент #EC5F39->#FFC949 (paint1),
   акцент #EC5F39. Значения card/steps-bg/cta-btn/btn/iconbg — первый
   заход в оранжевой гамме, уточняются на доводке 1:1. */
.page-id-9 { /* Яндекс Маркет */
	--mp-accent: #EC5F39;
	--mp-accent-rgb: 236, 95, 57;
	--mp-hero-from: #FFF4DA;
	--mp-hero-to: #FFD3C1;
	--mp-cta-from: #EC5F39;
	--mp-cta-to: #FFC949;
	--mp-cta-btn: #AE4C31;
	--mp-card: #FEFBF6;
	--mp-steps-bg: #FEFBF6;
	--mp-btn-steps: linear-gradient(90deg, #EC5F39 0%, #FFC949 100%);
	--mp-btn-news: linear-gradient(90deg, #EC5F39 0%, #FFC949 100%);
}
/* Палитра маркетплейса Lamoda - монохром, near-black.
   Цвета из макета Figma node 1:3173 и присланного SVG: hero-градиент
   белый -> #F2F2F2 (paint0), акцент #1A1A2E. CTA, карточки и кнопки -
   первый заход в монохромной гамме, уточняются на доводке 1:1. */
.page-id-10 { /* Lamoda */
	--mp-accent: #1A1A2E;
	--mp-accent-rgb: 26, 26, 46;
	--mp-hero-from: #FFFFFF;
	--mp-hero-to: #F2F2F2;
	--mp-cta-from: #1A1A2E;
	--mp-cta-to: #1A1A2E;
	--mp-cta-btn: #1A1A2E;
	--mp-card: #FAFAFA;
	--mp-steps-bg: #FAFAFA;
	--mp-btn-steps: #1A1A2E;
	--mp-btn-news: #1A1A2E;
}
/* Палитра маркетплейса MVideo - красная (бренд М.Видео).
   Цвета из макета Figma node 1:3573 и присланного SVG: hero-градиент
   4 стопа FFF1F1 -> EB2F48 (paint0), CTA EB2F48 -> C51835 (paint1),
   акцент EB2F48. Карточки, кнопки, фон иконок - первый заход, доводка уточнит. */
.page-id-11 { /* MVideo */
	--mp-accent: #EB2F48;
	--mp-accent-rgb: 235, 47, 72;
	--mp-hero-from: #FFF1F1;
	--mp-hero-to: #EB2F48;
	--mp-cta-from: #EB2F48;
	--mp-cta-to: #C51835;
	--mp-cta-btn: #C51835;
	--mp-card: #FFF6F7;
	--mp-steps-bg: #FFF6F7;
	--mp-btn-steps: #EB2F48;
	--mp-btn-news: #EB2F48;
}
/* Палитра Интернет-магазина - фиолетовая, как на главной.
   Цвета из макета Figma node 1:3973 и SVG: hero-декор темно-фиолетовый,
   услуги-CTA радиал 7B34BC -> 361D6A, акцент 6C37D6, кнопки 854AFB -> B193FC. */
.page-id-12 { /* Internet-magazin */
	--mp-accent: #6C37D6;
	--mp-accent-rgb: 108, 55, 214;
	--mp-hero-from: #F6F5FC;
	--mp-hero-to: #D9CDFD;
	--mp-cta-from: #6537B0;
	--mp-cta-to: #361D6A;
	--mp-cta-btn: #6C37D6;
	--mp-card: #F6F5FC;
	--mp-steps-bg: #F6F5FC;
	--mp-btn-steps: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
	--mp-btn-news: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
}
/* INTERNET-MAGAZIN HERO — тёмный вариант (Figma 1:3973); правила восстановлены
   после утраты незакоммиченных серверных стилей. */
.page-id-12 .ff-mp-hero { background: linear-gradient(180deg, #502A97 76.56%, #1E1540 100%); }
.page-id-12 .ff-mp-hero__title,
.page-id-12 .ff-mp-hero__subtitle { color: var(--wp--preset--color--white); }
.page-id-12 .ff-mp-btn .wp-block-button__link { background: #9671FF; }   /* макет: brand-light, текст белый как в базе */
.page-id-12 .ff-mp-hero__stats { background: rgba(255, 255, 255, 0.1); }
.page-id-12 .ff-mp-stat__num,
.page-id-12 .ff-mp-stat__label { color: var(--wp--preset--color--white); }
/* Глобальный переключатель деск/моб текста статов (спаны ff-mp-stat__desktop/
   ff-mp-stat__mobile — классы уникальны в проекте, пока используются только в
   hero этой страницы, см. контент page 12: "140+" деск vs "от 3 ₽" моб и т.д.). */
.ff-mp-stat__mobile { display: none; }
@media (max-width: 767px) {
	.ff-mp-stat__desktop { display: none; }
	.ff-mp-stat__mobile { display: inline; }
}
/* Палитра страницы О нас - фиолетовая, как на главной (идентична page-id-12). */
.page-id-16 { /* O nas */
	--mp-accent: #6C37D6;
	--mp-accent-rgb: 108, 55, 214;
	--mp-hero-from: #F6F5FC;
	--mp-hero-to: #D9CDFD;
	--mp-cta-from: #6537B0;
	--mp-cta-to: #361D6A;
	--mp-cta-btn: #6C37D6;
	--mp-card: #F6F5FC;
	--mp-steps-bg: #F6F5FC;
	--mp-btn-steps: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
	--mp-btn-news: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
}
/* Палитра страницы Маркировка - фиолетовая, как на главной (как page-id-12/16). */
.page-id-14 { /* Markirovka */
	--mp-accent: #6C37D6;
	--mp-accent-rgb: 108, 55, 214;
	--mp-hero-from: #FFFFFF;
	--mp-hero-to: #ECE1FB;
	--mp-cta-from: #6537B0;
	--mp-cta-to: #361D6A;
	--mp-cta-btn: #6C37D6;
	--mp-card: #F6F5FC;
	--mp-steps-bg: #F6F5FC;
	--mp-btn-steps: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
	--mp-btn-news: linear-gradient(90deg, #854AFB 0%, #B193FC 100%);
}
/* ---- Палитра маркетплейса (Мегамаркет = фиолетовый) ----
   Figma: desktop 306:357 (подписан "МВидео" — копия не переименована
   дизайнером, это НЕ M.Видео), mobile 307:808. Кляксы у степов НЕТ (в
   макете отсутствуют) — ::before/::after для .ff-steps не объявляются.
   --mp-cta-grad задаёт CTA-градиент десктопа целиком (свои ручки/угол,
   106.05deg общей формулы не подходит); --mp-cta-from/--mp-cta-to всё
   равно объявлены — их читает моб-override ниже (у Мегамаркета угол на
   мобильном кадре другой, 138.07deg, см. .page-id-165 .ff-mp-cta__card
   в блоке MARKETPLACE CTA). --mp-price-even/--mp-adv-icon-bg — новые
   переменные (см. общие правила .ff-mp-price/.ff-mp-adv-card__icon
   выше), т.к. у ММ чёт-строки прайса (#FCFAFF) и фон карточек (#FAFAFA)
   не совпадают, в отличие от других лендингов. */
.page-id-165 { /* Мегамаркет */
	--mp-accent: #8E51D4;
	--mp-accent-rgb: 142, 81, 212;
	--mp-hero-from: #F3F4F7;
	--mp-hero-to: #C99BFF;
	--mp-cta-grad: linear-gradient(113.40deg, #8E51D4 10.87%, #712FB6 71.90%); /* деск, свои ручки */
	--mp-cta-from: #8E51D4;  /* для моб-градиента (общий угол 138.07deg) */
	--mp-cta-to: #712FB6;
	--mp-cta-btn: #8E51D4;
	--mp-card: #FAFAFA;
	--mp-price-even: #FCFAFF;
	--mp-adv-icon-bg: #F4EDFF;
	--mp-steps-bg: #FAFAFA;
	--mp-btn-steps: #8E51D4;
	--mp-btn-news: #8E51D4;
}
/* Hero-кнопка ММ — белая с фиолетовым текстом (в отличие от WB/Ozon) */
.page-id-165 .ff-mp-btn .wp-block-button__link { background: var(--wp--preset--color--white); color: var(--mp-accent, #8E51D4); }
.page-id-165 .ff-mp-btn .wp-block-button__link:hover,
.page-id-165 .ff-mp-btn .wp-block-button__link:focus { color: var(--mp-accent, #8E51D4); filter: brightness(0.97); }
/* Широкие заголовки ММ */
.page-id-165 .ff-mp-adv .ff-mp-section__title { max-width: 660px; }  /* «Почему селлеры Мегамаркета работают с нами» — 2 строки деск */
.page-id-165 .ff-mp-hero__subtitle { max-width: 860px; }             /* сабтайтл 3 строки с <br>, нода макета 851px */

/* Hero страницы О нас: белый-в-фиолетовый фон, точки-паттерн вертикальными
   полосами по левому и правому краю на всю высоту,
   два блюр-эллипса (радиал справа-сверху, линейный слева-снизу), кнопка 9671FF.
   Градиенты-эллипсы - точные формулы из макета (заказчик). */
.page-id-16 .ff-mp-hero {
	background: #FFFFFF;
	position: relative;
	overflow: hidden;
	isolation: isolate;
}
/* На мобильном hero узкий и относительно высокий - auto 100% (ширина от
   высоты) даёт паттерн шире самого hero (проверено: ~499px паттерн при
   ~355px hero), обе стороны сливаются в сплошную заливку. Фикс - фиксированная
   некрупная ширина, безопасная в диапазоне узких экранов. */
@media (max-width: 767px) {
	.page-id-16 .ff-mp-hero {
		background: #FFFFFF;
	}
}
.page-id-16 .ff-mp-hero::before {
	content: "";
	position: absolute;
	z-index: -2;
	top: auto;
	right: -206px;
	bottom: -238px;
	width: 963px;
	height: 478px;
	background: radial-gradient(77.16% 77.16% at 63.91% 25.89%, #DA6FEF 0%, #A93AF4 100%);
	filter: blur(350px);
	opacity: 1;
	pointer-events: none;
}
.page-id-16 .ff-mp-hero::after {
	content: "";
	position: absolute;
	z-index: -2;
	bottom: -238px;
	left: -242px;
	width: 1006px;
	height: 498px;
	background: linear-gradient(251.72deg, #8E7AFF 39.36%, #7908C0 76.34%);
	filter: blur(350px);
	opacity: 1;
	pointer-events: none;
}
/* На мобильном hero узкий (~355px) - эллипсы 640x640 перекрывают весь блок
   сплошной заливкой, hero выглядит тёмно-фиолетовым вместо почти белого.
   Уменьшаем и высветляем. Правило ДОЛЖНО стоять после безусловных
   .page-id-16 .ff-mp-hero::before/::after выше (та же специфичность 0,2,1 -
   при равной специфичности выигрывает более позднее по тексту правило,
   а не большая специфичность самого @media). */
@media (max-width: 767px) {
	.page-id-16 .ff-mp-hero::before {
		top: auto;
		right: -149px;
		bottom: -95px;
		width: 344px;
		height: 264px;
		opacity: 1;
		filter: blur(350px);
	}
	.page-id-16 .ff-mp-hero::after {
		bottom: -119px;
		left: -146px;
		width: 327px;
		height: 272px;
		opacity: 1;
		filter: blur(350px);
	}
}
.page-id-16 .ff-mp-hero__cta .wp-block-button__link { background: #9671FF; }
.page-id-16 .ff-mp-stat__num { color: #1A1A2E; }
@media (min-width: 768px) {
	.page-id-16 .ff-mp-hero {
		box-sizing: border-box;
		height: 766px;
	}
}

/* Межсекционные отступы: ff-services/ff-lead-banner/ff-advantages/ff-shipping
   на этой странице не имеют собственного margin-top, поэтому получают только
   WordPress owl-дефолт 24px, тогда как остальные секции (hero->история,
   доставка->FAQ) уже сидят на fluid clamp 50->100px (см. .ff-history/.ff-why
   выше). Нормализуем в тот же ритм - тем же clamp, без @media (клэмп сам
   даёт нужный range и на моб, и на деск). */
.page-id-16 .ff-services,
.page-id-16 .ff-lead-banner,
.page-id-16 .ff-advantages,
.page-id-16 .ff-shipping {
	margin-top: clamp(50px, 38.46px + 3.2051vw, 100px);
}

/* Hero страницы Маркировка: тот же приём паттерн + блюр-эллипсы, что у
   .page-id-16 .ff-mp-hero (см. выше), свои цвета эллипсов из макета
   Маркировки. Кнопка 9671FF. Блока счётчиков-статов (ff-mp-stat) в hero
   этой страницы нет - в разметке его просто не будет. */
.page-id-14 .ff-mp-hero {
	background: #FFFFFF;
	position: relative;
	overflow: hidden;
	isolation: isolate;
}
@media (max-width: 767px) {
	.page-id-14 .ff-mp-hero {
		background: #FFFFFF;
	}
}
.page-id-14 .ff-mp-hero::before {
	content: "";
	position: absolute;
	z-index: -2;
	top: auto;
	right: -206px;
	bottom: -238px;
	width: 963px;
	height: 478px;
	background: radial-gradient(75% 75% at 64% 26%, #D7CAFF 0%, #A93AF4 100%);
	filter: blur(350px);
	opacity: 1;
	pointer-events: none;
}
.page-id-14 .ff-mp-hero::after {
	content: "";
	position: absolute;
	z-index: -2;
	bottom: -238px;
	left: -242px;
	width: 1006px;
	height: 498px;
	background: linear-gradient(230deg, #D0B0FF 0%, #DA9EFF 100%);
	filter: blur(350px);
	opacity: 1;
	pointer-events: none;
}
/* Мобиль: эллипсы 620x620 перекрыли бы весь узкий hero сплошной заливкой -
   уменьшаем и высветляем, порядок правил как у .page-id-16 (см. объяснение
   про специфичность там же). */
@media (max-width: 767px) {
	.page-id-14 .ff-mp-hero::before {
		top: auto;
		right: -37px;
		bottom: -152px;
		width: 183px;
		height: 195px;
		opacity: 1;
		filter: blur(350px);
	}
	.page-id-14 .ff-mp-hero::after {
		bottom: -162px;
		left: -22px;
		width: 216px;
		height: 215px;
		opacity: 1;
		filter: blur(350px);
	}
}
.page-id-14 .ff-mp-hero__cta .wp-block-button__link { background: #9671FF; }

.ff-mp-hero__pattern {
	position: absolute;
	inset: 0;
	z-index: -1;
	display: block;
	pointer-events: none;
	background-repeat: no-repeat;
}
.page-id-16 .ff-mp-hero__pattern {
	background-image: url("../img/hero-pattern.svg"), url("../img/hero-pattern.svg");
	background-position: -156px 66px, 845px -549px;
	background-size: 983px 961px, 1334px 1304px;
}
.page-id-14 .ff-mp-hero__pattern {
	background-image: url("../img/hero-pattern.svg"), url("../img/hero-pattern.svg");
	background-position: -370px -266px, 769px -288px;
	background-size: 983px 961px, 1334px 1304px;
}

@media (min-width: 768px) {
	.page-id-14 .ff-mp-hero {
		box-sizing: border-box;
		height: 768px;
		padding-top: 33px;
		padding-bottom: 49px;
	}
	.page-id-14 .ff-mp-hero__title {
		width: 1097px;
		max-width: 100%;
		margin-top: 74px;
		font-size: 4.25rem;
		line-height: 80px;
	}
	.page-id-14 .ff-mp-hero__subtitle {
		width: 720px;
		margin-top: 30px;
		font-size: 1.25rem;
		line-height: 30px;
	}
	.page-id-14 .ff-mp-hero__cta {
		margin-top: 30px;
	}
}

.ff-mp-hero {
	display: flex;
	flex-direction: column;
	align-items: center;
	position: relative;
	overflow: hidden;
	isolation: isolate;
	background: linear-gradient(180deg, var(--mp-hero-from, #FEF2FF) 0%, var(--mp-hero-to, #FAB8FF) 100%);
	border-radius: 3rem;
	/* верх 50px (крошки); бока fluid 10->213px => контент 1170 внутри wide-1595
	   (та же геометрия, что у .ff-hero); низ fluid 10->56px */
	padding: 50px clamp(0.625rem, -2.3029rem + 13.0128vw, 13.3125rem) clamp(0.625rem, -0.2135rem + 3.7247vw, 3.5rem);
	text-align: center;
}

/* >=768px: same fix and same reasoning as .ff-hero's own identical rule
   above (see its comment) — same alignwide geometry, same missing
   side gutter between ~768px and where wideSize used to start helping. */
@media (min-width: 768px) {
	.ff-mp-hero {
		width: min(1595px, calc(100% - 2 * var(--ff-gutter)));
		margin-inline: auto;
	}
}

@media (max-width: 767px) {
	.ff-mp-hero {
		box-sizing: border-box;
		margin-inline: 10px !important;
		width: auto;
		padding: 96px 10px 0;
	}
	.page-id-14 .ff-mp-hero {
		height: 445px;
	}
	.page-id-16 .ff-mp-hero {
		height: 515px;
	}
	.page-id-14 .ff-mp-hero__pattern,
	.page-id-16 .ff-mp-hero__pattern {
		background-image: url("../img/hero-pattern.svg");
		background-position: -107px 28px;
		background-size: 553px 541px;
	}
}

.ff-mp-hero__crumbs {
	align-self: flex-start;
	margin: 0;
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 0.875rem;
	line-height: 1.2;
	color: #503E59;
}
.ff-mp-hero__crumbs a { color: #503E59; text-decoration: none; }
.ff-mp-hero__crumbs a:hover { text-decoration: underline; }
.ff-mp-hero__crumbs-sep { margin: 0 6px; }
.ff-mp-hero__crumbs-current { color: #B4A5BC; }
@media (max-width: 767px) { .ff-mp-hero__crumbs { display: none; } }

.ff-mp-hero__title {
	margin: 27px 0 0;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 0.7981rem + 4.2308vw, 4.25rem);
	line-height: 1.18;
}
.ff-mp-hero__title-m { display: none; }
.ff-nowrap { white-space: nowrap; }
@media (max-width: 767px) {
	.ff-mp-hero__title { width: 320px; margin-top: 0; font-size: 1.75rem; line-height: 30px; max-width: 100%; }
	.ff-mp-hero__title-d { display: none; }
	.ff-mp-hero__title-m { display: inline; }
}

.ff-mp-hero__subtitle {
	margin: 30px auto 0;
	max-width: 720px;
	color: var(--wp--preset--color--text-dark);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: clamp(1rem, 0.9519rem + 0.2137vw, 1.25rem);
	line-height: 1.5;
}
@media (max-width: 767px) { .ff-mp-hero__subtitle { display: none !important; } }

.ff-mp-hero__cta { margin-top: 20px; }
.ff-mp-btn .wp-block-button__link {
	background: var(--mp-accent, #DB00CB);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 1rem;
	line-height: 1.19;
	border-radius: 999px;
	padding: 16px 28px;
	text-decoration: none;
}
.ff-mp-btn .wp-block-button__link:hover,
.ff-mp-btn .wp-block-button__link:focus { color: var(--wp--preset--color--white); filter: brightness(1.06); }
@media (max-width: 767px) { .ff-mp-hero__cta { margin-top: 40px; } }

.ff-mp-hero__stats {
	width: 100%;
	margin-top: 81px;
	background: #FFFFFF99;
	border-radius: 2.25rem;
	padding: 40px clamp(1rem, -1.7981rem + 12.4359vw, 5.375rem);
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 2rem;
}
.ff-mp-stat { text-align: center; }
.ff-mp-stat__num {
	margin: 0;
	color: var(--mp-accent, #DB00CB);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 700;
	font-size: clamp(1.5rem, 0.9231rem + 2.5641vw, 3rem);
	line-height: 1.2;
	white-space: nowrap;
}
.ff-mp-stat__label {
	margin: 4px 0 0;
	color: #503E59;
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 500;
	font-size: clamp(0.8125rem, 0.7644rem + 0.2137vw, 1rem);
	line-height: 1.4;
	white-space: nowrap;
}
@media (max-width: 767px) {
	.ff-mp-hero__stats {
		margin-top: 40px;
		padding: 24px 10px;
		display: grid;
		grid-template-columns: 1fr 1fr;
		row-gap: 16px;
		column-gap: 8px;
	}
	.ff-mp-stat__num, .ff-mp-stat__label { white-space: normal; }
}

/* =======================================================================
   MARKETPLACE LANDING — SECTION TITLE (общий для секций лендинга МП)
   Inter 600, 40px деск / 28px моб, по центру, navy.
   ======================================================================= */
.ff-mp-section {
	padding-top: clamp(50px, 38.46px + 3.2051vw, 100px);
	margin-top: 0; /* gasит owl 24px — зазор задаёт только padding-top (линейный 50@360 -> 100@1920) */
	/* >=768px only — ниже это правило перебивает следующая строка
	   (padding-inline:16px, @media max-width:767px, специфичность та
	   же, но позже по исходнику). Без align секция сама ограничена
	   WordPress-ом 1170px; паддинга на десктопе не было вообще (0, не
	   16px), поэтому max-width растёт в локстепе БЕЗ вычитания 16px —
	   см. общий комментарий у --ff-gutter в начале файла. */
	padding-inline: var(--ff-gutter);
}
@media (max-width: 767px) { .ff-mp-section { padding-inline: 16px; } }
/* :not(.alignfull) — см. идентичную правку у .ff-steps (комментарий
   там же): без неё на странице, где эта секция вдруг сохранена как
   align:full, паддинг+max-width без auto-центрирования от WordPress
   прижали бы контент к левому краю. */
.ff-mp-section:not(.alignfull) {
	max-width: calc(1170px + var(--ff-gutter) * 2);
}
.ff-mp-section__title {
	margin: 0 auto clamp(30px, 1.5rem + 1.5vw, 50px);
	max-width: 460px;
	color: var(--wp--preset--color--navy);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: clamp(1.75rem, 1.3846rem + 0.9615vw, 2.5rem);
	line-height: 1.25;
}
/* Прайс-таблица: заголовок длиннее остальных ("Стоимость фулфилмента для
   Wildberries") — общий max-width:460 рвёт его на 3 строки дека; макет
   (узел 1:2011, ширина текста 529) — 2 строки. Шире только у ЭТОГО
   заголовка, остальные .ff-mp-section__title (общий max-width:460) не
   трогаем. На мобиле контейнер уже уже обоих max-width — не влияет. */
.ff-mp-price-section .ff-mp-section__title {
	max-width: 560px;
}

/* =======================================================================
   MARKETPLACE LANDING — PRICE TABLE (Figma desktop 1:2284, mobile 117:2711)
   Мобайл: СТРАНИЦА не скроллится по X — таблица скроллится внутри своей
   <figure> (overflow-x:auto); min-width таблицы уводит «Комментарий» за
   экран (открывается горизонтальным скроллом самой таблицы).
   ======================================================================= */
.ff-mp-price {
	margin: 0;
	max-width: 100%;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}
.ff-mp-price table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	table-layout: fixed;
}
.ff-mp-price th, .ff-mp-price td { border: 0; }
.ff-mp-price th:nth-child(1), .ff-mp-price td:nth-child(1) { width: 31.6%; }
.ff-mp-price th:nth-child(2), .ff-mp-price td:nth-child(2) { width: 15.4%; }
.ff-mp-price th:nth-child(3), .ff-mp-price td:nth-child(3) { width: 53%; }
.ff-mp-price thead th {
	background: var(--mp-accent, #DB00CB);
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 1.25rem;
	line-height: 1.3;
	text-align: left;
	padding: 20px;
	vertical-align: middle;
}
.ff-mp-price thead th:first-child { padding-left: 60px; border-top-left-radius: 12px; }
.ff-mp-price thead th:last-child { border-top-right-radius: 12px; }
.ff-mp-price tbody td {
	padding: 19px 20px;
	vertical-align: middle;
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 1rem;
	line-height: 1.3;
	color: #20331A;
}
.ff-mp-price tbody td:first-child { padding-left: 60px; font-weight: 600; }
.ff-mp-price tbody td:nth-child(2) { color: var(--mp-accent, #DB00CB); font-weight: 500; white-space: nowrap; }
.ff-mp-price tbody tr:nth-child(odd) td { background: #FFFFFF; }
.ff-mp-price tbody tr:nth-child(even) td { background: var(--mp-price-even, var(--mp-card, #FCF5F9)); }
.ff-mp-price tbody tr:last-child td:first-child { border-bottom-left-radius: 12px; }
.ff-mp-price tbody tr:last-child td:last-child { border-bottom-right-radius: 12px; }
.ff-mp-price__note { color: #888888; font-size: 0.8125rem; margin-left: 12px; }
.ff-mp-price__note--stack { display: inline-block; margin-left: 0; margin-top: 2px; }

@media (max-width: 767px) {
	.ff-mp-price table { min-width: 680px; }
	.ff-mp-price th:nth-child(1), .ff-mp-price td:nth-child(1) { width: 28%; }
	.ff-mp-price th:nth-child(2), .ff-mp-price td:nth-child(2) { width: 24%; }
	.ff-mp-price th:nth-child(3), .ff-mp-price td:nth-child(3) { width: 48%; }
	.ff-mp-price thead th { font-size: 1.0625rem; padding: 14px 16px; }
	.ff-mp-price thead th:first-child { padding-left: 16px; }
	.ff-mp-price tbody td { padding: 14px 16px; }
	.ff-mp-price tbody td:first-child { padding-left: 16px; }
}

/* =======================================================================
   MARKETPLACE — ADVANTAGES «Почему селлеры … работают с нами»
   Figma desktop 1:2148, mobile 117:2654. 6 карточек. Десктоп 3×2 (gap 30),
   мобайл — горизонт. слайдер scroll-snap (карточка 270 + подгляд), как
   .ff-promise__bullets. Карточка #FFFAFD r12; иконка-зона #FAEFF8 r11 (сплошн.,
   по WB-Figma — НЕ радиальный градиент главной); иконка 32px #DB00CB (baked).
   Текст прижат к низу карточки (зазор иконка→текст плавающий), высоты равны.
   ======================================================================= */
.ff-mp-adv-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 30px;
}
.ff-mp-adv-card {
	display: flex;
	flex-direction: column;
	justify-content: space-between; /* иконка сверху, текст снизу; свободное место — зазор 64/42px (owl-reset !important не даёт использовать margin:auto) */
	min-height: 256px;
	background: #FFFAFD;
	border-radius: 12px;
	padding: 24px;
}
.ff-mp-adv-card__icon {
	width: 60px;
	height: 60px;
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--mp-adv-icon-bg, #FAEFF8);
	border-radius: 11px;
}
.ff-mp-adv-card__icon .wp-block-image { margin: 0; }
.ff-mp-adv-card__icon img {
	display: block;
	width: 32px;
	height: 32px;
	object-fit: contain;
}
.ff-mp-adv-card__body {
	display: flex;
	flex-direction: column;
	gap: 10px;
}
.ff-mp-adv-card__title {
	margin: 0;
	color: #3D2947;
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 700;
	font-size: 1.25rem;      /* 20px */
	line-height: 1.5;
}
.ff-mp-adv-card__desc {
	margin: 0;
	color: #3D2947;
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 400;
	font-size: 0.9375rem;    /* 15px */
	line-height: 1.47;
}
/* Ozon (Figma 1:2540/1:2548, узел "Frame 2536" и т.д. — см.
   _figma/ozon-nodes.json): карточка/иконка-зона там СВОИ оттенки, а не
   WB-константы выше (#FFFAFD/#FAEFF8 — по WB-Figma, не переменные палитры) —
   переопределяем точечно под .page-id-8, саму базовую WB-карточку не трогаем. */
.page-id-8 .ff-mp-adv-card { background: var(--mp-card, #FFFAFD); }
.page-id-8 .ff-mp-adv-card__icon { background: #EAEFF8; }
.page-id-9 .ff-mp-adv-card { background: var(--mp-card, #FEFBF6); }
.page-id-9 .ff-mp-adv-card__icon { background: #FDEEE7; }
.page-id-10 .ff-mp-adv-card { background: var(--mp-card, #FAFAFA); }
.page-id-10 .ff-mp-adv-card__icon { background: #ECECF5; }
.page-id-11 .ff-mp-adv-card { background: var(--mp-card, #FFF6F7); }
.page-id-11 .ff-mp-adv-card__icon { background: #FCEFF1; }
/* Мегамаркет: базовая .ff-mp-adv-card (тело карточки, не иконка) остаётся
   WB-хардкодом #FFFAFD — как и у остальных лендингов МП, переопределяем
   точечно. Иконка-зона у ММ уже не требует override — читает
   var(--mp-adv-icon-bg) прямо в общем правиле выше. */
.page-id-165 .ff-mp-adv-card { background: var(--mp-card, #FAFAFA); }
.page-id-11 .ff-mp-hero { background: linear-gradient(180deg, #FFF1F1 0%, #FFCDD8 30.62%, #FF4659 76.56%, #EB2F48 100%); }
/* Ламода: mesh-фон CTA-формы по референсу заказчика (aurora); низ светлый, поэтому note затемнён. */
.page-id-10 .ff-mp-cta__card {
	background:
		radial-gradient(22% 26% at 2% 3%, rgba(224,150,90,0.35) 0%, rgba(224,150,90,0) 45%),
		radial-gradient(62% 68% at 87% 15%, #1E3AD5 0%, rgba(30,58,213,0) 58%),
		radial-gradient(66% 62% at 46% -10%, #05041A 0%, rgba(5,4,26,0) 55%),
		radial-gradient(48% 62% at 4% 2%, #0A0818 0%, rgba(10,8,24,0) 55%),
		radial-gradient(105% 95% at 16% 116%, #ECE1F6 0%, rgba(236,225,246,0) 60%),
		linear-gradient(158deg, #14103F 0%, #4A3F9E 50%, #AB9ADC 100%);
}
.page-id-10 .ff-mp-cta__note,
.page-id-10 .ff-mp-cta__note a { color: #241A3D; }
/* Интернет-магазин: тот же mesh-градиент (aurora), что у Ламоды — по просьбе
   заказчика взять "как с Ламоды" один в один. */
.page-id-12 .ff-mp-cta__card {
	background:
		radial-gradient(22% 26% at 2% 3%, rgba(224,150,90,0.35) 0%, rgba(224,150,90,0) 45%),
		radial-gradient(62% 68% at 87% 15%, #1E3AD5 0%, rgba(30,58,213,0) 58%),
		radial-gradient(66% 62% at 46% -10%, #05041A 0%, rgba(5,4,26,0) 55%),
		radial-gradient(48% 62% at 4% 2%, #0A0818 0%, rgba(10,8,24,0) 55%),
		radial-gradient(105% 95% at 16% 116%, #ECE1F6 0%, rgba(236,225,246,0) 60%),
		linear-gradient(158deg, #14103F 0%, #4A3F9E 50%, #AB9ADC 100%);
}
.page-id-12 .ff-mp-cta__note,
.page-id-12 .ff-mp-cta__note a { color: #241A3D; }
/* Двойной отступ услуги -> шаги: .page-template-page-marketplace .ff-steps
   (ниже в файле) задаёт свой margin-top тем же числом классов — тай по
   специфичности решается порядком (та строка позже), поэтому здесь нужен
   !important, иначе обнуление тихо не сработает. */
.page-id-12 .ff-steps { margin-top: 0 !important; }
@media (max-width: 767px) {
	.ff-mp-adv-grid {
		display: flex;
		grid-template-columns: none;
		gap: 10px;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		min-width: 0;
	}
	.ff-mp-adv-grid::-webkit-scrollbar { display: none; }
	.ff-mp-adv-card {
		flex: 0 0 270px;
		min-width: 0;
		scroll-snap-align: start;
	}
}

/* =======================================================================
   STEPS — reveal-анимация (главная + лендинги МП). JS (reveal.js) вешает
   .ff-anim-ready (без JS шаги видимы), затем .is-visible при скролле.
   Десктоп: шаги «выезжают» с чередующихся сторон (зигзаг); мобайл: fade+вверх.
   ======================================================================= */
.ff-steps.ff-anim-ready { overflow-x: clip; }
.ff-steps.ff-anim-ready .ff-steps__step {
	opacity: 0;
	transition: opacity .6s ease, transform .6s ease;
}
.ff-steps.ff-anim-ready .ff-steps__step:nth-child(odd) { transform: translateX(-48px); }
.ff-steps.ff-anim-ready .ff-steps__step:nth-child(even) { transform: translateX(48px); }
.ff-steps.ff-anim-ready.is-visible .ff-steps__step { opacity: 1; transform: none; }
.ff-steps.ff-anim-ready.is-visible .ff-steps__step:nth-child(2) { transition-delay: .1s; }
.ff-steps.ff-anim-ready.is-visible .ff-steps__step:nth-child(3) { transition-delay: .2s; }
.ff-steps.ff-anim-ready.is-visible .ff-steps__step:nth-child(4) { transition-delay: .3s; }
@media (max-width: 767px) {
	.ff-steps.ff-anim-ready .ff-steps__step:nth-child(odd),
	.ff-steps.ff-anim-ready .ff-steps__step:nth-child(even) { transform: translateY(24px); }

	/* Fix: this rule and the base ".is-visible" reset above tie at
	   specificity (0,4,0); this one used to be the later of the two in
	   source order, so it always won the tie regardless of .is-visible —
	   opacity correctly reached 1 on reveal, but transform stayed stuck at
	   translateY(24px) forever on mobile (steps rendered ~24px lower than
	   their true layout position, e.g. the last step sat only ~6px above
	   the CTA button instead of the intended 30px). Re-assert the reset
	   here, after the tied rule, so .is-visible wins on mobile too. */
	.ff-steps.ff-anim-ready.is-visible .ff-steps__step {
		transform: none;
	}
}
@media (prefers-reduced-motion: reduce) {
	.ff-steps.ff-anim-ready .ff-steps__step { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* =======================================================================
   MARKETPLACE STEPS — светлая полоса + декор-фигуры по краям (десктоп) +
   акцент палитры лендинга. Базовый layout .ff-steps общий с главной.
   Структурные правила (фон/отступы/z-index) — на .page-template-page-
   marketplace, общем для любого лендинга МП; цвета — через переменные
   палитры (--mp-steps-bg/--mp-accent/--mp-btn-steps), которые объявляет
   каждый .page-id-N сам (см. .page-id-7 выше — Wildberries). Кляксы
   (url+геометрия) и цвет стрелки в CTA-кнопке — WB-специфичные ассеты,
   остаются в .page-id-7 (у Ozon будут свои/глобальная стрелка). Figma 1:2026.
   ======================================================================= */
.page-template-page-marketplace .ff-steps {
	background: var(--mp-steps-bg, #FFFAFD);
	position: relative;
	overflow: hidden;
	margin-top: clamp(50px, 38.46px + 3.2051vw, 100px);
	padding-top: clamp(50px, 38.46px + 3.2051vw, 100px);
	padding-bottom: clamp(50px, 38.46px + 3.2051vw, 100px);
}
.page-id-7 .ff-steps::before {
	content: "";
	position: absolute; left: 0; top: 0;
	width: 496px; height: 511px;
	background: url("../img/steps/left.svg") no-repeat left top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-7 .ff-steps::after {
	content: "";
	position: absolute; right: 0; top: 216px;
	width: 424px; height: 684px;
	background: url("../img/steps/right.svg") no-repeat right top / contain;
	pointer-events: none; z-index: 0;
}
/* Ozon — свои кляксы (assets/img/steps/ozon-{left,right}.svg), координаты и
   viewBox из клиентского экспорта Figma-фрейма (см. _figma/ozon-nodes.json,
   узлы 62:496/63:500), НЕ вычислены из геометрии. */
.page-id-8 .ff-steps::before { /* левая, вылезает за левый край */
	content: "";
	position: absolute; left: -124px; top: 345px;
	width: 644px; height: 548px;
	background: url("../img/steps/ozon-left.svg") no-repeat left top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-8 .ff-steps::after { /* правая, прижата к верху, вылезает вправо */
	content: "";
	position: absolute; right: -143px; top: 0;
	width: 518px; height: 511px;
	background: url("../img/steps/ozon-right.svg") no-repeat right top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-9 .ff-steps::before {
	content: "";
	position: absolute; left: -124px; top: 345px;
	width: 644px; height: 548px;
	background: url("../img/steps/ym-left.svg") no-repeat left top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-9 .ff-steps::after {
	content: "";
	position: absolute; right: -143px; top: 0;
	width: 518px; height: 511px;
	background: url("../img/steps/ym-right.svg") no-repeat right top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-10 .ff-steps::before {
	content: "";
	position: absolute; left: -124px; top: 345px;
	width: 644px; height: 548px;
	background: url("../img/steps/lamoda-left.svg") no-repeat left top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-10 .ff-steps::after {
	content: "";
	position: absolute; right: -143px; top: 0;
	width: 518px; height: 511px;
	background: url("../img/steps/lamoda-right.svg") no-repeat right top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-11 .ff-steps::before {
	content: "";
	position: absolute; left: -124px; top: 345px;
	width: 644px; height: 548px;
	background: url("../img/steps/mvideo-left.svg") no-repeat left top / contain;
	pointer-events: none; z-index: 0;
}
.page-id-11 .ff-steps::after {
	content: "";
	position: absolute; right: -143px; top: 0;
	width: 518px; height: 511px;
	background: url("../img/steps/mvideo-right.svg") no-repeat right top / contain;
	pointer-events: none; z-index: 0;
}
.page-template-page-marketplace .ff-steps__title,
.page-template-page-marketplace .ff-steps__timeline,
.page-template-page-marketplace .ff-steps__cta { position: relative; z-index: 1; }
@media (max-width: 767px) {
	.page-template-page-marketplace .ff-steps::before,
	.page-template-page-marketplace .ff-steps::after { display: none; }
}
/* Ozon: в отличие от WB, в макете кляксы на мобиле ВИДНЫ — возвращаем их
   именно для .page-id-8, поверх общего скрытия выше (равная специфичность,
   этот блок идёт позже в исходнике => побеждает для этой страницы; секция
   .ff-steps имеет overflow:hidden — выносы обрежутся штатно). */
@media (max-width: 767px) {
	.page-id-8 .ff-steps::before { display: block; left: 0; top: 0; width: 250px; height: 214px; }
	.page-id-8 .ff-steps::after { display: block; right: 0; top: 484px; width: 253px; height: 249px; left: auto; }
	.page-id-9 .ff-steps::before { display: block; left: 0; top: 0; width: 250px; height: 214px; }
	.page-id-9 .ff-steps::after { display: block; right: 0; top: 484px; width: 253px; height: 249px; left: auto; }
	.page-id-10 .ff-steps::before { display: block; left: 0; top: 0; width: 250px; height: 214px; }
	.page-id-10 .ff-steps::after { display: block; right: 0; top: 484px; width: 253px; height: 249px; left: auto; }
	.page-id-11 .ff-steps::before { display: block; left: 0; top: 0; width: 250px; height: 214px; }
	.page-id-11 .ff-steps::after { display: block; right: 0; top: 484px; width: 253px; height: 249px; left: auto; }
}
.page-template-page-marketplace .ff-steps__num,
.page-template-page-marketplace .ff-steps__step-title { color: var(--mp-accent, #DB00CB); }
.page-template-page-marketplace .ff-steps__step::before { background: var(--mp-accent, #DB00CB); }
.page-template-page-marketplace .ff-steps__cta .wp-block-button__link {
	background: var(--mp-btn-steps, linear-gradient(90deg, #B747D1 0%, #D211CC 100%));
}
.page-id-7 .ff-steps__cta .wp-block-button__link::after {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23DB00CB' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='7' y1='17' x2='17' y2='7'/%3E%3Cpolyline points='7 7 17 7 17 17'/%3E%3C/svg%3E");
}

/* =======================================================================
   MARKETPLACE CTA — «Получите расчёт под ваш товар за 30 минут»
   Переиспользуемая секция (patterns/marketplace-cta.php), стоит между
   .ff-steps и .ff-categories. Цвета — через
   --mp-cta-from/--mp-cta-to/--mp-cta-btn (объявлены в палитре .page-id-N
   выше, см. .page-id-7); новый маркетплейс дублирует свой .page-id-N блок
   с новыми значениями этих трёх переменных — сама секция не меняется.
   Figma: desktop 1:2198 (1920), mobile 118:2754 (360).
   ======================================================================= */
.ff-mp-cta__card {
	/* Рендер-точная конверсия ручек градиента из full.json (формулы Dev Mode
	   от заказчика на этот узел нет) — проценты и угол не пересчитывать из геометрии. */
	background: var(--mp-cta-grad, linear-gradient(106.05deg, var(--mp-cta-from, #DB00CB) 9.75%, var(--mp-cta-to, #B746D0) 86.28%));
	border-radius: 12px;
	padding: 50px 40px;
	color: var(--wp--preset--color--white);
}
.ff-mp-cta__title {
	margin: 0 auto;
	max-width: 650px;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 2.5rem;
	line-height: 50px;
}
@media (min-width: 768px) {
	/* Десктоп — ровно 2 строки, перенос после «товар»; на мобиле спан
	   переносится свободно (3 строки натуральным переносом). */
	.ff-mp-cta__nb { white-space: nowrap; }
}
.ff-mp-cta__subtitle {
	margin: 20px auto 0;
	max-width: 669px;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 0.9375rem;
	line-height: 20px;
}
.ff-mp-cta__form {
	display: flex;
	flex-direction: column;
	align-items: center;
	margin: 30px auto 0;
	width: 100%;
}
.ff-mp-cta__row {
	display: flex;
	gap: 12px;
	width: 100%;
	max-width: 640px;
}
.ff-mp-cta__input {
	flex: 1 1 0;
	min-width: 0;
	height: 48px;
	border: 0;
	border-radius: 10px;
	background: rgba(255, 255, 255, 0.2);
	font-family: var(--wp--preset--font-family--inter);
	font-size: 1rem;
	color: var(--wp--preset--color--white);
	padding: 0 18px;
}
.ff-mp-cta__input::placeholder {
	color: #F1F1F1;
	opacity: 1;
}
/* Тот же hover/focus, что у .ff-calc__contact-input — включая поле имени
   (без маркер-класса ff-calc__contact-input), чтобы оба инпута вели себя
   одинаково. */
.ff-mp-cta__input:hover {
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35);
}
.ff-mp-cta__input:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.45);
}
/* forms.js вешает is-invalid прямо на инпут; правило .ff-lead-form__input.
   is-invalid таргетит чужой класс и наш инпут не покрывает — дублируем. */
.ff-mp-cta__input.is-invalid {
	box-shadow: 0 0 0 2px var(--wp--preset--color--accent-red) inset;
}
.ff-mp-cta__submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	margin: 30px auto 0;
	height: 51px;
	padding: 16px 28px;
	border: 0;
	border-radius: 100px;
	background: var(--wp--preset--color--white);
	color: var(--mp-cta-btn, #9E0092);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 600;
	font-size: 1rem;
	line-height: 1.21;
	cursor: pointer;
}
/* Конвенция .ff-calc__contact-submit (тоже белая кнопка на фиолетовом
   фоне): просто filter:brightness на hover/focus, без доп. рамки. */
.ff-mp-cta__submit:hover,
.ff-mp-cta__submit:focus {
	filter: brightness(0.97);
}
.ff-mp-cta__note {
	margin: 30px auto 0;
	max-width: 669px;
	color: rgba(255, 255, 255, 0.8);
	font-family: var(--wp--preset--font-family--inter);
	font-weight: 400;
	font-size: 0.8125rem;
	line-height: 20px;
}
.ff-mp-cta__note a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 2px;
}
.ff-mp-cta__note a:hover {
	text-decoration: none;
}
/* Базовые цвета .ff-lead-form__status (белый/розовый) уже подходят на
   градиенте — здесь только центрируем. */
.ff-mp-cta .ff-lead-form__status {
	text-align: center;
}

@media (max-width: 767px) {
	.ff-mp-cta__card {
		padding: 30px 16px;
	}
	/* Мегамаркет: на мобильном кадре Figma угол градиента CTA-карточки
	   другой, чем на десктопе (138.07deg против 113.40deg), при тех же
	   цветах (--mp-cta-from/--mp-cta-to, те же 9.75%/86.28% ручки, что и
	   в общем десктопном правиле выше) — скоуп только на .page-id-165,
	   чтобы не задеть WB/Ozon/остальные МП (у них на мобиле нет
	   отдельного узла в Figma, там просто наследуется десктопный фон). */
	.page-id-165 .ff-mp-cta__card {
		background: linear-gradient(138.07deg, var(--mp-cta-from, #8E51D4) 9.75%, var(--mp-cta-to, #712FB6) 86.28%);
	}
	.ff-mp-cta__title {
		margin: 0;
		max-width: none;
		font-size: 1.75rem;
		line-height: 30px;
		/* !important: title/subtitle get Gutenberg's has-text-align-center
		   utility class from the {"textAlign":"center"} block attribute;
		   core prints that as ":root .has-text-align-center" (specificity
		   0,2,0), which otherwise beats our single-class selector here. */
		text-align: left !important;
	}
	.ff-mp-cta__subtitle {
		margin: 20px 0 0;
		max-width: none;
		text-align: left !important;
	}
	.ff-mp-cta__form {
		margin-top: 20px;
		align-items: stretch;
	}
	.ff-mp-cta__row {
		flex-direction: column;
		gap: 12px;
		max-width: none;
	}
	.ff-mp-cta__input {
		/* flex-basis:0 главную ось (ширину) задаёт на десктоке (row); в
		   column-направлении мобайла главная ось — высота, и тот же
		   flex-basis:0 увёл бы высоту к content-based авто-минимуму
		   инпута (< 48px) вместо заданных 48. Фиксируем базис явно. */
		flex: 0 0 48px;
	}
	.ff-mp-cta__submit {
		margin-top: 20px;
		width: 100%;
		height: 52px;
	}
	.ff-mp-cta__note {
		margin-top: 20px;
	}
}

/* =======================================================================
   MARKETPLACE OVERRIDES — categories / FAQ / news (общие для любого
   лендинга МП)
   Секции ff-categories/ff-faq/ff-news переиспользуются с главной 1-в-1 (те
   же классы, тот же faq.js/news.js) — здесь только точечная перекраска под
   палитру лендинга МП: --mp-accent/--mp-accent-rgb/--mp-card/--mp-btn-news
   объявлены в палитре КАЖДОГО конкретного .page-id-N (см. .page-id-7 выше —
   Wildberries). Новый лендинг МП дублирует свой .page-id-N с этими же
   переменными и своими значениями — правила ниже не меняются.
   ======================================================================= */
.page-template-page-marketplace .ff-categories__card { background-color: var(--mp-card, #FCF5F9); }           /* было bg-lavender #F6F5FC */
.page-template-page-marketplace .ff-faq__item summary::after {                                                /* плюс/минус: было brand-light #9671FF */
	background-image:
		linear-gradient(var(--mp-accent, #DB00CB), var(--mp-accent, #DB00CB)),
		linear-gradient(var(--mp-accent, #DB00CB), var(--mp-accent, #DB00CB));
}
.page-template-page-marketplace .ff-faq__item:hover { border-color: var(--mp-accent, #DB00CB); }               /* было brand-light #9671FF (.ff-faq__item:hover, ~стр.3727) */
.page-template-page-marketplace .ff-faq__item summary:focus-visible { box-shadow: 0 0 0 3px rgba(var(--mp-accent-rgb, 219, 0, 203), 0.45); } /* было rgba(133,75,251,.45) (~стр.3757) */
.page-template-page-marketplace .ff-news__teaser { background-color: var(--mp-card, #FCF5F9); }                /* было bg-lavender */
.page-template-page-marketplace .ff-news__teaser-tag { color: var(--mp-accent, #DB00CB); }                     /* текст тега «Статьи»; фон остаётся белым */
.page-template-page-marketplace .ff-news__teaser-link.wp-block-read-more,
.page-template-page-marketplace .ff-news__teaser-link a { color: var(--mp-accent, #DB00CB); }                  /* «Читать →», было brand-soft */
.page-template-page-marketplace .ff-news__arrow--next { background-color: var(--mp-accent, #DB00CB); }         /* активная стрелка, было brand-light */
.page-template-page-marketplace .ff-news__arrow:focus-visible { box-shadow: 0 0 0 3px rgba(var(--mp-accent-rgb, 219, 0, 203), 0.35); } /* был фиолетовый ring */
.page-template-page-marketplace .ff-news__cta .wp-block-button__link {
	/* Figma 62:440 (WB): ручки осевые (0,.5)→(1,.5) — чистый 90deg, без
	   конверсий; фон — через --mp-btn-news (у Ozon будет сплошной цвет, а
	   не градиент). */
	background: var(--mp-btn-news, linear-gradient(90deg, #DB00CB 0%, #F673ED 100%));
}
/* Стрелка в белом круге кнопки (::after у .ff-btn-pill, #854BFB) НЕ
   перекрашивается — в WB-макете (обе версии) остаётся фиолетовой. Стрелка
   -prev слайдера новостей (#ECECF5) тоже не трогается — совпадает с макетом. */

/* Зазоры между переиспользуемыми секциями (те же классы, что и на главной):
   их собственные pt/pb 70/70 деск, 40/40 моб — "воздух" из главной, на
   лендингах МП он лишний, т.к. зазор здесь задаёт ТОЛЬКО margin-top (та же
   линейная формула, что .ff-mp-section, 50@360 -> 100@1920). Обнуляем их
   pt/pb — специфичность 0,2,0 бьёт в т.ч. моб-правила главной вроде
   ".ff-faq + .ff-news" (тоже 0,2,0, но раньше по исходнику — тай-брейк в
   нашу пользу для этих трёх классов на лендингах МП). */
.page-template-page-marketplace .ff-categories,
.page-template-page-marketplace .ff-faq,
.page-template-page-marketplace .ff-news {
	margin-top: clamp(50px, 38.46px + 3.2051vw, 100px);
	padding-top: 0;
	padding-bottom: 0;
}
/* Низ страницы: news -> футер. footer.wp-block-template-part — НЕ прямой
   DOM-сосед .ff-news (сидит на уровень выше, рядом с <main>), поэтому
   стык тюнингуется через margin-bottom последней секции, а не через
   обычную пару-соседей. После обнуления pt/pb выше остаточный зазор
   (замер) — 24px деск/10px моб (owl/родная кромка футера, не наша); нужно
   добавить 76px деск/40px моб, чтобы дотянуть до 100/50 — значения
   подобраны по факту (getBoundingClientRect на живой странице WB), не
   вычислены из вёрстки. */
.page-template-page-marketplace .ff-news {
	margin-bottom: clamp(40px, 31.6923px + 2.3077vw, 76px);
}

/* Заголовок категорий: на WB деск/моб-тексты разные (см. content-snapshots/
   wildberries.html) — оба варианта лежат как отдельные спаны внутри одного
   .ff-categories__title и переключаются тем же брейкпоинтом, на котором
   сетка карточек уходит в мобильный слайдер (см. .ff-categories__card
   { flex: 0 0 270px; } выше). Классы не scoped: на главной их просто нет. */
.ff-categories__title-m { display: none; }
@media (max-width: 640px) {
	.ff-categories__title-d { display: none; }
	.ff-categories__title-m { display: inline; }
}

/* Заголовки FAQ/news лендинга Ozon (стр. 8): тот же приём деск/моб-спанов,
   что и у .ff-categories__title выше (см. content-snapshots/ozon.html) —
   на WB и главной эти классы просто не существуют, поэтому правило не
   scoped под .page-id-8. */
.ff-faq__title-m, .ff-news__title-m { display: none; }
@media (max-width: 640px) {
	.ff-faq__title-d, .ff-news__title-d { display: none; }
	.ff-faq__title-m, .ff-news__title-m { display: inline; }
}

/* =======================================================================
   REVEAL-АНИМАЦИИ v2 — универсальная scroll-reveal система (главная +
   секции, общие с лендингами МП: .ff-categories/.ff-faq/.ff-news подключены
   тут же самими своими классами; WB-специфичные секции лендинга
   /wildberries/ — .ff-mp-hero/.ff-mp-price-section/.ff-mp-adv/.ff-mp-cta —
   тем же механизмом, отдельные блоки 14-17 ниже).

   Механика (assets/js/reveal.js): каждой найденной секции достаются
   .ff-anim-ready + ff-rv ff-rv--<type>; детям, где нужен каскад — инлайновая
   --rvi (индекс). Скрытые состояния ниже существуют ТОЛЬКО под
   .ff-anim-ready — без JS всё видно сразу (то же прогрессивное улучшение,
   что и у .ff-steps выше). Один общий IntersectionObserver один раз
   добавляет .is-visible (unobserve сразу же — при скролле вверх/вниз не
   переигрывается); hero — исключение, раскрывается на 2х requestAnimationFrame
   сразу при загрузке, не дожидаясь скролла. Анимируются только
   opacity/transform — layout не двигается, CLS 0.

   .ff-steps ("Как начать работать?") сюда не входит — его анимация принята
   заказчиком отдельно (см. блок STEPS выше), эти правила её не трогают.

   Ловушка transition-перезаписи: .ff-calc__service и .ff-faq__item уже
   несут свой собственный hover-transition (box-shadow/border-color) —
   ниже он не заменяется, а объединяется в один список с opacity/transform,
   причём transition-delay (стаггер) стоит ТОЛЬКО у opacity/transform —
   иначе после reveal все последующие hover'ы наследовали бы задержку
   каскада навсегда (.is-visible добавляется один раз и остаётся).
   ======================================================================= */

:root {
	--ff-rv-ease: cubic-bezier(0.22, 1, 0.36, 1);
	--ff-rv-ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);
	--ff-rv-shift: 28px;
}

@media (max-width: 767px) {
	:root {
		--ff-rv-shift: 16px;
	}
}

/* --- 1. HERO — вход при загрузке (2х rAF), не через scroll ------------- */

.ff-hero.ff-anim-ready .ff-hero__title {
	opacity: 0;
	transform: translateY(24px);
	transition: opacity 0.75s var(--ff-rv-ease), transform 0.75s var(--ff-rv-ease);
}

.ff-hero.ff-anim-ready .ff-hero__subtitle,
.ff-hero.ff-anim-ready .ff-hero__partners-line {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.65s var(--ff-rv-ease) 0.09s, transform 0.65s var(--ff-rv-ease) 0.09s;
}

.ff-hero.ff-anim-ready .ff-hero__cta {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.6s var(--ff-rv-ease) 0.18s, transform 0.6s var(--ff-rv-ease) 0.18s;
}

/* Не из ТЗ буквально (там расписаны только 4 шага) — статы-бар не может
   просто остаться статичным на фоне анимированного текста над ним; заполняем
   пробел лёгким fade+rise между кнопками и декором. */
.ff-hero.ff-anim-ready .ff-hero__stats {
	opacity: 0;
	transform: translateY(16px);
	transition: opacity 0.6s var(--ff-rv-ease) 0.24s, transform 0.6s var(--ff-rv-ease) 0.24s;
}

.ff-hero.ff-anim-ready::before,
.ff-hero.ff-anim-ready::after {
	opacity: 0;
	transform: scale(0.97);
	transition: opacity 0.8s var(--ff-rv-ease) 0.25s, transform 0.8s var(--ff-rv-ease) 0.25s;
}

.ff-hero.ff-anim-ready.is-visible .ff-hero__title,
.ff-hero.ff-anim-ready.is-visible .ff-hero__subtitle,
.ff-hero.ff-anim-ready.is-visible .ff-hero__cta,
.ff-hero.ff-anim-ready.is-visible .ff-hero__stats {
	opacity: 1;
	transform: none;
}

/* .ff-hero__partners-line отдыхает на opacity:.76 (см. её же правило выше),
   не на 1 — цель reveal должна совпадать с этим, а не быть полностью непрозрачной. */
.ff-hero.ff-anim-ready.is-visible .ff-hero__partners-line {
	opacity: 0.76;
	transform: none;
}

/* ::before отдыхает на opacity:.1 (точечная текстура, см. её же правило
   выше); ::after (свечение) — на 1, уже как в базовом правиле. */
.ff-hero.ff-anim-ready.is-visible::before {
	opacity: 0.1;
	transform: scale(1);
}

.ff-hero.ff-anim-ready.is-visible::after {
	opacity: 1;
	transform: scale(1);
}

/* --- 2. PARTNERS — вся секция мягким fade-up; лого/маркиза не стаггерятся --- */

.ff-partners.ff-anim-ready {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-partners.ff-anim-ready.is-visible {
	opacity: 1;
	transform: none;
}

/* --- 3. CALCULATOR — карточка целиком + стаггер строк услуг + итог -----

   ТЗ говорит "строки слева" / "панель итога справа", но живой DOM —
   .ff-calc__card это единая вертикальная колонка (display:flex;flex-
   direction:column), двухколоночного строки/итог разбиения нет (проверено
   по main.css, ~строка 3068). Строки услуг анимируются стаггером как есть
   (по порядку сверху вниз), а панель итога (.ff-calc__result) получает
   акцентный slide-x, как и просили — переносим инструкцию на реальную
   структуру 1-в-1 по смыслу. */

.ff-calc.ff-anim-ready .ff-calc__title,
.ff-calc.ff-anim-ready .ff-calc__subtitle {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-calc.ff-anim-ready .ff-calc__card {
	opacity: 0;
	transform: scale(0.97) translateY(var(--ff-rv-shift));
	transition: opacity 0.8s var(--ff-rv-ease), transform 0.8s var(--ff-rv-ease);
}

/* .ff-calc__service уже несёт transition: box-shadow/border-color (hover,
   ~строка 3404) — объединяем в один список, задержку-стаггер вешаем только
   на opacity/transform (см. докблок раздела выше). */
.ff-calc.ff-anim-ready .ff-calc__service {
	opacity: 0;
	transform: translateY(16px);
	transition:
		opacity 0.55s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 60ms), 550ms),
		transform 0.55s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 60ms), 550ms),
		box-shadow 0.15s ease,
		border-color 0.15s ease;
}

.ff-calc.ff-anim-ready .ff-calc__result {
	opacity: 0;
	transform: translateX(28px);
	transition: opacity 0.7s var(--ff-rv-ease) 0.2s, transform 0.7s var(--ff-rv-ease) 0.2s;
}

.ff-calc.ff-anim-ready.is-visible .ff-calc__title,
.ff-calc.ff-anim-ready.is-visible .ff-calc__subtitle,
.ff-calc.ff-anim-ready.is-visible .ff-calc__card,
.ff-calc.ff-anim-ready.is-visible .ff-calc__service,
.ff-calc.ff-anim-ready.is-visible .ff-calc__result {
	opacity: 1;
	transform: none;
}

/* --- 4. PROMISE — 6 пунктов стаггером, иконка overshoot, фото/CTA доп. --- */

.ff-promise.ff-anim-ready .ff-promise__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-promise.ff-anim-ready .ff-promise__bullet {
	opacity: 0;
	transform: translateY(16px);
	transition:
		opacity 0.6s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 80ms), 550ms),
		transform 0.6s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 80ms), 550ms);
}

/* Наследует --rvi от родителя .ff-promise__bullet (CSS custom properties
   каскадируют потомкам) — отдельный проход в JS не нужен. */
.ff-promise.ff-anim-ready .ff-promise__bullet-icon {
	opacity: 0;
	transform: scale(0.6);
	transition:
		opacity 0.5s var(--ff-rv-ease-back) calc(min(calc(var(--rvi, 0) * 80ms), 550ms) + 120ms),
		transform 0.5s var(--ff-rv-ease-back) calc(min(calc(var(--rvi, 0) * 80ms), 550ms) + 120ms);
}

/* Не из ТЗ буквально (пункт 4 расписывает только пункты-буллеты) — большое
   фото справа от колонки иначе осталось бы статичным; лёгкий fade+scale
   (не translateX — рядом нет overflow:hidden обёртки, translateX рисковал
   бы горизонтальным скроллом). */
.ff-promise.ff-anim-ready .ff-promise__photo {
	opacity: 0;
	transform: scale(0.97);
	transition: opacity 0.75s var(--ff-rv-ease) 0.15s, transform 0.75s var(--ff-rv-ease) 0.15s;
}

/* Тоже не из ТЗ буквально — кнопка "Оставить заявку" под буллетами,
   довесок в конце каскада (после последнего буллета на 80ms*5=400ms). */
.ff-promise.ff-anim-ready .ff-promise__cta {
	opacity: 0;
	transform: translateY(16px) scale(0.95);
	transition: opacity 0.55s var(--ff-rv-ease-back) 0.52s, transform 0.55s var(--ff-rv-ease-back) 0.52s;
}

.ff-promise.ff-anim-ready.is-visible .ff-promise__title,
.ff-promise.ff-anim-ready.is-visible .ff-promise__bullet,
.ff-promise.ff-anim-ready.is-visible .ff-promise__bullet-icon,
.ff-promise.ff-anim-ready.is-visible .ff-promise__photo,
.ff-promise.ff-anim-ready.is-visible .ff-promise__cta {
	opacity: 1;
	transform: none;
}

/* --- 5. SERVICES — карточки стаггером, CTA-карточка последняя (scale) --- */

.ff-services.ff-anim-ready .ff-services__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-services.ff-anim-ready .ff-services__card {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 90ms), 550ms),
		transform 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 90ms), 550ms);
}

/* Тот же querySelectorAll в JS индексирует карточки и CTA-карточку вместе,
   по порядку DOM — CTA естественно получает следующий (последний) индекс,
   спецкейс в JS не нужен; только своя scale-трансформация вместо rise. */
.ff-services.ff-anim-ready .ff-services__cta {
	opacity: 0;
	transform: scale(0.96);
	transition:
		opacity 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 90ms), 550ms),
		transform 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 90ms), 550ms);
}

.ff-services.ff-anim-ready.is-visible .ff-services__title,
.ff-services.ff-anim-ready.is-visible .ff-services__card,
.ff-services.ff-anim-ready.is-visible .ff-services__cta {
	opacity: 1;
	transform: none;
}

/* --- 7. CATEGORIES — диагональная волна (--rvi = col+row из JS) + фото --- */

.ff-categories.ff-anim-ready .ff-categories__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-categories.ff-anim-ready .ff-categories__card {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 70ms), 550ms),
		transform 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 70ms), 550ms);
}

/* "Окно" фото уже right:0;bottom:0 + overflow:hidden (.ff-categories__card-
   photo, см. выше) — масштабируем сам этот контейнер (не вложенный <img>
   с его 8 разными per-category left/top) ради одного общего правила на все
   карточки; --rvi наследуется от родительской карточки. */
.ff-categories.ff-anim-ready .ff-categories__card-photo {
	opacity: 0;
	transform: scale(1.08);
	transform-origin: bottom right;
	transition:
		opacity 0.7s var(--ff-rv-ease) calc(min(calc(var(--rvi, 0) * 70ms), 550ms) + 150ms),
		transform 0.7s var(--ff-rv-ease) calc(min(calc(var(--rvi, 0) * 70ms), 550ms) + 150ms);
}

.ff-categories.ff-anim-ready.is-visible .ff-categories__title,
.ff-categories.ff-anim-ready.is-visible .ff-categories__card,
.ff-categories.ff-anim-ready.is-visible .ff-categories__card-photo {
	opacity: 1;
	transform: none;
}

/* --- 8. LEAD BANNER — карточка целиком, декор от краёв, стекло, чекбоксы --- */

.ff-lead-banner.ff-anim-ready .ff-lead-banner__card {
	opacity: 0;
	transform: scale(0.97) translateY(var(--ff-rv-shift));
	transition: opacity 0.8s var(--ff-rv-ease), transform 0.8s var(--ff-rv-ease);
}

/* .ff-lead-banner__card уже position:relative;overflow:hidden — ±28px
   декора всегда клипуются карточкой, горизонтального скролла страницы
   отсюда быть не может даже до раскрытия. */
.ff-lead-banner.ff-anim-ready .ff-lead-banner__decor-left {
	opacity: 0;
	transform: translateX(-28px);
	transition: opacity 0.75s var(--ff-rv-ease) 0.2s, transform 0.75s var(--ff-rv-ease) 0.2s;
}

.ff-lead-banner.ff-anim-ready .ff-lead-banner__decor-right {
	opacity: 0;
	transform: translateX(28px);
	transition: opacity 0.75s var(--ff-rv-ease) 0.2s, transform 0.75s var(--ff-rv-ease) 0.2s;
}

.ff-lead-banner.ff-anim-ready .ff-lead-form__panel {
	opacity: 0;
	transform: translateY(16px);
	transition: opacity 0.7s var(--ff-rv-ease) 0.26s, transform 0.7s var(--ff-rv-ease) 0.26s;
}

.ff-lead-banner.ff-anim-ready .ff-lead-form__checkbox {
	opacity: 0;
	transition: opacity 0.5s var(--ff-rv-ease) 0.38s;
}

.ff-lead-banner.ff-anim-ready .ff-lead-form__checkbox:nth-child(2) {
	transition-delay: 0.45s;
}

.ff-lead-banner.ff-anim-ready.is-visible .ff-lead-banner__card,
.ff-lead-banner.ff-anim-ready.is-visible .ff-lead-banner__decor-left,
.ff-lead-banner.ff-anim-ready.is-visible .ff-lead-banner__decor-right,
.ff-lead-banner.ff-anim-ready.is-visible .ff-lead-form__panel,
.ff-lead-banner.ff-anim-ready.is-visible .ff-lead-form__checkbox {
	opacity: 1;
	transform: none;
}

/* --- 9. ADVANTAGES — заголовок fade-up, карточки стаггером ------------- */

.ff-advantages.ff-anim-ready .ff-advantages__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-advantages.ff-anim-ready .ff-advantages__card {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 80ms), 550ms),
		transform 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 80ms), 550ms);
}

.ff-advantages.ff-anim-ready.is-visible .ff-advantages__title,
.ff-advantages.ff-anim-ready.is-visible .ff-advantages__card {
	opacity: 1;
	transform: none;
}

/* --- 10. STAFF — волна: нечётные снизу, чётные сверху, + scale-in ------ */

.ff-staff.ff-anim-ready .ff-staff__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-staff.ff-anim-ready .ff-staff__badge {
	opacity: 0;
	transition:
		opacity 0.7s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 70ms), 550ms),
		transform 0.7s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 70ms), 550ms);
}

.ff-staff.ff-anim-ready .ff-staff__badge:nth-child(odd) {
	transform: translateY(28px) scale(0.95);
}

.ff-staff.ff-anim-ready .ff-staff__badge:nth-child(even) {
	transform: translateY(-28px) scale(0.95);
}

@media (max-width: 767px) {
	.ff-staff.ff-anim-ready .ff-staff__badge:nth-child(odd) {
		transform: translateY(14px) scale(0.95);
	}

	.ff-staff.ff-anim-ready .ff-staff__badge:nth-child(even) {
		transform: translateY(-14px) scale(0.95);
	}
}

.ff-staff.ff-anim-ready.is-visible .ff-staff__title,
.ff-staff.ff-anim-ready.is-visible .ff-staff__badge {
	opacity: 1;
	transform: none;
}

/* --- 11. SHIPPING — левая/правая панель навстречу друг другу ----------- */

/* В отличие от .ff-steps/.ff-calc__card/.ff-lead-banner__card, у этой
   секции нет собственного overflow:hidden — ±32px transform ниже сидит
   вплотную к краям строки, так что клип нужен явно (только под
   .ff-anim-ready — статическая раскладка без JS не затрагивается). */
.ff-shipping.ff-anim-ready {
	overflow-x: clip;
}

.ff-shipping.ff-anim-ready .ff-shipping__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-shipping.ff-anim-ready .ff-shipping__text {
	opacity: 0;
	transform: translateX(-32px);
	transition: opacity 0.8s var(--ff-rv-ease), transform 0.8s var(--ff-rv-ease);
}

.ff-shipping.ff-anim-ready .ff-shipping__photo {
	opacity: 0;
	transform: translateX(32px);
	transition: opacity 0.8s var(--ff-rv-ease), transform 0.8s var(--ff-rv-ease);
}

.ff-shipping.ff-anim-ready .ff-shipping__block-icon {
	opacity: 0;
	transition: opacity 0.5s var(--ff-rv-ease) 0.2s;
}

.ff-shipping.ff-anim-ready.is-visible .ff-shipping__title,
.ff-shipping.ff-anim-ready.is-visible .ff-shipping__text,
.ff-shipping.ff-anim-ready.is-visible .ff-shipping__photo,
.ff-shipping.ff-anim-ready.is-visible .ff-shipping__block-icon {
	opacity: 1;
	transform: none;
}

/* --- 12. FAQ — заголовок fade-up, карточки лесенкой -------------------- */

.ff-faq.ff-anim-ready .ff-faq__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

/* .ff-faq__item уже несёт transition: box-shadow/border-color (hover,
   ~строка 3809) — то же объединение, что и у .ff-calc__service выше. */
.ff-faq.ff-anim-ready .ff-faq__item {
	opacity: 0;
	transform: translateY(20px);
	transition:
		opacity 0.6s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 60ms), 550ms),
		transform 0.6s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 60ms), 550ms),
		box-shadow 0.15s ease,
		border-color 0.15s ease;
}

.ff-faq.ff-anim-ready.is-visible .ff-faq__title,
.ff-faq.ff-anim-ready.is-visible .ff-faq__item {
	opacity: 1;
	transform: none;
}

/* --- 13. NEWS — заголовок+стрелки fade, тизеры стаггером, CTA overshoot --- */

/* Вешаем на обёртку .ff-news__head (title+arrows), не на .ff-news__arrow —
   у стрелок свой transition (opacity/filter, ~строка 4000) для hover,
   трогать его незачем (см. докблок раздела выше про приём "обёртка вместо
   элемента"). */
.ff-news.ff-anim-ready .ff-news__head {
	opacity: 0;
	transition: opacity 0.6s var(--ff-rv-ease);
}

.ff-news.ff-anim-ready .ff-news__teaser {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 90ms), 550ms),
		transform 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 90ms), 550ms);
}

.ff-news.ff-anim-ready .ff-news__cta {
	opacity: 0;
	transform: scale(0.94);
	transition: opacity 0.55s var(--ff-rv-ease-back) 0.35s, transform 0.55s var(--ff-rv-ease-back) 0.35s;
}

.ff-news.ff-anim-ready.is-visible .ff-news__head,
.ff-news.ff-anim-ready.is-visible .ff-news__teaser,
.ff-news.ff-anim-ready.is-visible .ff-news__cta {
	opacity: 1;
	transform: none;
}

/* =======================================================================
   WB-ЛЕНДИНГ (/wildberries/, page 7) — секции ff-mp-*, этап 2 reveal-работы.
   Те же токены/приёмы, что и выше (--ff-rv-ease/--ff-rv-ease-back/
   --ff-rv-shift, min(calc(var(--rvi,0) * Nms), 550ms)-кап на стаггерах,
   .ff-anim-ready-гейт, единый is-visible-сброс opacity:1/transform:none).
   ======================================================================= */

/* --- 14. MP-HERO — вход при загрузке (2х rAF), как .ff-hero главной ---- */

.ff-mp-hero.ff-anim-ready .ff-mp-hero__crumbs {
	opacity: 0;
	transition: opacity 0.6s var(--ff-rv-ease);
}

.ff-mp-hero.ff-anim-ready .ff-mp-hero__title {
	opacity: 0;
	transform: translateY(24px);
	transition: opacity 0.75s var(--ff-rv-ease) 0.06s, transform 0.75s var(--ff-rv-ease) 0.06s;
}

/* Скрыта на мобиле (display:none!important, см. правило выше) — начальное
   opacity:0 там просто не рендерится; фикс-мс тайминги соседей (title/cta/
   stats) ни от чего не зависят, так что "дыры" в каскаде без неё не будет. */
.ff-mp-hero.ff-anim-ready .ff-mp-hero__subtitle {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.65s var(--ff-rv-ease) 0.14s, transform 0.65s var(--ff-rv-ease) 0.14s;
}

/* .ff-mp-hero__cta — обёртка wp-block-buttons (родитель самой ссылки), не
   <a>: у ссылки свой hover (filter:brightness, .ff-mp-btn .wp-block-button__
   link:hover) — он не участвует, трогать нечего. */
.ff-mp-hero.ff-anim-ready .ff-mp-hero__cta {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.6s var(--ff-rv-ease) 0.22s, transform 0.6s var(--ff-rv-ease) 0.22s;
}

/* 4 стата — стаггер через --rvi (JS: items ".ff-mp-stat" у .ff-mp-hero),
   база 300ms + шаг 70ms/индекс, тот же min(...,550ms)-кап каскада, что и
   везде (при 4 элементах кап не выстреливает, макс. реальная задержка
   300+3*70=510ms). Сама .ff-mp-hero__stats (белая плашка-подложка) не
   скрывается — фон виден сразу, стаггерятся только числа/подписи внутри. */
.ff-mp-hero.ff-anim-ready .ff-mp-stat {
	opacity: 0;
	transform: translateY(16px);
	transition:
		opacity 0.6s var(--ff-rv-ease) calc(min(calc(var(--rvi, 0) * 70ms), 550ms) + 300ms),
		transform 0.6s var(--ff-rv-ease) calc(min(calc(var(--rvi, 0) * 70ms), 550ms) + 300ms);
}

.ff-mp-hero.ff-anim-ready.is-visible .ff-mp-hero__crumbs,
.ff-mp-hero.ff-anim-ready.is-visible .ff-mp-hero__title,
.ff-mp-hero.ff-anim-ready.is-visible .ff-mp-hero__subtitle,
.ff-mp-hero.ff-anim-ready.is-visible .ff-mp-hero__cta,
.ff-mp-hero.ff-anim-ready.is-visible .ff-mp-stat {
	opacity: 1;
	transform: none;
}

/* --- 15. MP-PRICE — заголовок fade-up, thead-слайд, tbody-каскад ------- */

.ff-mp-price-section.ff-anim-ready .ff-mp-section__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-mp-price-section.ff-anim-ready .ff-mp-price thead {
	opacity: 0;
	transform: translateY(-12px);
	transition: opacity 0.5s var(--ff-rv-ease) 0.1s, transform 0.5s var(--ff-rv-ease) 0.1s;
}

/* Дек: строки едут по X (слева направо), --rvi = индекс строки (JS: items
   ".ff-mp-price tbody tr"), тот же min(...,550ms)-кап каскада (при 7 строках
   кап не выстреливает, макс. 6*70=420ms). transform на tr не трогает layout/
   высоту строки (translate — чисто визуальный сдвиг) и не портит radius
   шапки/низа таблицы (radius висит на самих th/td, border-collapse:
   separate) — проверено computed-стилями и визуально на живой странице.
   Горизонт. -24px клипуется существующим .ff-mp-price{overflow-x:auto}
   (тот же контейнер, что даёт моб. скролл таблицы) — новый overflow не
   добавляем. */
.ff-mp-price-section.ff-anim-ready .ff-mp-price tbody tr {
	opacity: 0;
	transform: translateX(-24px);
	transition:
		opacity 0.6s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 70ms), 550ms),
		transform 0.6s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 70ms), 550ms);
}

/* Моб: таблица живёт в горизонт. скролл-контейнере — slide-x там сбивает
   восприятие свайпа, поэтому только fade + вертикальный rise 12px. Шаг/кап
   каскада те же (наследуются из правила выше, меняем только transform). */
@media (max-width: 767px) {
	.ff-mp-price-section.ff-anim-ready .ff-mp-price tbody tr {
		transform: translateY(12px);
	}
}

.ff-mp-price-section.ff-anim-ready.is-visible .ff-mp-section__title,
.ff-mp-price-section.ff-anim-ready.is-visible .ff-mp-price thead,
.ff-mp-price-section.ff-anim-ready.is-visible .ff-mp-price tbody tr {
	opacity: 1;
	transform: none;
}

/* --- 16. MP-ADV («Почему селлеры WB») — карточки стаггером + иконка ---- */

.ff-mp-adv.ff-anim-ready .ff-mp-section__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-mp-adv.ff-anim-ready .ff-mp-adv-card {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 80ms), 550ms),
		transform 0.75s var(--ff-rv-ease) min(calc(var(--rvi, 0) * 80ms), 550ms);
}

/* Наследует --rvi от родителя .ff-mp-adv-card (custom properties каскадируют
   потомкам, тот же приём, что .ff-promise__bullet-icon) — overshoot-scale,
   +120ms сверх задержки своей карточки. */
.ff-mp-adv.ff-anim-ready .ff-mp-adv-card__icon {
	opacity: 0;
	transform: scale(0.6);
	transition:
		opacity 0.5s var(--ff-rv-ease-back) calc(min(calc(var(--rvi, 0) * 80ms), 550ms) + 120ms),
		transform 0.5s var(--ff-rv-ease-back) calc(min(calc(var(--rvi, 0) * 80ms), 550ms) + 120ms);
}

.ff-mp-adv.ff-anim-ready.is-visible .ff-mp-section__title,
.ff-mp-adv.ff-anim-ready.is-visible .ff-mp-adv-card,
.ff-mp-adv.ff-anim-ready.is-visible .ff-mp-adv-card__icon {
	opacity: 1;
	transform: none;
}

/* --- 17. MP-CTA («Получите расчёт») — карточка + внутренний каскад ----- */

.ff-mp-cta.ff-anim-ready .ff-mp-cta__card {
	opacity: 0;
	transform: scale(0.97) translateY(var(--ff-rv-shift));
	transition: opacity 0.8s var(--ff-rv-ease), transform 0.8s var(--ff-rv-ease);
}

.ff-mp-cta.ff-anim-ready .ff-mp-cta__title {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.7s var(--ff-rv-ease) 0.15s, transform 0.7s var(--ff-rv-ease) 0.15s;
}

.ff-mp-cta.ff-anim-ready .ff-mp-cta__subtitle {
	opacity: 0;
	transform: translateY(var(--ff-rv-shift));
	transition: opacity 0.65s var(--ff-rv-ease) 0.23s, transform 0.65s var(--ff-rv-ease) 0.23s;
}

.ff-mp-cta.ff-anim-ready .ff-mp-cta__input {
	opacity: 0;
	transform: translateY(14px);
	transition: opacity 0.6s var(--ff-rv-ease) 0.3s, transform 0.6s var(--ff-rv-ease) 0.3s;
}

.ff-mp-cta.ff-anim-ready .ff-mp-cta__input:nth-child(2) {
	transition-delay: 0.37s;
}

/* Кнопка сейчас не несёт СВОЕГО transition (filter на :hover/:focus меняется
   мгновенно — проверено computed-стилями на живой странице, transition-
   Duration 0s) — добавляем filter в общий список ЗДЕСЬ же, только под
   .ff-anim-ready (без JS кнопка ведёт себя ровно как раньше, прогрессивное
   улучшение), чтобы hover не ощущался резче самого reveal и заодно ничего
   не "затиралось" в смысле ТЗ: opacity/transform несут задержку-стаггер
   0.45s, filter — нет (иначе следующий hover после reveal ловил бы её же
   задержку, .is-visible ведь не снимается никогда). */
.ff-mp-cta.ff-anim-ready .ff-mp-cta__submit {
	opacity: 0;
	transform: scale(0.94);
	transition:
		opacity 0.55s var(--ff-rv-ease-back) 0.45s,
		transform 0.55s var(--ff-rv-ease-back) 0.45s,
		filter 0.15s ease;
}

.ff-mp-cta.ff-anim-ready .ff-mp-cta__note {
	opacity: 0;
	transition: opacity 0.55s var(--ff-rv-ease) 0.52s;
}

.ff-mp-cta.ff-anim-ready.is-visible .ff-mp-cta__card,
.ff-mp-cta.ff-anim-ready.is-visible .ff-mp-cta__title,
.ff-mp-cta.ff-anim-ready.is-visible .ff-mp-cta__subtitle,
.ff-mp-cta.ff-anim-ready.is-visible .ff-mp-cta__input,
.ff-mp-cta.ff-anim-ready.is-visible .ff-mp-cta__submit,
.ff-mp-cta.ff-anim-ready.is-visible .ff-mp-cta__note {
	opacity: 1;
	transform: none;
}

/* ==========================================================================
   КОНТАКТЫ — page 17
   Desktop frame 1920×1144 / mobile frame 360×1545.
   Text remains native Gutenberg content; only the functional form is HTML.
   ========================================================================== */

.page-id-17 main,
.editor-styles-wrapper .ff-contacts {
	margin-block: 0 !important;
}

.page-id-17 .wp-site-blocks > footer {
	margin-block-start: 0 !important;
}

.page-id-17 main > *,
.ff-contacts > *,
.ff-contacts__inner > *,
.ff-contacts__layout > *,
.ff-contacts__details > *,
.ff-contacts__list > *,
.ff-contacts__item > *,
.ff-contacts__card > * {
	margin-block-start: 0 !important;
	margin-block-end: 0 !important;
}

.ff-contacts {
	box-sizing: border-box;
	min-height: 620px;
	padding: 13px 0 70px;
	color: #1a1a2e;
}

.ff-contacts__inner {
	box-sizing: border-box;
	/* >=1024px only in practice — the two narrower tiers below
	   (641-1023 and <=640) each set their own fixed width and always
	   win there (later in the cascade), so growing --ff-gutter here
	   never touches their already-accepted layouts. */
	width: min(1170px, calc(100% - 2 * var(--ff-gutter)));
	max-width: 1170px !important;
	margin-inline: auto !important;
	position: relative;
	top: -30px;
}

.ff-contacts__breadcrumbs {
	gap: 5px;
	min-height: 17px;
	color: #b9b1c7;
	font-size: 14px;
	line-height: 17px;
}

.ff-contacts__breadcrumbs p,
.ff-contacts__breadcrumbs a {
	color: inherit;
	font: inherit;
	text-decoration: none;
}

.ff-contacts__breadcrumbs p:first-child,
.ff-contacts__breadcrumbs p:first-child a {
	color: #4a3d58;
}

.ff-contacts__layout {
	display: grid !important;
	grid-template-columns: minmax(0, 1fr) 575px;
	gap: 95px;
	align-items: start !important;
	margin-top: 49px !important;
}

.ff-contacts__details,
.ff-contacts__card {
	min-width: 0;
}

.ff-contacts__title {
	font-family: Inter, sans-serif;
	font-size: 64px;
	font-weight: 600;
	line-height: 1.25;
	letter-spacing: -0.02em;
}

.ff-contacts__list {
	display: grid;
	gap: 20px;
	margin-top: 20px !important;
}

.ff-contacts__item {
	display: grid;
	gap: 20px;
	min-height: 80px;
}

.ff-contacts__label {
	font-size: 20px;
	font-weight: 400;
	line-height: 30px;
}

.ff-contacts__value,
.ff-contacts__value a {
	color: #1a1a2e;
	font-size: 26px;
	font-weight: 600;
	line-height: 30px;
	text-decoration: none;
}

.ff-contacts__value a {
	transition: color 0.25s ease, opacity 0.25s ease;
}

.ff-contacts__value a:hover,
.ff-contacts__value a:focus-visible {
	color: #8f67ff;
}

.ff-contacts__card {
	box-sizing: border-box;
	width: 575px;
	height: 471px;
	padding: 40px;
	border-radius: 14px;
	background: #f6f5fc;
}

.ff-contacts__form-title {
	text-align: center;
	font-size: 32px;
	font-weight: 600;
	line-height: 50px;
}

.ff-contacts__form-copy {
	margin-top: 20px !important;
	text-align: center;
	font-size: 16px;
	font-weight: 400;
	line-height: 20px;
}

.ff-contacts__form {
	position: relative;
	display: grid;
	grid-template-columns: 1fr;
	gap: 12px;
	width: 351px;
	margin: 30px auto 0 !important;
}

@media (min-width: 1024px) {
	.ff-contacts__form {
		transform: translateX(-10px);
	}
}

.ff-contacts__input {
	box-sizing: border-box;
	width: 100%;
	height: 48px;
	padding: 0 17px;
	border: 1px solid #e8e5ef;
	border-radius: 10px;
	outline: 0;
	background: transparent;
	color: #1a1a2e;
	font: 400 16px/1 Inter, sans-serif;
	transition: border-color 0.25s ease, background-color 0.25s ease, box-shadow 0.25s ease;
}

.ff-contacts__input::placeholder {
	color: #8d898f;
	opacity: 1;
}

.ff-contacts__input:hover {
	border-color: #c9baff;
	background: rgba(255, 255, 255, 0.35);
}

.ff-contacts__input:focus-visible {
	border-color: #8f67ff;
	background: #fff;
	box-shadow: 0 0 0 3px rgba(143, 103, 255, 0.14);
}

.ff-contacts__input.is-invalid {
	border-color: #d73333;
}

.ff-contacts__consent {
	display: grid;
	grid-template-columns: 16px 1fr;
	gap: 11px;
	align-items: start;
	min-height: 54px;
	margin-top: 3px;
	color: #aba6b0;
	font-size: 12px;
	font-weight: 400;
	line-height: 18px;
	cursor: pointer;
}

.ff-contacts__consent input[type="checkbox"] {
	width: 16px;
	height: 16px;
	margin: 0;
	border-color: #e5e3e8;
	background: #ecebed;
	accent-color: #8f67ff;
}

.ff-contacts__consent input[type="checkbox"]:checked {
	border-color: #8f67ff;
	background: #8f67ff;
}

.ff-contacts__consent input[type="checkbox"]:checked::after {
	border-color: #fff;
}

.ff-contacts__consent span {
	color: #aba6b0;
	font-size: 12px;
	line-height: 18px;
	letter-spacing: 0;
}

.ff-contacts__consent a {
	color: #8f67ff;
	text-underline-offset: 2px;
	transition: color 0.25s ease;
}

.ff-contacts__consent a:hover,
.ff-contacts__consent a:focus-visible {
	color: #6c37d6;
}

.ff-contacts__consent.is-invalid {
	color: #b64141;
}

.ff-contacts__submit {
	box-sizing: border-box;
	width: 100%;
	height: 52px;
	margin-top: 6px;
	border: 0;
	border-radius: 999px;
	background: #8f67ff;
	color: #fff;
	font: 600 16px/20px Inter, sans-serif;
	cursor: pointer;
	transition: transform 0.25s ease, background-color 0.25s ease, box-shadow 0.25s ease;
}

.ff-contacts__submit:hover,
.ff-contacts__submit:focus-visible {
	background: #7c52f2;
	box-shadow: 0 10px 24px rgba(108, 55, 214, 0.24);
	transform: translateY(-1px);
}

.ff-contacts__submit:disabled {
	cursor: wait;
	opacity: 0.72;
	transform: none;
}

.ff-contacts .ff-lead-form__status {
	position: absolute;
	top: calc(100% + 6px);
	left: 0;
	width: 100%;
	margin: 0;
	text-align: center;
	font-size: 12px;
	line-height: 16px;
}

.ff-contacts .ff-lead-form__hp {
	position: absolute !important;
	left: -9999px !important;
	width: 1px !important;
	height: 1px !important;
	overflow: hidden !important;
}

.ff-contacts.ff-anim-ready .ff-contacts__breadcrumbs,
.ff-contacts.ff-anim-ready .ff-contacts__details,
.ff-contacts.ff-anim-ready .ff-contacts__card {
	opacity: 0;
	transform: translateY(20px);
	transition: opacity 0.7s var(--ff-rv-ease), transform 0.7s var(--ff-rv-ease);
}

.ff-contacts.ff-anim-ready .ff-contacts__details {
	transition-delay: 0.08s;
}

.ff-contacts.ff-anim-ready .ff-contacts__card {
	transition-delay: 0.16s;
}

.ff-contacts.ff-anim-ready.is-visible .ff-contacts__breadcrumbs,
.ff-contacts.ff-anim-ready.is-visible .ff-contacts__details,
.ff-contacts.ff-anim-ready.is-visible .ff-contacts__card {
	opacity: 1;
	transform: none;
}

@media (max-width: 1023px) and (min-width: 641px) {
	.ff-contacts {
		min-height: auto;
		padding: 28px 0 70px;
	}

	.ff-contacts__inner {
		width: min(704px, calc(100% - 64px));
		top: 0;
	}

	.ff-contacts__layout {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		gap: 32px;
		margin-top: 40px !important;
	}

	.ff-contacts__title {
		font-size: 48px;
	}

	.ff-contacts__card {
		width: 100%;
		height: auto;
		min-height: 471px;
		padding: 32px 24px;
	}

	.ff-contacts__form {
		width: 100%;
	}
}

@media (max-width: 640px) {
	.ff-contacts {
		min-height: 911px;
		padding: 20px 16px 46px;
	}

	.ff-contacts__inner {
		width: 100%;
		max-width: 328px !important;
		top: -4px;
	}

	.ff-contacts__breadcrumbs {
		display: none !important;
	}

	.ff-contacts__layout {
		display: block !important;
		margin-top: 0 !important;
	}

	.ff-contacts__title {
		font-size: 28px;
		line-height: 30px;
		letter-spacing: 0;
	}

	.ff-contacts__list {
		gap: 20px;
		margin-top: 20px !important;
	}

	.ff-contacts__item {
		gap: 20px;
		min-height: 80px;
	}

	.ff-contacts__label {
		font-size: 20px;
		line-height: 30px;
	}

	.ff-contacts__value,
	.ff-contacts__value a {
		font-size: 24px;
		line-height: 30px;
	}

	.ff-contacts__card {
		width: 100%;
		height: 465px;
		margin-top: 50px !important;
		padding: 24px 16px;
		border-radius: 12px;
	}

	.ff-contacts__form-title {
		font-size: 26px;
		line-height: 30px;
	}

	.ff-contacts__form-copy {
		margin-top: 20px !important;
		font-size: 15px;
		line-height: 19px;
	}

	.ff-contacts__form {
		width: 100%;
		margin-top: 32px !important;
	}

	.ff-contacts__input {
		height: 48px;
		padding-inline: 17px;
	}

	.ff-contacts__consent {
		grid-template-columns: 16px 1fr;
		gap: 11px;
		min-height: 74px;
		margin-top: 3px;
		font-size: 12px;
		line-height: 18px;
	}

	.ff-contacts__submit {
		height: 52px;
		margin-top: 5px;
	}

	.page-id-17 .ff-footer__navcontact {
		gap: 30px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.ff-contacts__value a,
	.ff-contacts__input,
	.ff-contacts__consent a,
	.ff-contacts__submit {
		transition: none;
	}

	.ff-contacts.ff-anim-ready .ff-contacts__breadcrumbs,
	.ff-contacts.ff-anim-ready .ff-contacts__details,
	.ff-contacts.ff-anim-ready .ff-contacts__card {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* ==========================================================================
   SHARED PUBLIC FORM CHECKBOX
   Matches the calculator service control: 18×18, 4px radius, white base,
   purple checked state and white tick. Scoped to lead forms so WordPress
   editor/admin controls and radio buttons remain native and untouched.
   ========================================================================== */

.ff-lead-form input[type="checkbox"] {
	appearance: none;
	-webkit-appearance: none;
	position: relative;
	box-sizing: border-box;
	flex: 0 0 18px;
	width: 18px;
	height: 18px;
	margin: 0;
	border: 1.5px solid #d9d4ee;
	border-radius: 4px;
	background-color: #fff;
	background-repeat: no-repeat;
	background-position: center;
	background-size: 62%;
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}

.ff-contacts__consent {
	grid-template-columns: 18px 1fr;
}

.ff-lead-form input[type="checkbox"]::after {
	content: none !important;
}

.ff-lead-form input[type="checkbox"]:hover:not(:disabled) {
	border-color: var(--wp--preset--color--brand-soft);
	box-shadow: 0 0 0 2px rgba(150, 113, 255, 0.14);
}

.ff-lead-form input[type="checkbox"]:checked {
	border-color: var(--wp--preset--color--brand-soft);
	background-color: var(--wp--preset--color--brand-soft);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='5 13 10 18 19 7'/%3E%3C/svg%3E");
}

.ff-lead-form input[type="checkbox"]:focus-visible {
	outline: 3px solid rgba(150, 113, 255, 0.32);
	outline-offset: 2px;
}

.ff-lead-form input[type="checkbox"]:disabled {
	opacity: 0.48;
	cursor: not-allowed;
}

.ff-lead-form input[type="checkbox"].is-invalid,
.ff-lead-form input[type="checkbox"][aria-invalid="true"],
.ff-lead-form .ff-lead-form__checkbox.is-invalid input[type="checkbox"] {
	border-color: var(--wp--preset--color--accent-red);
	box-shadow: 0 0 0 2px rgba(215, 51, 51, 0.18);
}

@media (prefers-reduced-motion: reduce) {
	.ff-lead-form input[type="checkbox"] {
		transition: none;
	}
}

/* ==========================================================================
   SMART PUBLIC SELECT
   Progressive enhancement for explicitly known front-end selects. The
   native control remains in the DOM/form as the source of truth; existing
   calculator dropdown, WordPress navigation/editor/admin stay untouched.
   ========================================================================== */

.ff-smart-select {
	position: relative;
	z-index: 1;
	box-sizing: border-box;
	width: 100%;
	min-width: 0;
	font-family: var(--wp--preset--font-family--inter);
}

.ff-smart-select.is-open {
	z-index: 80;
}

.ff-smart-select__native {
	position: absolute !important;
	width: 1px !important;
	height: 1px !important;
	margin: -1px !important;
	padding: 0 !important;
	overflow: hidden !important;
	clip: rect(0 0 0 0) !important;
	clip-path: inset(50%) !important;
	border: 0 !important;
	white-space: nowrap !important;
}

.ff-smart-select__button {
	display: flex;
	box-sizing: border-box;
	width: 100%;
	height: 46px;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 0 16px;
	border: 1px solid #ddd;
	border-radius: 10px;
	background: #fff;
	color: #3d2947;
	font: 400 16px/20px var(--wp--preset--font-family--inter);
	text-align: left;
	cursor: pointer;
	transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.ff-smart-select--ffg-mp .ff-smart-select__button {
	height: 48px;
}

.ff-smart-select__button:hover:not(:disabled) {
	border-color: #c9baff;
	background-color: #fcfaff;
}

.ff-smart-select__button:focus-visible,
.ff-smart-select.is-open .ff-smart-select__button {
	outline: none;
	border-color: var(--wp--preset--color--brand-soft);
	box-shadow: 0 0 0 3px rgba(150, 113, 255, 0.2);
}

.ff-smart-select__button:disabled {
	opacity: 0.52;
	cursor: not-allowed;
}

.ff-smart-select__value {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ff-smart-select__chevron {
	flex: 0 0 auto;
	width: 8px;
	height: 8px;
	margin-right: 2px;
	border-right: 1.5px solid var(--wp--preset--color--brand);
	border-bottom: 1.5px solid var(--wp--preset--color--brand);
	transform: translateY(-2px) rotate(45deg);
	transition: transform 0.2s ease;
}

.ff-smart-select.is-open .ff-smart-select__chevron {
	transform: translateY(2px) rotate(225deg);
}

.ff-smart-select__list {
	position: absolute;
	top: calc(100% + 8px);
	left: 0;
	box-sizing: border-box;
	width: 100%;
	min-width: 100%;
	max-width: calc(100vw - 24px);
	max-height: min(300px, calc(100vh - 24px));
	margin: 0;
	padding: 10px;
	overflow-x: hidden;
	overflow-y: auto;
	border: 0;
	border-radius: 16px;
	background: var(--wp--preset--color--white);
	box-shadow: 0 16px 40px rgba(26, 26, 46, 0.14);
	list-style: none;
	overscroll-behavior: contain;
	scrollbar-width: thin;
	scrollbar-color: rgba(108, 55, 214, 0.35) transparent;
	animation: ff-smart-select-in 0.2s ease both;
}

.ff-smart-select.is-up .ff-smart-select__list {
	top: auto;
	bottom: calc(100% + 8px);
	transform-origin: bottom center;
}

.ff-smart-select__list[hidden] {
	display: none;
}

.ff-smart-select__option {
	box-sizing: border-box;
	min-height: 40px;
	padding: 10px 14px;
	border-radius: 10px;
	color: #3d2947;
	font-size: 15px;
	line-height: 20px;
	cursor: pointer;
	transition: color 0.16s ease, background-color 0.16s ease;
}

.ff-smart-select__option:hover,
.ff-smart-select__option.is-active {
	background: var(--wp--preset--color--bg-lavender);
	color: var(--wp--preset--color--brand);
}

.ff-smart-select__option.is-selected {
	background: #f1ebff;
	color: var(--wp--preset--color--brand);
	font-weight: 600;
}

.ff-smart-select__option.is-disabled {
	opacity: 0.42;
	cursor: not-allowed;
}

@keyframes ff-smart-select-in {
	from {
		opacity: 0;
		transform: translateY(-6px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

@media (max-width: 640px) {
	.ff-smart-select__list {
		max-width: calc(100vw - 32px);
	}
}

@media (prefers-reduced-motion: reduce) {
	.ff-smart-select__button,
	.ff-smart-select__chevron,
	.ff-smart-select__option {
		transition: none;
	}

	.ff-smart-select__list {
		animation: none;
	}
}

/* =======================================================================
   FOOTER — TELEGRAM CONTACT LINE (боевые контакты, добавлено 2026-07-30).
   Новое правило, существующие футер-стили (см. ~3645) не трогаем.
   ======================================================================= */

.ff-footer__tg a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--wp--preset--color--white);
	font-family: var(--wp--preset--font-family--plus-jakarta-sans);
	font-weight: 600;
	font-size: 1rem;
	line-height: 1.125;
	text-decoration: none;
}

.ff-footer__tg svg {
	width: 18px;
	height: 18px;
	flex-shrink: 0;
}

/* =======================================================================
   КОНТАКТЫ — ЗНАЧОК TELEGRAM ВМЕСТО НИКА (боевой запрос, добавлено 2026-08-08).
   SVG идентичен футеру (.ff-footer__tg), крупнее — 28px, т.к. строка
   значения на этой странице крупная. Параграф зафиксирован на высоте 30px
   (как текстовые значения телефона/e-mail), чтобы вертикальный ритм списка
   .ff-contacts__list не сдвинулся. Тап-таргет 44x44 сделан через ::after
   с отрицательным inset — он вне потока и не влияет на раскладку.
   ======================================================================= */

.ff-contacts__value--tg {
	display: flex;
	align-items: center;
	height: 30px;
}

.ff-contacts__value--tg a {
	position: relative;
	display: inline-flex;
	align-items: center;
}

.ff-contacts__value--tg svg {
	width: 28px;
	height: 28px;
	flex-shrink: 0;
}

.ff-contacts__value--tg a::after {
	content: "";
	position: absolute;
	inset: -8px;
}

