/*
 * Shell — header, navigation, footer, language switcher.
 *
 * Every value here is a theme.json token (var(--wp--preset--*) / var(--wp--custom--*)). No
 * hardcoded colours, sizes or spacing: if something needs a value that is not a token, the
 * token set is wrong and gets fixed there, not patched here. That discipline is what the
 * previous theme lacked — 251 selectors with colours written inline per rule.
 *
 * Layout is CSS Grid and flow, and every responsive decision is a CONTAINER query: the
 * header rearranges according to the width IT has, not the viewport's. The old theme wrote
 * its column counts into the markup (col-md-3 / col-sm-6 / col-xs-6, 90 occurrences), so a
 * layout change meant editing templates.
 *
 * The only literal numbers are the 44px pointer-target floor (an accessibility constant, not
 * a design value) and icon dimensions.
 */

/* ========================================================================== *
 * Global box model
 * ========================================================================== *
 *
 * There is no base.css in this theme (DESIGN.md assumes one; it was never written), so
 * nothing established a box model and every element inherited the CSS default of
 * `content-box`. Measured at a real 390px viewport: `.nv-hero__inner` sets `width: 100%`
 * plus `padding-inline`, and rendered 430px wide inside a 390px viewport — its last 20px,
 * including the tail of the h1, sat outside the screen and was clipped by the hero's
 * `overflow: hidden` (so it never showed up as document scrollWidth, which is why it was
 * invisible to an overflow check).
 *
 * Every component in this theme is written as though border-box were in force. This makes
 * that true rather than accidentally true. shell.css carries it because it is the only
 * stylesheet enqueued on every page — the others load per template from inc/.
 */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* ========================================================================== *
 * Header
 * ========================================================================== */

.nv-header {
	position: relative;   /* the menu panel is positioned against the header, not its cell */
	background: var(--wp--preset--color--base);
	border-block-end: 1px solid var(--wp--preset--color--border);
	container-type: inline-size;
	container-name: header;
}

/*
 * THE UTILITY STRIP IS GONE — see parts/header.html for the reasoning, and note that it is
 * removed rather than hidden, so there is no `.nv-header__utility` rule here to hide. All the
 * rules that dressed it (`__utility`, `__utility-inner`, `__utility-end`, `.nv-contact--utility`,
 * `.nv-menu--inline`, `.nv-auth*`) went with it: each was grepped first and had exactly one
 * call site, the strip, except `.nv-auth*`, whose block has rendered an empty string since the
 * account links were removed.
 */

/* ---------- the one row ---------- */
/*
 * ONE ROW AT EVERY WIDTH, AND IT IS A GRID.
 *
 *     >= 72rem   brand | NAVIGATION | phone | language | cart
 *     <  72rem   brand | phone | cart | menu          (language moves into the menu panel)
 *
 * Grid, not flex, and this is the load-bearing decision. As a flex row the brand was the only
 * shrinkable item, so at 390px it collapsed to 51.4px while the 163.8px logo inside it kept
 * its size and simply painted over the control beside it — a 97.4px overlap of the language
 * switcher, measured, and invisible to any overflow check because `scrollWidth` stayed 390.
 *
 * Here the brand is `minmax(0, 1fr)` and every other object is an `auto` track. The brand
 * therefore receives exactly the space that is left after the controls have taken theirs, and
 * the logo is capped at `100%` of it. Overlap is not "unlikely"; it is not expressible.
 *
 * Order is CSS, so the DOM stays in reading order.
 */

.nv-header__main,
.nv-footer__inner,
.nv-footer__bottom {
	max-inline-size: var(--wp--style--global--content-size, 1280px);
	margin-inline: auto;
	padding-inline: var(--wp--preset--spacing--sm);
}

/*
 * These wrappers are `wp-block-group … is-layout-flow`, so WordPress's flow layout emits
 * `> * + * { margin-block-start: var(--wp--style--block-gap) }` — 30px — for them. The theme
 * then lays them out as flex/grid, where that margin is not rhythm between stacked blocks but
 * dead space between rows. Zeroing it is what removed the last of the header's empty bands;
 * the `gap` below is what actually spaces these.
 */
.nv-header__main > *,
.nv-footer__inner > *,
.nv-footer__bottom > * {
	margin-block: 0;
}

.nv-header__main {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto auto auto;
	align-items: center;
	gap: var(--wp--preset--spacing--xxs);
	padding-block: var(--wp--preset--spacing--xxs);
}

/* LOGO · PHONE ICON · CART · MENU. */
.nv-header__brand              { order: 1; }
.nv-header__main > .nv-contact--header { order: 2; }
.nv-header__main > .nv-cart    { order: 3; }
.nv-header__nav                { order: 4; }

/* The switcher a phone sees is the copy inside the menu panel; this one has no room in a
   350px row and is not merely small here, it has no box. */
.nv-header__main > .nv-lang {
	display: none;
}

.nv-header__brand {
	display: flex;
	align-items: center;
	min-inline-size: 0;   /* a grid item's automatic minimum is its content; this removes it */
}

/*
 * `inline-size: 180px` is the wanted size and `max-inline-size: 100%` is the promise. In the
 * `auto` brand track of the desktop row the first wins and the logo is 180px; in the
 * `minmax(0, 1fr)` track of the mobile row the second wins and the logo is exactly as wide as
 * the leftover space, never wider. The old `min(180px, 42vw)` cap could not do this: 42vw is a
 * fact about the VIEWPORT, and the space left in the row is not.
 */
.nv-header__brand .wp-block-site-logo,
.nv-header__brand .custom-logo-link {
	min-inline-size: 0;
	max-inline-size: 100%;
}

.nv-header__brand .wp-block-site-logo img {
	display: block;
	inline-size: 180px;
	max-inline-size: 100%;
	block-size: auto;
}

/*
 * The logo is an 890x112 wordmark, so at its display width it is only ~23px tall and the link
 * around it was a 23px target. Padding to the 44px floor costs no height the row did not
 * already have.
 */
.nv-header__brand .custom-logo-link {
	display: flex;
	align-items: center;
	min-block-size: 44px;
}

.nv-header__nav {
	display: flex;
	align-items: center;
	min-inline-size: 0;
}

/* ---------- >= 72rem: navigation goes inline, the toggle and the panel dissolve ---------- */
/*
 * 72rem = 1152px, and the number is arithmetic, not convention. Measured at 1440: the five
 * top-level items occupy 502.3px in Russian (477.8 in Ukrainian) plus four 5px gaps = 522.3.
 * Everything else in the row is fixed: 180 logo + 94.4 phone + 89 language + 77 cart + four
 * 20px gaps + 40px padding = 560.4. The navigation therefore needs a 1,082.7px header before
 * it fits on one line, so 62rem (992px) could not carry it — measured, and `Контакты` sat on
 * a second row at 1024 with 463.6px of track against 522.3px of content. 72rem leaves 69.3px
 * of slack, ~13%, which is the room a translation edit needs.
 *
 * The cost is explicit: at 1024 the navigation is the panel, not an inline row. That is the
 * trade the width budget forces, and the alternative — shrinking the type or the targets to
 * make five items fit 463px — is the one thing this rebuild is not allowed to do.
 */
@container header (inline-size >= 72rem) {
	.nv-header__main {
		grid-template-columns: auto minmax(0, 1fr) auto auto auto;
		gap: var(--wp--preset--spacing--sm);
		padding-block: var(--wp--preset--spacing--xs);
	}

	.nv-header__brand                      { order: 1; }
	.nv-header__nav                        { order: 2; }
	.nv-header__main > .nv-contact--header { order: 3; }
	.nv-header__main > .nv-lang            { order: 4; display: block; }
	.nv-header__main > .nv-cart            { order: 5; }

	.nv-header__nav {
		justify-content: center;
	}
}


/* ========================================================================== *
 * Breadcrumbs
 * ========================================================================== *
 *
 * WooCommerce's trail, styled for colour by catalog.css and product.css but sized here: the
 * links measured 47x17 at 390px. This rule is in shell.css rather than in either of those
 * because /cart/ renders a breadcrumb and loads NEITHER of them (its sheets are shell,
 * commerce, components and content) — verified by reading document.styleSheets on the page.
 *
 * Cost of the floor, measured on /product/sfericheskoe-zerkalo-k300/ at 390px: the whole
 * trail grows 46px -> 67px.
 */
.woocommerce-breadcrumb a {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
}

/* ========================================================================== *
 * Contact details
 * ========================================================================== */

.nv-contact--header {
	display: flex;
	align-items: center;
	line-height: 1.3;
}

/*
 * THE PHONE IS THE SMALLEST TYPE IN THE HEADER, NOT THE LARGEST.
 *
 * It rendered at `md`/700 — 17.7px bold at 1440, measured — which made a number nobody reads
 * until they have decided to call the loudest string in the chrome, louder than the navigation
 * and level with the page's primary action. Both B2B references set their header phone in the
 * smallest type they use. `sm`/400 is this system's "small" role (design-system.md §2.1).
 */
.nv-contact--header .nv-contact__phone {
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 400;
	white-space: nowrap;
}

/*
 * Below 48rem the phone is an ICON. The number is not deleted from the document and not
 * `display: none`d — it is CLIPPED, so it remains the link's accessible name and the control a
 * screen reader announces is still "(063) 440-99-66". What changes is that it stops asking a
 * 350px row for 100px it does not have.
 */
.nv-contact__text {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.nv-contact--header .nv-contact__link {
	justify-content: center;
	min-inline-size: 44px;
}

.nv-contact__icon {
	flex: none;
}

@container header (inline-size >= 48rem) {
	.nv-contact__text {
		position: static;
		inline-size: auto;
		block-size: auto;
		overflow: visible;
		clip-path: none;
	}

	.nv-contact__icon {
		display: none;
	}
}

/*
 * Contact details are links people tap — a phone number on a phone is the most likely tap on
 * the page — but they rendered as bare inline text: measured at 390px, the e-mail link was
 * 129x17 and each phone number 107x21, against the 44px floor this theme states as a
 * non-negotiable. `inline-flex` is what lets a minimum block size apply at all; an inline box
 * ignores it.
 */
.nv-contact__link {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	color: inherit;
	text-decoration: none;
}

.nv-contact__link:hover {
	color: var(--wp--preset--color--brand);
	text-decoration: underline;
}

.nv-contact--footer .nv-contact__row {
	margin-block: 0 var(--wp--preset--spacing--xxxs);
	font-size: var(--wp--preset--font-size--sm);
}

/* ========================================================================== *
 * Menus — one component, three shapes (inline, primary, stacked)
 * ========================================================================== */

.nv-menu__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.nv-menu__list a {
	display: flex;
	align-items: center;
	min-block-size: 44px;   /* pointer-target floor; the old text links were ~16px tall */
	padding-inline: var(--wp--preset--spacing--xxs);
	color: inherit;
	text-decoration: none;
	line-height: 1.25;
}

.nv-menu__list a:hover {
	color: var(--wp--preset--color--brand);
}

.nv-menu__list a:focus-visible {
	outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--accent);
	outline-offset: var(--wp--custom--focus--offset);
}

/* Current page: an attribute, not a class, so the visible and the announced state are the
   same fact. */
.nv-menu__list a[aria-current="page"] {
	color: var(--wp--preset--color--brand);
	font-weight: 700;
}

/* ---------- stacked: the two footer menus ---------- */

.nv-menu--stacked .nv-menu__list a {
	padding-inline: 0;
	font-size: var(--wp--preset--font-size--sm);
}

/* ---------- primary: the 22-item main navigation ---------- */

.nv-menu__toggle {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--xxs);
	min-block-size: 44px;
	min-inline-size: 44px;
	padding-inline: var(--wp--preset--spacing--xxs);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--wp--custom--radius--md);
	background: var(--wp--preset--color--base);
	color: var(--wp--preset--color--contrast);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 700;
	cursor: pointer;
}

.nv-menu__toggle:focus-visible {
	outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--accent);
	outline-offset: var(--wp--custom--focus--offset);
}

/* Three bars drawn with the border box and two pseudo-elements — no icon font, no image. */
.nv-menu__bars,
.nv-menu__bars::before,
.nv-menu__bars::after {
	display: block;
	inline-size: 20px;
	block-size: 2px;
	background: currentColor;
}

.nv-menu__bars {
	position: relative;
}

.nv-menu__bars::before,
.nv-menu__bars::after {
	content: "";
	position: absolute;
	inset-inline-start: 0;
}

.nv-menu__bars::before { inset-block-start: -6px; }
.nv-menu__bars::after  { inset-block-start: 6px; }

/* Below 48rem the toggle is the bars alone: the word is clipped, not removed, so the button
   keeps "Меню" as its accessible name while costing the row 44px instead of ~92px. */
.nv-menu__toggle-text {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

@container header (inline-size >= 48rem) {
	.nv-menu__toggle-text {
		position: static;
		inline-size: auto;
		block-size: auto;
		overflow: visible;
		clip-path: none;
	}
}

/* ---------- the mobile panel ---------- */
/*
 * A FULL-WIDTH SHEET BELOW THE HEADER, NOT A COLUMN INSIDE IT.
 *
 * Before: the list was a static child of one cell of the header row, so opening it opened it
 * in that cell — 141.8px wide and 1,132.5px tall at 390px (122.7 x 1,182.3 on /ua/), with 22
 * links wrapping inside 142px, and the header itself grew to 1,212.5px. Measured.
 *
 * Taking the panel out of flow fixes it at the root. The containing block is `.nv-header` (it
 * is `position: relative`, and `container-type` would make it one anyway), so `inset-inline: 0`
 * is the header's full width and `inset-block-start: 100%` is immediately below it — by
 * construction, at every width, without a magic offset.
 *
 * The height cap is the one place this design cannot have everything: 22 links at the 44px
 * floor need 968px before they even wrap, and shrinking them below 44px is not on the table.
 * The cap is therefore `min(80svh, 52rem)` — tall enough that the panel does NOT scroll at 768
 * or 1024, where the multi-column layout brings the content to ~814px and ~770px, and bounded
 * by the viewport on a phone, where 22 links in one column are ~1,078px and scrolling is the
 * only honest answer. The research's flat ~480px panel assumes the six-family menu; that is a
 * MENU-STRUCTURE change (Priority 2) and is not this task's to make.
 */
.nv-menu--primary .nv-menu__panel {
	display: none;
	position: absolute;
	inset-inline: 0;
	inset-block-start: 100%;
	z-index: 30;
	max-block-size: min(80svh, 52rem);
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: var(--wp--preset--spacing--sm);
	background: var(--wp--preset--color--base);
	border-block-start: 1px solid var(--wp--preset--color--border);
	/* The site's ONE shadow (design-system.md §8): floating layers only. */
	box-shadow: 0 8px 40px rgb(0 0 0 / 24%);
}

.nv-menu--primary.nv-menu--open .nv-menu__panel {
	display: block;
}

/*
 * The panel's own layout: one column on a phone, as many 17rem columns as fit above that. At
 * 768px that is two and at 1024px three, which is what keeps the panel off the scrollbar there.
 *
 * MULTICOL, NOT GRID, and the difference is visible. A grid aligns rows, so `Головна` (one
 * link) shared a row with `Каталог продукції` (nine) and its cell was padded out to the taller
 * one — measured at 768: a ~550px void in the first column. Multicol flows and balances
 * instead, so the groups pack.
 */
.nv-menu--primary .nv-menu__panel > .nv-menu__list {
	columns: 17rem;
	column-gap: var(--wp--preset--spacing--md);
}

.nv-menu--primary .nv-menu__panel > .nv-menu__list > li {
	break-inside: avoid;
}

.nv-menu--primary .nv-menu__panel > .nv-menu__list > li > a {
	font-weight: 700;
}

/* In the panel every submenu is simply visible — no second level of tapping, and nothing
   that depends on hover, which a touch screen does not have. */
.nv-menu--primary .sub-menu {
	margin: 0;
	padding-inline-start: var(--wp--preset--spacing--sm);
	list-style: none;
}

.nv-menu--primary .sub-menu a {
	color: var(--wp--preset--color--text-muted);
	font-size: var(--wp--preset--font-size--sm);
}

/* The language switcher, in the panel, below the links it is not part of. */
.nv-menu__lang {
	margin-block-start: var(--wp--preset--spacing--xs);
	padding-block-start: var(--wp--preset--spacing--xxs);
	border-block-start: 1px solid var(--wp--preset--color--border);
}

@container header (inline-size >= 72rem) {
	.nv-menu--primary .nv-menu__toggle {
		display: none;
	}

	/*
	 * `display: contents` dissolves the panel: no box, so no absolute positioning, no padding,
	 * no shadow and no scroll container — the list becomes a child of the nav and lays itself
	 * out inline. Both selectors are written because `.nv-menu--primary.nv-menu--open
	 * .nv-menu__panel` outranks a one-class version, and a panel left open on a phone that is
	 * then rotated must not stay a sheet.
	 */
	.nv-menu--primary .nv-menu__panel,
	.nv-menu--primary.nv-menu--open .nv-menu__panel {
		display: contents;
	}

	/* One switcher at a time: this copy has no box while the header's own is showing. */
	.nv-menu__lang {
		display: none;
	}

	.nv-menu--primary .nv-menu__panel > .nv-menu__list {
		columns: auto;
		display: flex;
		flex-wrap: wrap;
		justify-content: center;
		gap: var(--wp--preset--spacing--xxxs);
	}

	.nv-menu--primary .nv-menu__panel > .nv-menu__list > li {
		position: relative;
	}

	.nv-menu--primary .nv-menu__panel > .nv-menu__list > li > a {
		padding-inline: var(--wp--preset--spacing--xxs);
		font-weight: 700;
		text-transform: uppercase;
		letter-spacing: 0.02em;
		font-size: var(--wp--preset--font-size--xs);
	}

	/*
	 * Submenus. Opened by :hover AND :focus-within — the second half is what makes them
	 * keyboard-operable without a line of JavaScript: tabbing into a child link opens the
	 * panel, tabbing past the last one closes it. The old theme's dropdowns were hover-only
	 * and unreachable by keyboard.
	 */
	.nv-menu--primary .sub-menu {
		position: absolute;
		inset-block-start: 100%;
		inset-inline-start: 0;
		z-index: 20;
		display: none;
		min-inline-size: 18rem;
		max-inline-size: 26rem;
		padding: var(--wp--preset--spacing--xxs);
		background: var(--wp--preset--color--base);
		border: 1px solid var(--wp--preset--color--border);
		border-radius: var(--wp--custom--radius--lg);
	}

	.nv-menu--primary .nv-menu__panel > .nv-menu__list > li:hover > .sub-menu,
	.nv-menu--primary .nv-menu__panel > .nv-menu__list > li:focus-within > .sub-menu {
		display: block;
	}

	.nv-menu--primary .sub-menu a {
		color: var(--wp--preset--color--contrast);
		font-size: var(--wp--preset--font-size--sm);
	}

	.nv-menu--primary .sub-menu a:hover {
		color: var(--wp--preset--color--brand);
	}

	/* The last two top-level items would push their panels off the inline end. */
	.nv-menu--primary .nv-menu__panel > .nv-menu__list > li:nth-last-child(-n+2) > .sub-menu {
		inset-inline-start: auto;
		inset-inline-end: 0;
	}
}

/* ========================================================================== *
 * Cart
 * ========================================================================== */

/*
 * TYPE-QUALIFIED ON PURPOSE — `a.nv-cart`, not `.nv-cart`.
 *
 * `nv-cart` names two different things in this theme: the header's cart button (an <a>,
 * rendered by inc/shell.php) and the cart PAGE's <main> (templates/page-cart.html), which
 * commerce.css targets as `.nv-cart .shop_table`, `.nv-cart .cart_totals` and so on. While
 * these rules were unqualified, the button's skin also applied to that <main>, so the cart
 * page's entire content area became an `inline-flex` box with a border and a 44px floor.
 *
 * Measured at 390px: <main> was inline-flex, the cart form shrank to a 159px flex item
 * pushed to x=220, and its table overflowed to x=438 — 48px of horizontal page scroll on
 * /cart/ (76px before the box-sizing reset above). Qualifying by element fixes it without
 * touching commerce.css or renaming the template class that commerce.css depends on.
 */
a.nv-cart {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--xxs);
	min-block-size: 44px;
	padding-inline: var(--wp--preset--spacing--xxs);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--wp--custom--radius--md);
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--sm);
	text-decoration: none;
	transition: border-color var(--wp--custom--transition--base), color var(--wp--custom--transition--base);
}

a.nv-cart:hover {
	border-color: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand);
}

a.nv-cart:focus-visible {
	outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--accent);
	outline-offset: var(--wp--custom--focus--offset);
}

.nv-cart__icon {
	flex: none;
}

.nv-cart__count {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-inline-size: 1.5em;
	padding-inline: var(--wp--preset--spacing--xxxs);
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--base);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	line-height: 1.6;
}

/*
 * ICON AND COUNT. THE SENTENCE IS NEVER PAINTED, AT ANY WIDTH.
 *
 * "Ваша корзина ещё пуста" / "N товаров на сумму …" stays in the document — it is the cart's
 * accessible name — but it is clipped at every width, including desktop, where an earlier
 * rule un-hid it above 62rem. Painted, it made the cart 229.5px wide and that is what pushed
 * `Контакты` onto a second line at 1440. A cart in a header is an icon and a count.
 */
.nv-cart__label {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ========================================================================== *
 * Language switcher
 * ========================================================================== */

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

/* The hairline between the two, and the only rule that draws anything here. */
.nv-lang__item + .nv-lang__item {
	border-inline-start: 1px solid var(--wp--preset--color--border);
}

/*
 * THE CURRENT LANGUAGE IS NOT A CALL TO ACTION — AND THE OTHER ONE IS NOT EITHER.
 *
 * Two defects, one rule. The first was that the active link carried `background: brand` +
 * 700 + 44px, pixel-for-pixel the primary-CTA treatment, for a control that only tells you
 * where you already are. The second survived that fix: `font-weight: 700` and a full border
 * were set on BOTH links, so the pair read as two pills and neither looked current — the one
 * state the control exists to express was the one it did not show.
 *
 * design-system.md §9.1 specifies the treatment: two `xs` text controls separated by a
 * hairline, active at 700 `contrast`, inactive at 400 `text-muted`, no fill and no border on
 * either, the whole pair inside a 44px row so both remain valid touch targets. Weight and
 * colour now carry the state and nothing else does, so exactly one of them can look current.
 */
.nv-lang__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: 44px;   /* pointer target floor — the old text links were ~16px tall */
	min-inline-size: 44px;
	padding-inline: var(--wp--preset--spacing--xxxs);
	border: 0;
	background: none;
	color: var(--wp--preset--color--text-muted);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 400;
	line-height: 1;
	text-decoration: none;
	transition: color var(--wp--custom--transition--base);
}

.nv-lang__link:hover {
	color: var(--wp--preset--color--brand);
}

/* aria-current, not a class: the state is already in the markup for assistive tech, so
   styling the same attribute keeps the two from drifting apart. */
.nv-lang__link[aria-current="true"] {
	color: var(--wp--preset--color--contrast);
	font-weight: 700;
}

.nv-lang__link:focus-visible {
	outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--accent);
	outline-offset: var(--wp--custom--focus--offset);
}

/* ========================================================================== *
 * Footer
 * ========================================================================== */

/*
 * The footer is ONE band, not four boxes.
 *
 * Measured before this pass: every column carried a full-width rule under its heading, every
 * link row was a 44px block, and the band opened and closed with `xl` padding — so four
 * headings each drew their own edge and the columns read as separate islands stacked in a
 * dark rectangle. Three things fix that, and they are the ordinary rules for a site footer:
 *
 *   1. NO per-column divider. A footer heading is a label, not a section edge — the only
 *      hairline in here is the one above the copyright row, which separates two genuinely
 *      different kinds of thing. Columns are separated by space alone.
 *   2. Headings are quiet. They are `xs` uppercase at reduced opacity, so the LINKS are the
 *      strongest thing in the band; before, four `md` headings each with a rule under it
 *      outweighed the content they labelled.
 *   3. Link rows are as tall as a link, not as tall as a touch target. The 44px floor still
 *      applies where a finger is the pointer — `@media (pointer: coarse)` — but on a mouse a
 *      44px row inside a 5-item list adds ~80px of nothing per column, which is most of the
 *      height the band did not need.
 *
 * The column gap is wider than the row gap on purpose: horizontal space is what tells two
 * columns apart once the dividers are gone.
 */

.nv-footer {
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--base);
	margin-block-start: var(--wp--preset--spacing--lg);
	padding-block: var(--wp--preset--spacing--lg);
	container-type: inline-size;
	container-name: footer;
}

.nv-footer__inner {
	display: grid;
	column-gap: var(--wp--preset--spacing--lg);
	row-gap: var(--wp--preset--spacing--md);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
}

/* Two classes deep so it beats the block's own `has-md-font-size` regardless of which
   stylesheet the browser loaded last. */
.nv-footer .nv-footer__heading {
	margin-block: 0 var(--wp--preset--spacing--xxs);
	padding-block-end: 0;
	border-block-end: 0;
	color: var(--wp--preset--color--base);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	opacity: 0.65;
}

.nv-footer a {
	color: var(--wp--preset--color--base);
}

.nv-footer a:hover,
.nv-footer .nv-menu__list a:hover {
	color: var(--wp--preset--color--accent-light);
}

/*
 * Row height: the link's own height plus a little, instead of the 44px block the header
 * navigation needs. `.nv-menu__list a` is `display: flex` for the header's icon rows; here
 * there is nothing to align, so it goes back to being text that wraps.
 */
.nv-footer .nv-menu__list a,
.nv-footer .nv-contact__link {
	display: inline-block;
	min-block-size: 0;
	padding-block: var(--wp--preset--spacing--xxxs);
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.35;
}

.nv-footer .nv-contact--footer .nv-contact__row {
	margin-block: 0;
}

/* Where the pointer is a finger, the 44px floor comes back. */
@media (pointer: coarse) {
	.nv-footer .nv-menu__list a,
	.nv-footer .nv-contact__link {
		display: flex;
		align-items: center;
		min-block-size: 44px;
		padding-block: 0;
	}
}

/* The one line of company fact under the footer's useful-links column: quieter than a link,
   but on the dark ground it borrows the footer's own colour rather than the muted token. */
.nv-footer__note {
	margin-block: var(--wp--preset--spacing--xxs) 0;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.4;
	opacity: 0.7;
}

.nv-social {
	margin-block-start: var(--wp--preset--spacing--xs);
}

/*
 * The block's default anchor is a 24x24 icon box. On a phone these three are the only
 * targets in the footer's social row and they sat at barely half the 44px floor — measured
 * 24x24 on the home page. The icon keeps its size; the hit area grows around it.
 */
.nv-social .wp-block-social-link-anchor {
	display: flex;
	align-items: center;
	justify-content: center;
	min-inline-size: 44px;
	min-block-size: 44px;
	color: var(--wp--preset--color--base);
}

.nv-social .wp-block-social-link-anchor:hover {
	color: var(--wp--preset--color--accent-light);
}

/*
 * The only hairline in the band. `currentColor` at full strength was a white rule across a
 * dark footer — louder than the copyright line it sits above.
 */
.nv-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--xs);
	margin-block-start: var(--wp--preset--spacing--md);
	padding-block-start: var(--wp--preset--spacing--sm);
	border-block-start: 1px solid color-mix(in srgb, currentColor 25%, transparent);
	font-size: var(--wp--preset--font-size--sm);
}

.nv-copyright {
	margin: 0;
}

/* ========================================================================== *
 * Back-to-top
 * ========================================================================== *
 *
 * Still an in-page anchor to the header's `id`, so it works with scripting off and needs no
 * script of its own. What changed is WHERE it is.
 *
 * IT USED TO SIT IN THE FOOTER'S FLOW, and that was wrong twice over. Measured on the home
 * page at 1440×900: the footer's content column runs x 70→1350, and the button rendered at
 * x 0 — outside the container entirely, clipped against the viewport's left edge, aligned
 * with nothing. And being the footer's last child it owned a full-width row to itself:
 * 30px margin + 44px button + the footer's 32px bottom padding, a ~106px band that was empty
 * apart from one small circle. A back-to-top control at the bottom of the footer is also the
 * one place it cannot help, because reaching it means already having scrolled to the bottom.
 *
 * Now it is pinned to the viewport's bottom-inline-end corner and reveals itself once the
 * reader is roughly a screen down. Taking it out of flow is what removes the empty band —
 * there is no compensating length anywhere, so nothing here can drift out of step with the
 * footer's own spacing.
 *
 * `position: fixed` is why the block is a SIBLING of `<footer>` in parts/footer.html rather
 * than a child: `.nv-footer` declares `container-type: inline-size`, and a container query
 * container is a containing block for its fixed descendants. Inside the footer this would
 * pin to the footer's box. Verified the new parent chain is clear — `.wp-block-template-part`,
 * `.wp-site-blocks` and `body` carry no `container-type`, `transform`, `filter`,
 * `perspective` or `contain`.
 *
 * Z-INDEX 50 places it above the sticky catalogue/nav furniture (30 and 40) and below the
 * mobile drawer and its scrim (60/61), which must be able to cover it. Raw integers match
 * how every other layer in this theme is written; there is no z-index token to reach for.
 */
.nv-totop {
	position: fixed;
	inset-block-end: var(--wp--preset--spacing--sm);
	inset-inline-end: var(--wp--preset--spacing--sm);
	z-index: 50;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-inline-size: var(--wp--custom--touch--icon);
	min-block-size: var(--wp--custom--touch--icon);
	border: 1px solid var(--wp--preset--color--brand-dark);
	border-radius: var(--wp--custom--radius--full);
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--base);
	box-shadow: 0 8px 40px rgb(0 0 0 / 24%);
	text-decoration: none;
	transition: background var(--wp--custom--transition--base), color var(--wp--custom--transition--base);
}

.nv-totop:hover {
	background: var(--wp--preset--color--brand-dark);
	color: var(--wp--preset--color--base);
}

.nv-totop:focus-visible {
	outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--accent);
	outline-offset: var(--wp--custom--focus--offset);
}

/*
 * Reveal on scroll, with no JavaScript: a scroll-progress timeline over the root scroller.
 * `animation-range` runs the fade across the second half of the first viewport height, so the
 * control is absent while the reader is still on the opening screen — where it would only be
 * covering content it cannot help with — and settled by the time they are one screen down.
 *
 * `visibility` rather than `opacity` alone: an `opacity: 0` control is still in the tab order
 * and still announced, so a keyboard user would land on an invisible button. With
 * `animation-fill-mode: both`, scroll positions before the range hold the 0% frame, so it is
 * genuinely `hidden` up there.
 *
 * BEHIND `@supports` DELIBERATELY. Firefox has no scroll-driven animations yet; there it
 * falls through to the rules above and the button is simply always visible, which is the
 * ordinary floating back-to-top and costs a reader nothing. Nothing is hidden by default and
 * then revealed by an enhancement, so a browser that supports neither cannot end up with an
 * unreachable control. `prefers-reduced-motion` is not consulted: this is an opacity change
 * with no travel, and suppressing it would leave the button permanently on screen.
 */
@supports (animation-timeline: scroll()) {
	.nv-totop {
		/*
		 * The resting state is hidden, and it is safe to write it HERE and only here: every
		 * browser that enters this block can run the animation that reveals it. Measured why
		 * it is needed — a scroll timeline is inactive until its scroller is actually
		 * scrollable, and during load the document is still short, so the button painted
		 * bottom-right for the first few hundred milliseconds of every page load and then
		 * vanished. The one case where the timeline never activates is a page too short to
		 * scroll, and there the control stays hidden, which is the right answer: there is no
		 * "top" to go back to.
		 */
		visibility: hidden;
		opacity: 0;
		animation: nv-totop-reveal linear both;
		animation-timeline: scroll(root block);
		animation-range: 50vh 100vh;
	}

	@keyframes nv-totop-reveal {
		from {
			visibility: hidden;
			opacity: 0;
		}

		to {
			visibility: visible;
			opacity: 1;
		}
	}
}

/*
 * YITH's compare bar pins itself across the full width of the viewport's bottom edge while
 * anything is in the comparison, and it is 130px tall at 1440 — taller once its text wraps.
 * The two controls want the same corner.
 *
 * Standing the button off by the bar's height is not available: that height is whatever the
 * plugin's thumbnails, wrapped text and button add up to, it differs per viewport AND per
 * language, and the rule below `body #yith-woocompare-preview-bar` exists precisely because
 * this file refuses to name it. So the button yields instead. It is a convenience that
 * duplicates the Home key; the compare bar is a task the customer is in the middle of.
 *
 * `.shown` is the plugin's own state class — it adds it when the first product is compared —
 * so this follows the bar automatically and needs no state of its own.
 */
body:has(#yith-woocompare-preview-bar.shown) .nv-totop {
	display: none;
}

/* ========================================================================== *
 * Shared
 * ========================================================================== */

.screen-reader-text {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/*
 * No `:focus` rule for the skip link here on purpose. WordPress core already ships
 * `.skip-link.screen-reader-text:focus` (clip-path: none; height/width: auto; padding:
 * 15px 23px 14px), which reveals it as a ~47px control — verified by reading the loaded
 * cssRules on the page, not assumed. A rule here would be dead weight at lower specificity
 * and would wrongly un-hide every other `.screen-reader-text` that can take focus.
 */

@media (prefers-reduced-motion: reduce) {
	* { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
	html { scroll-behavior: auto; }
}

html {
	scroll-behavior: smooth;
}

/* ========================================================================== *
 * Content — shared page furniture that has no other owner
 * ========================================================================== */

.nv-main {
	padding-block: var(--wp--preset--spacing--lg);
}

.nv-meta {
	color: var(--wp--preset--color--text-muted);
	font-size: var(--wp--preset--font-size--sm);
	gap: var(--wp--preset--spacing--xs);
	margin-block-end: var(--wp--preset--spacing--sm);
}

.nv-featured img,
.nv-grid img {
	inline-size: 100%;
	block-size: auto;
	border-radius: var(--wp--custom--radius--lg);
}

/*
 * The archive grid is core's grid layout (minimumColumnWidth 18rem), so the column count
 * comes from available space rather than a column class. That is what replaces
 * col-md-3/col-sm-6/col-xs-6 — 90 of those existed across the old templates, and every one
 * had to be edited to change a layout.
 */
.nv-grid > * > :is(h2, .wp-block-post-title) {
	margin-block: var(--wp--preset--spacing--xxs) 0;
}

.nv-grid > * > .wp-block-post-excerpt {
	color: var(--wp--preset--color--text-muted);
}

/* Pagination: core renders plain links; give them a hit area and a visible current state. */
.wp-block-query-pagination {
	gap: var(--wp--preset--spacing--xxs);
	margin-block-start: var(--wp--preset--spacing--lg);
}

.wp-block-query-pagination a,
.wp-block-query-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-inline-size: 44px;
	min-block-size: 44px;
	padding-inline: var(--wp--preset--spacing--xxxs);
	border-radius: var(--wp--custom--radius--md);
	text-decoration: none;
}

.wp-block-query-pagination .page-numbers.current {
	background: var(--wp--preset--color--brand);
	color: var(--wp--preset--color--base);
}

/* Decorative script face, opt-in via a class — never applied by JavaScript scanning
   inline styles, which is how the old theme did it (main.js:51). */
.has-accent-font-family {
	font-family: var(--wp--preset--font-family--accent);
}

/*
 * WordPress gives `.nv-header > * + *` its 30px block-gap. Hiding the utility strip with
 * `display: none` did NOT dissolve the `+` sibling relationship, so the gap survived as a 30px
 * EMPTY BAND inside the header at every width — 32% of the 95px mobile header was void.
 *
 * The strip is now removed outright, so `.nv-header` has one child and the selector cannot
 * match. The rule stays as a guard: the header lays its own children out and must never
 * inherit core's flow gap if a second child is ever added.
 */
.nv-header > * + * {
	margin-block-start: 0;
}

/* ========================================================================== *
 * YITH Compare preview bar — reserving its own space
 * ========================================================================== *
 *
 * The plugin pins its bar with `position: fixed; bottom: 0`, which takes it out of flow: it
 * floated over whatever happened to be at the bottom of the page — the product tab strip
 * mid-page, the footer's contact column and legal links at the end. The bar is 130px tall at
 * 1440, and taller once its text wraps on a phone, so a real amount of the footer was
 * unreachable for as long as anything was in the comparison.
 *
 * `sticky` instead of `fixed` is the whole fix, and it is a fix by structure rather than by
 * measurement. A sticky element STAYS IN FLOW: it is pinned to the bottom of the viewport
 * while the page scrolls, exactly as before, and at the end of the document it comes to rest
 * in its own space below the footer. The page grows by precisely the height of the bar.
 *
 * Why that matters more than it sounds: the alternative is `body { padding-block-end: … }`,
 * which has to NAME the bar's height. That height is not a design value — it is whatever the
 * plugin's thumbnails, wrapped text and button add up to, and it changes with the viewport and
 * with the language (the Ukrainian label wraps at a different width from the Russian). Any
 * number written here would be a guess that silently drifts. This rule introduces no length,
 * no colour and no breakpoint at all, which is why it needs no tokens and cannot drift.
 *
 * The bar is a direct child of `<body>` followed only by `<script>` and `<link>`, so its
 * resting place IS the end of the page. `html`/`body` have `overflow: visible`, which sticky
 * requires.
 *
 * Nothing is reserved when the bar is empty: the plugin ships `display: none` and only adds
 * `.shown` once a product is compared, and a `display: none` element occupies no space and
 * ignores `position`. So this needs no `.shown` qualifier of its own — the state stays the
 * plugin's to own, and the AJAX path keeps working untouched. That last point is not a
 * detail: the plugin updates the bar with `$('#yith-woocompare-preview-bar').replaceWith()`,
 * so the element must keep existing in the DOM. Styling it is safe; suppressing it is not.
 *
 * `inline-size` replaces the plugin's `100vw`. In flow, `100vw` is measured against the
 * viewport INCLUDING the scrollbar, which would push a horizontal scrollbar onto every page;
 * `100%` is the body's content box, and body carries no horizontal padding or margin, so the
 * bar stays edge to edge exactly as it renders today.
 *
 * The `body` in the selector is load-bearing and is the smallest lever that works. The
 * plugin's own rule is `#yith-woocompare-preview-bar`, an id — identical specificity — and
 * its stylesheet is enqueued AFTER this one, so an id-only rule here loses the cascade and
 * `position: fixed` survives (measured: it did). `inc/compare.php` solves the same problem
 * the other way, by declaring the plugin's handle as a dependency so source order does the
 * work, but that route is not available here: this sheet loads on every page while the
 * plugin's loads only where Compare is gated, and `wp_enqueue_style()` drops a stylesheet
 * whose dependency is absent. A missing dependency would mean no shell CSS at all on every
 * page outside the shop.
 */
body #yith-woocompare-preview-bar {
	position: sticky;
	inline-size: 100%;
}
