/*
 * Catalogue menu: the header button and the two-pane drawer it opens.
 *
 * Ships with the block rather than with the theme: the render callback emits
 * these class names, so a theme that does not know them would leave the block
 * unstyled. Colours and sizes are theme.json tokens — the contract is written
 * down in docs/design/block-css-contract.md.
 *
 * The two-pane shape is the 14.08 study's verdict: a family-grouped rail on
 * the left, the hovered branch's subcategories on the right; on the phone the
 * same markup plays drill-down — the rail is screen one, the pane screen two.
 */

.gsl-catalog {
	flex-shrink: 0;
}

.gsl-catalog__toggle {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	height: 44px;
	padding-inline: var(--wp--preset--spacing--40);
	border: 0;
	border-radius: var(--wp--custom--radius--medium);
	background: var(--wp--preset--color--brand-action);
	color: var(--wp--preset--color--base);
	font: inherit;
	font-weight: 600;
	cursor: pointer;
}

.gsl-catalog__toggle:hover {
	background: var(--wp--preset--color--brand-text);
}

.gsl-catalog__toggle[aria-expanded="true"] .gsl-catalog__chevron {
	transform: rotate(180deg);
}

.gsl-catalog__chevron {
	transition: transform 0.14s;
}

.gsl-catalog__panel {
	position: absolute;
	left: 0;
	right: 0;
	z-index: 20;
	background: var(--wp--preset--color--surface-soft);
	border-bottom: 1px solid var(--wp--preset--color--border);
	box-shadow: 0 18px 30px -26px color-mix(in srgb, var(--wp--preset--color--ink) 55%, transparent);
	padding-block: var(--wp--preset--spacing--40);
}

.gsl-catalog__panel[hidden] {
	display: none;
}

/* ------------------------------------------------------------ two panes ---- */

.gsl-catalog__flyout {
	display: flex;
	align-items: stretch;
}

.gsl-catalog__rail {
	flex: 0 0 270px;
	padding-block: var(--wp--preset--spacing--20);
	border-right: 1px solid var(--wp--preset--color--border);
}

.gsl-catalog__family {
	display: block;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40) var(--wp--preset--spacing--10);
	font-size: var(--wp--preset--font-size--label);
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
}

.gsl-catalog__branch {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	padding: 6px var(--wp--preset--spacing--40);
	border-left: 3px solid transparent;
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

.gsl-catalog__branch:hover,
.gsl-catalog__branch.is-active {
	background: var(--wp--preset--color--base);
	border-left-color: var(--wp--preset--color--gold);
	color: var(--wp--preset--color--brand-text);
}

/* The category glyphs: strokes ride the row colour (muted rest, brand on
   hover via currentColor), the strung-bead signature takes the gold token,
   bead bodies take base so the thread passes behind them. */
.gsl-catalog__ic {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	color: var(--wp--preset--color--muted);
}

.gsl-catalog__ic svg {
	display: block;
	width: 100%;
	height: 100%;
}

.gsl-catalog__branch:hover .gsl-catalog__ic,
.gsl-catalog__branch.is-active .gsl-catalog__ic {
	color: var(--wp--preset--color--brand-text);
}

.gsl-catalog__ic-g {
	fill: var(--wp--preset--color--gold-icon);
	stroke: none;
}

/* «Фурнітура з позолотою» — єдиний розділ, чия піктограма написана золотом
   цілком: позолота і є те, чим цей розділ відрізняється від сусіднього. */
.gsl-catalog__ic-gold {
	stroke: var(--wp--preset--color--gold-icon);
	fill: none;
}

.gsl-catalog__ic-b {
	fill: var(--wp--preset--color--base);
}

.gsl-catalog__branch-short {
	display: none;
}

.gsl-catalog__arrow {
	margin-left: auto;
	color: var(--wp--preset--color--muted);
	flex-shrink: 0;
}

.gsl-catalog__panes {
	flex: 1;
	min-width: 0;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--60);
}

.gsl-catalog__pane[hidden] {
	display: none;
}

/* Off the phone the drill-down back button is furniture. */
.gsl-catalog__back {
	display: none;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	border: 0;
	background: transparent;
	padding: var(--wp--preset--spacing--20) 0;
	color: var(--wp--preset--color--muted);
	font: inherit;
	font-size: var(--wp--preset--font-size--small);
	cursor: pointer;
}

.gsl-catalog__all {
	display: flex;
	align-items: baseline;
	gap: var(--wp--preset--spacing--30);
	padding-block: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 700;
	text-decoration: none;
}

.gsl-catalog__all-name {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.gsl-catalog__all-go {
	flex-shrink: 0;
	color: var(--wp--preset--color--brand-text);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.gsl-catalog__all:hover .gsl-catalog__all-go {
	text-decoration: underline;
}

/* Підрозділи — плитки з фотографією (власник, 22.09.2026). Картинка каже, що
   всередині, підпис каже, чим воно відрізняється від сусіда: між гілками фото
   впізнаються з першого погляду, а всередині однієї гілки три підрозділи
   темних ниток намистин схожі між собою, і розрізняє їх слово. */
.gsl-catalog__subs {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--30);
	margin: var(--wp--preset--spacing--30) 0 0;
	padding: 0;
	list-style: none;
}

.gsl-catalog__subs a {
	display: block;
	color: var(--wp--preset--color--contrast);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

/* Хвіст підрозділів під плитками: слова там, де картинка не окупається.
   Рядок коштує чверть висоти плитки, а ці підрозділи відкривають рідко. */
.gsl-catalog__rest {
	margin-top: var(--wp--preset--spacing--30);
	padding-top: var(--wp--preset--spacing--20);
	border-top: 1px solid var(--wp--preset--color--hairline);
}

.gsl-catalog__rest-head {
	display: block;
	font-size: var(--wp--preset--font-size--label);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
	margin-bottom: 2px;
}

.gsl-catalog__rest-item {
	display: flex;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--20);
	padding: 7px 0;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.3;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
	border-bottom: 1px solid var(--wp--preset--color--hairline);
}

.gsl-catalog__rest-item i {
	font-style: normal;
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--label);
}

/* Квадрат, а не пропорції фото: ряд плиток має лежати рівно, чого б там не
   зняли — нитку завдовжки 75 см чи один замочок. */
.gsl-catalog__shot {
	display: block;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--wp--custom--radius--medium);
	background: var(--wp--preset--color--base);
}

.gsl-catalog__shot img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Підрозділ без жодного фото лишається плиткою: порожнє місце тримає ряд. */
.gsl-catalog__shot--empty {
	background: var(--wp--preset--color--surface);
}

.gsl-catalog__sub-name {
	/* Довге слово мусить переноситися, а не зникати: плитка вужча за
	   «Напівнамистини», і без цього хвіст слова просто зрізало. */
	overflow-wrap: anywhere;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
	margin-top: 5px;
	font-weight: 600;
	line-height: 1.3;
	color: var(--wp--preset--color--ink);
}

.gsl-catalog__sub-n {
	font-size: var(--wp--preset--font-size--label);
	color: var(--wp--preset--color--muted);
}

.gsl-catalog__subs a:hover {
	color: var(--wp--preset--color--brand-text);
}

/* Laptops shorter than the rail: the panel scrolls inside itself.
   `top` pins it under the whole header (owner, 13.10.2026: «съедает нижнюю
   часть шапки»). Without it the panel took its static place under the
   toggle, 10 px above the header's edge, and covered the white band under
   the logo, the toggle and the search. 100% of the header, which is the
   positioned ancestor (`.gsl-head`, theme style.css). */
@media (min-width: 641px) {
	.gsl-catalog__panel {
		top: 100%;
		max-height: calc(100dvh - 140px);
		overflow-y: auto;
		overscroll-behavior: contain;
	}
}

@media (max-width: 1080px) {
	.gsl-catalog__subs {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* ------------------------------------------- phone: split view (v2) -------
   The owner's call after living with the drill-down for an evening: the
   rail stays, the pane slides in beside it — the WB/AliExpress catalog
   shape. One screen, one action, no second screen. Short rail labels and
   micro family labels buy the one-screen budget. */

@media (max-width: 640px) {
	/* 114 px is what the page keeps above the drawer; the 54 px the language
	   bar used to hold at the bottom went back to the rail. */
	.gsl-catalog__flyout {
		height: calc(100dvh - 114px);
	}

	/* The wrap inset is desktop air; on the phone the rail earns it back -
	   the family labels were ellipsizing over dead margin (owner, 15.08). */
	.gsl-catalog__panel .gsl-wrap {
		padding-inline: var(--wp--preset--spacing--20);
	}

	/* The rail used to squeeze its rows to fit the screen — «прокрутка
	   уводит» (owner, 15.08.2026) — and with sixteen sections the squeeze
	   landed on 36 px, a target of about seven millimetres. The owner chose
	   the other side of that trade on 22.09.2026: the row is 44 px now, the
	   size Apple asks for, and the rail scrolls by about a row and a half.
	   Sixteen rows of a finger's height beat sixteen rows nobody can hit. */
	.gsl-catalog__rail {
		flex: 0 0 48%;
		padding-block: 0;
		display: flex;
		flex-direction: column;
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	.gsl-catalog__family {
		/* Підпис сім'ї — не кнопка, тож він віддає висоту рядкам, які нею є. */
		padding: 2px var(--wp--preset--spacing--30) 0;
		border-top: 1px solid var(--wp--preset--color--border);
		letter-spacing: 0.04em;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.gsl-catalog__family:first-child {
		border-top: 0;
	}

	.gsl-catalog__branch {
		flex: 0 0 auto;
		min-height: 44px;
		padding: 0 var(--wp--preset--spacing--20) 0 var(--wp--preset--spacing--30);
		gap: 8px;
		font-size: var(--wp--preset--font-size--base);
		font-weight: 600;
		line-height: 1.15;
		white-space: nowrap;
		overflow: hidden;
	}

	.gsl-catalog__ic {
		width: 20px;
		height: 20px;
	}

	.gsl-catalog__branch-short {
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.gsl-catalog__family {
		flex: 0 0 auto;
	}

	.gsl-catalog__branch.is-active {
		background: var(--wp--preset--color--cream);
		color: var(--wp--preset--color--ink);
	}

	.gsl-catalog__branch-full,
	.gsl-catalog__arrow {
		display: none;
	}

	.gsl-catalog__branch-short {
		display: inline;
	}

	.gsl-catalog__panes {
		padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	/* The pane arrives, it does not just appear. */
	.gsl-catalog__pane:not([hidden]) {
		animation: gsl-pane-in 0.18s ease;
	}

	.gsl-catalog__all {
		min-height: 44px;
		align-items: center;
		gap: var(--wp--preset--spacing--20);
		border-bottom: 1px solid var(--wp--preset--color--border);
		font-size: var(--wp--preset--font-size--small);
		white-space: nowrap;
	}

	/* The rail already names the branch - the pane keeps just the door. */
	.gsl-catalog__all-name {
		display: none;
	}

	/* На телефоні дві колонки: плитка стає мішенню в пів пальця завширшки, і
	   стоїть вона під правою рукою, якою телефон і тримають. */
	.gsl-catalog__subs {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--20);
		margin-top: var(--wp--preset--spacing--20);
	}

	/* Плитка тут завширшки пів долоні, а назви в цьому каталозі довгі:
	   «Намистини силіконові та гризунці». Два рядки різали їх на півслові,
	   три вміщують майже всі — і підпис лишається підписом, а не загадкою. */
	.gsl-catalog__sub-name {
		-webkit-line-clamp: 3;
		line-clamp: 3;
		font-size: var(--wp--preset--font-size--label);
	}
}

@keyframes gsl-pane-in {
	from {
		opacity: 0;
		transform: translateX(14px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.gsl-catalog__pane:not([hidden]) {
		animation: none;
	}
}

/* On a phone the toggle is a bare burger — three dark bars drawn with a
   mask so they take the text colour. */
@media (max-width: 640px) {
	.gsl-catalog__toggle {
		background: transparent;
		border: 0;
		color: var(--wp--preset--color--contrast);
		box-shadow: none;
		width: 44px;
		min-width: 44px;
		height: 44px;
		min-height: 0;
		padding: 0;
		justify-content: center;
	}

	.gsl-catalog__toggle > span,
	.gsl-catalog__toggle .gsl-catalog__chevron,
	.gsl-catalog__toggle > svg {
		display: none;
	}

	.gsl-catalog__toggle::before {
		content: "";
		width: 26px;
		height: 26px;
		background: currentColor;
		-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 6.4h18v1.5H3zM3 11.2h18v1.5H3zM3 16h18v1.5H3z'/%3E%3C/svg%3E") center / contain no-repeat;
		mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 6.4h18v1.5H3zM3 11.2h18v1.5H3zM3 16h18v1.5H3z'%3E%3C/path%3E%3C/svg%3E") center / contain no-repeat;
	}
}

/* The language row of the drawer: phone-only (the top strip owns the
   switcher on desktop). The current-language chip gets the cream token -
   the utility-bar version mixes against a dark ground, which on the
   drawer's light one would fade to nothing. */
.gsl-catalog__lang {
	display: none;
}

@media (max-width: 640px) {
	.gsl-catalog__lang {
		display: block;
		flex: 0 0 auto;
		margin-top: var(--wp--preset--spacing--10);
		padding: var(--wp--preset--spacing--10) 0 var(--wp--preset--spacing--20);
		border-top: 1px solid var(--wp--preset--color--border);
	}

	.gsl-catalog__lang .gsl-lang {
		margin-inline-start: 0;
		justify-content: flex-start;
	}

	.gsl-catalog__lang .gsl-lang__item {
		display: inline-flex;
		align-items: center;
		min-height: 40px;
		padding-inline: var(--wp--preset--spacing--50);
	}

	.gsl-catalog__lang .gsl-lang__item.is-current {
		background: var(--wp--preset--color--cream);
		color: var(--wp--preset--color--ink);
	}
}

/* The panel is absolutely positioned, so its height never reaches the
   document scroll — the panel scrolls itself; dvh keeps the math honest
   when the mobile browser chrome collapses. */
@media (max-width: 640px) {
	.gsl-catalog__panel {
		max-height: calc(100dvh - 90px);
		overflow-y: auto;
		overscroll-behavior: contain;
	}
}
/* v8 — the pane gets the width, the rail keeps every section on the screen
   (owner, 24.09.2026). On a 390 px phone the rail held 166 px and the pane
   146, and the subsection photo was 67 px — «маленькі фото». The rail sheds
   width: 120 px, an 18 px pictogram, the small type for the short labels,
   which all fit on one line in both languages. The pane goes 146 → 209 and
   the photo 67 → 99.

   Two things the first cut got wrong, both reported from the phone within
   the hour. The rail wobbled sideways: `overflow-y: auto` makes overflow-x
   auto as well, and the language row — two pills of 136 px in a 120 px rail
   — was enough for a horizontal scroll nobody asked for. And it scrolled
   down: fixed 44 px rows (22.09) plus four family labels and a 56 px
   language row run 841 px on a 730 px rail. «Нам нужно, чтобы левые
   категории были все на одной странице.»

   So: the language row leaves the rail (render.php prints it inside the
   pane box now) and sits at the right end of the pane's header row, beside
   «Всі товари →», where it costs no height — absolutely positioned inside
   the scrolling pane box, so it scrolls away with the pane rather than
   hovering over the tiles. And the rows flex again, between 36 and 44 px: a
   finger's height where the screen allows (44 on a 414×896), every section
   on one screen where it does not (39 on a 676 px rail, the owner's phone). */
@media (max-width: 640px) {
	.gsl-catalog__rail {
		flex: 0 0 120px;
		overflow-x: hidden;
	}

	.gsl-catalog__branch {
		flex: 1 1 auto;
		min-height: 36px;
		max-height: 44px;
		gap: 6px;
		padding: 0 var(--wp--preset--spacing--10) 0 6px;
		font-size: var(--wp--preset--font-size--small);
	}

	.gsl-catalog__ic {
		width: 18px;
		height: 18px;
	}

	.gsl-catalog__family {
		flex: 0 0 auto;
		padding: 0 var(--wp--preset--spacing--20);
		line-height: 1.2;
	}

	.gsl-catalog__lang {
		position: absolute;
		top: 6px;
		right: var(--wp--preset--spacing--20);
		z-index: 2;
		margin: 0;
		padding: 0;
		border: 0;
	}

	.gsl-catalog__lang .gsl-lang__item {
		min-height: 32px;
		padding-inline: var(--wp--preset--spacing--30);
	}

	.gsl-catalog__panes {
		position: relative;
		padding: var(--wp--preset--spacing--20);
	}

	.gsl-catalog__subs {
		gap: 6px;
	}
}

/* v8.1 — the page holds still under the open drawer (owner, 24.09.2026):
   the class comes from view.js while the panel is open on a phone. Only the
   document stops scrolling — body is not pinned, so scrollY, the compact
   header and the page position stay exactly as they were. The rail and the
   panes contain their own overscroll, so a swipe that runs out of pane stops
   there instead of reaching the page. */
@media (max-width: 640px) {
	/* html only: overflow on body as well would make body a scroll box of
	   its own, and the sticky header would stick to it and ride away. */
	html.gsl-catalog-lock {
		overflow: hidden;
		overscroll-behavior: none;
	}

	.gsl-catalog__rail,
	.gsl-catalog__panes {
		overscroll-behavior: contain;
	}
}

/* v8.2 — the pane springs like the rail (owner, 24.09.2026: «везде так
   пружинит, стационарно не прикольно»). A phone only rubber-bands a box
   that can scroll; a branch with four subsections could not, so the pane
   stood dead while the rail bounced. The open pane is always one pixel
   taller than its box, so it scrolls — and bounces — whatever it holds.
   The page under the drawer still does not move (v8.1). */
@media (max-width: 640px) {
	.gsl-catalog__pane:not([hidden]) {
		min-height: calc(100% + 1px);
	}
}

/* «Обране» at the foot of the rail — phones only; the desktop header keeps
   its heart. A hairline sets it apart from the sections above. */
.gsl-catalog__branch--fav {
	display: none;
}

.gsl-catalog__fav-count {
	margin-left: auto;
	min-width: 20px;
	padding: 0 6px;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--gold);
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--label);
	line-height: 20px;
	text-align: center;
}

.gsl-catalog__fav-count[hidden] {
	display: none;
}

@media (max-width: 640px) {
	.gsl-catalog__branch--fav {
		display: flex;
		margin-top: var(--wp--preset--spacing--20);
		border-top: 1px solid var(--wp--preset--color--hairline);
	}
}
