/*
 * Homepage section layout, matching the approved design: a section head with
 * a "see all" link on the right, then a row of tiles.
 */

/*
 * The title of a listing page — Продукти, Послуги, a product category, a price
 * list, the cart. These are block-editor headings, so they used to carry the
 * theme's "H1 64" preset while Проєкти and Блог, which have templates of their
 * own, sat at 48. One class over all of them, one number in tokens.css.
 */
.sx-page-title {
	font-size: var( --sx-title-page );
	line-height: 1.1;
	letter-spacing: -0.02em;
}

/*
 * Pages that write their headings in the page itself carry the editor presets
 * — "H1 64" and "H2 48" — rather than any class of ours. Mapped onto the same
 * two steps as the rest of the site so such a page reads like a page of this
 * site and not like a stray document.
 *
 * This used to be scoped to .page-template-page-service, and that was too
 * narrow: the moment a page went onto another template it came out at the raw
 * 64/48 while every page beside it sat at 48/28. Any page whose body copy is
 * written in the editor wants the same scale, so the scope is now the page
 * rather than one template.
 *
 * Narrowed to .wp-block-heading on purpose. Without it the rule also outranks
 * our own components' headings — .sx-cta-card__title is a single class and
 * loses to this pair — and the CTA card would quietly render two pixels
 * smaller here than everywhere else on the site.
 *
 * !important on the h1 because WordPress writes its own !important into every
 * preset font-size class, and that heading carries one. Rewriting the pages'
 * stored content would be the alternative — not worth overwriting copy someone
 * may have edited by hand. The h2 gets none, so an editor who deliberately
 * picks a size in the editor still wins.
 */
.page .entry-content > h1.wp-block-heading {
	font-size: var( --sx-title-page ) !important;
	line-height: 1.1;
	letter-spacing: -0.02em;
}

.page .entry-content h2.wp-block-heading {
	font-size: var( --sx-title-section );
	line-height: 1.15;
}

.sx-home-block {
	margin-top: var( --wp--preset--spacing--70 );
}

/* ---- Problem statement ----
   The airy one. No cards, no rules, no artwork: it sits between the statistics
   row and the product grid, and anything with a background or a border would
   read as a third grid instead of as a pause between two. Its only devices are
   space and a short measure. */

.sx-problem-block {
	margin-top: var( --wp--preset--spacing--80, var( --wp--preset--spacing--70 ) );
	padding-block: var( --wp--preset--spacing--50 );
}

.sx-problem-block__head {
	max-width: 760px;
}

.sx-problem-block__title {
	margin: 0;
	font-size: var( --sx-title-section );
	line-height: 1.15;
	letter-spacing: -0.02em;
}

.sx-problem-block__lead {
	margin: 20px 0 0;
	max-width: 620px;
	color: var( --sx-text-secondary );
	font-size: 1.0625rem;
	line-height: 1.65;
}

.sx-problem-list {
	display: grid;
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	gap: 48px;
	margin: var( --wp--preset--spacing--60 ) 0 0;
	padding: 0;
	list-style: none;
}

.sx-problem__icon {
	display: block;
	width: 28px;
	height: 28px;
	color: var( --sx-brand-text );
}

.sx-problem__icon svg {
	display: block;
	width: 100%;
	height: 100%;
}

.sx-problem__title {
	margin: 18px 0 0;
	font-size: 1.0625rem;
	line-height: 1.3;
}

.sx-problem__text {
	margin: 8px 0 0;
	max-width: 34ch;
	color: var( --sx-text-secondary );
	line-height: 1.6;
}

@media ( max-width: 900px ) {
	.sx-problem-list {
		grid-template-columns: minmax( 0, 1fr );
		gap: 32px;
	}

	.sx-problem__text {
		max-width: none;
	}
}

.sx-home-block__head {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: 24px;
	margin-bottom: var( --wp--preset--spacing--50 );
}

.sx-home-block__title {
	margin: 0;
	font-size: var( --sx-title-section );
	line-height: 1.1;
}

.sx-home-block__lead {
	margin: 8px 0 0;
	color: var( --sx-text-secondary );
}

.sx-home-block__more {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var( --sx-text-secondary );
	font-size: 0.875rem;
	text-decoration: none;
	white-space: nowrap;
}

.sx-home-block__more span {
	color: var( --sx-brand-text );
	transition: transform var( --sx-transition-fast ) var( --sx-ease );
}

.sx-home-block__more:hover {
	color: var( --sx-brand-text );
}

.sx-home-block__more:hover span {
	transform: translateX( 4px );
}

/* ---- Tiles ---- */

.sx-tiles {
	display: grid;
	gap: 20px;
}

.sx-tiles--4 {
	grid-template-columns: repeat( 4, minmax( 0, 1fr ) );
}

.sx-tiles--2 {
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
}

/*
 * A section that something links to has to stop below the sticky header, not
 * behind it. Without this the hero's "Дізнатися більше" scrolled the heading
 * it was aiming at to exactly y=0 — under 88px of header, invisible, so the
 * link looked broken even once its anchor existed.
 *
 * --sx-header-h is published by header-nav.js from the bar's measured height;
 * the fallback is the desktop figure, for the moment before that runs.
 *
 * Desktop only: below 1200px the bar sits at the bottom of the screen and
 * nothing is in the way at the top.
 */
@media ( min-width: 1200px ) {
	.sx-home-block[id] {
		scroll-margin-top: calc( var( --sx-header-h, 88px ) + 16px );
	}
}

/*
 * The homepage services are chosen page by page now, so the count is whatever
 * the office ticked rather than always four. An odd one out would otherwise
 * leave a hole beside the cube; letting the last card take the full width
 * reads as a deliberate row instead of a missing tile.
 *
 * Bounded by the breakpoint on purpose. Below 768px the grid is a single
 * column, and "span 2" there does not fill a row — it makes the grid grow an
 * implicit second column, which turned the whole mobile list back into two
 * cramped columns.
 */
@media ( min-width: 768px ) {
	.sx-tiles--2 > :last-child:nth-child( odd ) {
		grid-column: span 2;
	}
}

.sx-tile {
	position: relative;
	display: flex;
	flex-direction: column;
	min-height: 200px;
	padding: 24px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-lg );
	background: var( --sx-white );
	color: inherit;
	text-decoration: none;
	transition: transform var( --sx-transition-base ) var( --sx-ease ),
		border-color var( --sx-transition-base ) var( --sx-ease ),
		box-shadow var( --sx-transition-base ) var( --sx-ease );
}

.sx-tile__title {
	display: block;
	margin: 16px 0 8px;
	font-size: 1.0625rem;
	font-weight: 600;
	line-height: 1.3;
}

.sx-tile__text {
	display: block;
	margin: 0;
	color: var( --sx-text-secondary );
	font-size: 0.875rem;
	line-height: 1.5;
}

.sx-tile__arrow {
	margin-top: auto;
	padding-top: 20px;
	color: var( --sx-brand-text );
	font-size: 1.125rem;
	transition: transform var( --sx-transition-base ) var( --sx-ease );
}

.sx-tile:hover {
	transform: translateY( -4px );
	border-color: var( --sx-brand-200 );
	box-shadow: var( --sx-shadow-card-hover );
}

.sx-tile:hover .sx-tile__arrow {
	transform: translateX( 4px );
}

.sx-tile:focus-visible {
	outline: 3px solid rgba( 242, 47, 42, 0.2 );
	outline-offset: 2px;
}

/* The service variant lays icon and text side by side and needs less height. */
.sx-tile--flat {
	flex-direction: row;
	align-items: flex-start;
	gap: 14px;
	min-height: 0;
	background: var( --sx-white );
}

.sx-tile--flat .sx-tile__title {
	margin-top: 0;
}

.sx-tile--flat .sx-icon-box {
	flex: 0 0 auto;
}

/* Icon colour is fixed site-wide in tokens.css — red on the light red tint.
   The per-tile tints that used to live here contradicted that rule. */

/* ---- Services split ---- */

.sx-services-split {
	display: grid;
	grid-template-columns: minmax( 0, 1.35fr ) minmax( 0, 1fr );
	align-items: center;
	gap: 40px;
}

.sx-services-split__art svg,
.sx-services-split__art img {
	display: block;
	width: 100%;
	height: auto;
}

/* The cube is a rendered image with a white background, so it needs no frame
   or shadow of its own — just a ceiling so it does not outgrow its column. */
.sx-cube {
	max-width: 380px;
	margin-inline: auto;
}

/*
 * The drawn cube, on the front page only. On trial beside the render above —
 * see inc/home-cube.php, which decides which of the two the section gets.
 *
 * Every colour is a palette token rather than a literal, so the cube follows
 * the site rather than having a scheme of its own. Three shades of the same
 * neutral separate the three faces, which is the whole of the shading: no
 * gradients, because a gradient across a face is the thing that makes flat
 * geometry look like it is imitating a render and failing.
 */
.sx-cube-svg {
	display: block;
	width: 100%;
	max-width: 380px;
	height: auto;
	margin-inline: auto;
	/* Small cubes wait outside the frame; this is what keeps them from
	   painting over the tiles beside them on the way in. */
	overflow: hidden;
}

.sx-cube-svg__t { fill: var( --sx-neutral-50 ); }
.sx-cube-svg__l { fill: var( --sx-neutral-200 ); }
.sx-cube-svg__r { fill: var( --sx-neutral-300 ); }

.sx-cube-svg__cube--brand .sx-cube-svg__t { fill: var( --sx-brand ); }
.sx-cube-svg__cube--brand .sx-cube-svg__l { fill: var( --sx-brand-hover ); }
.sx-cube-svg__cube--brand .sx-cube-svg__r { fill: var( --sx-brand-active ); }

/*
 * A hairline where two faces meet. Without it the top of one cube and the
 * side of the one behind it are near enough in tone to merge, and the stack
 * loses the grid that makes it read as many cubes rather than one shape.
 */
.sx-cube-svg polygon {
	stroke: var( --sx-neutral-400 );
	stroke-width: 0.5;
	stroke-opacity: 0.28;
	stroke-linejoin: round;
}

.sx-cube-svg__cube--brand polygon {
	stroke: var( --sx-brand-active );
	stroke-opacity: 0.35;
}

/*
 * Assembled, and staying that way.
 *
 * The script leaves the cube alone entirely when this is set, so this rule is
 * only here for the case where it has already moved something and the setting
 * changes underneath it.
 */
@media ( prefers-reduced-motion: reduce ) {
	.sx-cube-svg__cube {
		transform: none !important;
		opacity: 1 !important;
	}
}

/*
 * Variant B: the same stack given the surface the logo and the hero graphic
 * have. Each face is a rounded plate with a gradient and a gloss, the bottom
 * row carries a visible edge underneath, and one shadow sits under the lot.
 *
 * The three custom properties are the dials. Turning the gloss off, or the
 * thickness down, moves this towards variant A without editing the artwork.
 */
.sx-cube-svg--b {
	--sx-cube-gloss: 1;
	--sx-cube-thickness: 3px;
	--sx-cube-shadow: 1;
}

/*
 * Transforms are read in viewBox units rather than the element's own painted
 * box, so a piece near the edge of the drawing travels the same distance as
 * one in the middle. Without it each piece would be measured against itself
 * and the stack would come apart unevenly.
 */
.sx-cube-b__piece {
	transform-box: view-box;
}

.sx-cube-b__gloss {
	opacity: var( --sx-cube-gloss );
}

/*
 * The red pieces take neither the gloss nor the white seam. Both were drawn
 * for a pale plate: on red the gloss reads as a smear and the white seam as a
 * halo, and the brand colour stops looking like the brand colour.
 */
.sx-cube-b__piece[ data-red="True" ] .sx-cube-b__gloss {
	opacity: 0;
}

.sx-cube-b__piece[ data-red="True" ] rect {
	stroke-opacity: 0;
}

/* The darker plate under the face, which is what reads as thickness. Only the
   bottom row has one — a full edge on all 27 would show through the gaps. */
.sx-cube-b__edge {
	transform: translateY( var( --sx-cube-thickness ) );
}

.sx-cube-b__shadow {
	opacity: var( --sx-cube-shadow );
}

/*
 * Assembled and still. The shadow keeps its own opacity here rather than the
 * one the script would have faded it to, so a stack that never came apart is
 * not left floating without one.
 */
@media ( prefers-reduced-motion: reduce ) {
	.sx-cube-b__piece {
		transform: none !important;
		opacity: 1 !important;
	}

	.sx-cube-b__shadow {
		opacity: var( --sx-cube-shadow ) !important;
	}
}

@media ( max-width: 1023px ) {
	.sx-tiles--4 {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	}

	.sx-services-split {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-services-split__art {
		max-width: 360px;
		margin-inline: auto;
	}
}

@media ( max-width: 767px ) {
	.sx-home-block__head {
		flex-direction: column;
		align-items: flex-start;
		gap: 12px;
	}

	.sx-tiles--4,
	.sx-tiles--2 {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-tile {
		min-height: 0;
	}
}

/* ---- Client logos ---- */

.sx-clients {
	margin-top: var( --wp--preset--spacing--70 );
}

.sx-clients__title {
	margin: 0 0 var( --wp--preset--spacing--50 );
	font-size: var( --sx-title-section );
	line-height: 1.1;
}

/* The viewport the row drifts behind. Padding rather than margin on the block
   edges so the focus ring has somewhere to sit instead of being clipped. */
.sx-clients__track {
	/* Makes the track a query container, which is what gives the tiles below a
	   width to measure against. */
	container-type: inline-size;
	overflow-x: auto;
	padding-block: 3px;

	/*
	 * The loop jump in clients-marquee.js is a scrollLeft assignment, and it
	 * only stays invisible if it lands instantly — a smooth behaviour inherited
	 * from an ancestor would animate the row across a whole copy in full view.
	 */
	scroll-behavior: auto;

	/* Panning the logos should not drag the page along at the ends. */
	overscroll-behavior-x: contain;

	/* Scrolling stays available — focus pauses the drift and the row can then
	   be panned — but the bar itself is hidden: a scrollbar under a row that
	   moves on its own reads as a stuck control. */
	scrollbar-width: none;
}

.sx-clients__track::-webkit-scrollbar {
	display: none;
}

.sx-clients__track:focus-visible {
	outline: 3px solid var( --sx-brand );
	outline-offset: 3px;
}

/*
 * The drift. The copies of the list sit side by side and the strip slides left
 * by exactly one copy, at which point the second copy is standing where the
 * first began and the jump back to zero is invisible.
 *
 * That distance is not a quarter of the strip. The four lists are separated by
 * the same 12px gap as the tiles, so the strip measures 4L + 36 while one lap
 * is L + 12 — a quarter of the strip is L + 9 and the row would creep 3px short
 * every lap. Hence the correction.
 *
 * Speed is a duration for a fixed distance, so a row of nineteen logos travels
 * at roughly 35px a second; adding logos slows it down rather than making it
 * dash, which is the right way round for a decorative band.
 */
.sx-clients__marquee {
	display: flex;
	gap: 12px;
	width: max-content;
	animation: sx-clients-drift 90s linear infinite;
}

@keyframes sx-clients-drift {
	from { transform: translateX( 0 ); }
	to   { transform: translateX( calc( -25% - 3px ) ); }
}

/*
 * Stop for anyone actually looking at it — pointer or keyboard.
 *
 * The pointer half is gated on a device that has one. A touch screen leaves
 * :hover stuck on whatever was last touched, so on a phone a single swipe of
 * the row would have frozen it there until something else was tapped, which
 * reads as a band that has broken rather than one that is being considered.
 */
@media ( hover: hover ) {
	.sx-clients__track:hover .sx-clients__marquee {
		animation-play-state: paused;
	}
}

.sx-clients__track:focus-within .sx-clients__marquee {
	animation-play-state: paused;
}

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

	/* Nothing moves now, so the scrollbar goes back to being the only way to
	   reach the rest of the row. */
	.sx-clients__track {
		scrollbar-width: thin;
		scrollbar-color: var( --sx-border-strong ) transparent;
	}

	.sx-clients__track::-webkit-scrollbar {
		display: initial;
	}
}

.sx-clients__list {
	display: flex;
	gap: 12px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * Eight across: each tile takes an eighth of what is left once the seven 12px
 * gaps between them are removed.
 *
 * Measured in cqw — the track's own width — and not in per cent. A percentage
 * here resolves against the flex container, and the flex container is the row
 * of nineteen tiles, which has already stretched to fit them: the tiles would
 * be sized against a width they themselves determine, and the row came out at
 * seven-and-a-bit items instead of eight.
 *
 * min-width is released because flex items otherwise refuse to shrink below
 * their content.
 */
.sx-clients__item {
	flex: 0 0 auto;
	width: calc( ( 100cqw - 7 * 12px ) / 8 );
	min-width: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 96px;

	/*
	 * Tighter than it was, and tighter across than down. 16px all round left a
	 * 155px tile with a 123px opening, and the wide wordmarks — Columbia, Барва
	 * — are limited by the opening's width, not by anything about the mark, so
	 * every pixel taken off the sides is a pixel they grow by. Down the tile
	 * the margin still has to read as a margin, hence 12.
	 */
	padding: 12px 10px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-md );
	background: var( --sx-white );
}

.sx-clients__item img {
	max-width: 100%;

	/*
	 * The full height the padding leaves, rather than the 56px it used to be.
	 * A tile is 96 tall and gives up 24 of that to padding and 2 to its border,
	 * so 70 is the mark's share and the row keeps the height it had; at 56 a
	 * square logo — Файн-Ел, MINISO, FRAMO, Інтер'єр Експерт — sat in the middle
	 * of the card with 40px of nothing above and below it, and the row read as
	 * a wall of empty boxes with something small in each.
	 *
	 * It only helps the marks that are limited by their height. A wordmark five
	 * times wider than it is tall runs out of width first and is unaffected by
	 * this number; those gained what the side padding gave up, and evening the
	 * two families out properly would mean re-cutting the files to one optical
	 * size, which is artwork rather than CSS.
	 */
	max-height: 70px;
	width: auto;
	height: auto;
	object-fit: contain;
	/*
	 * A dozen brand palettes side by side would fight the page, so the row is
	 * greyed by default and shows true colour on hover.
	 *
	 * Greyed, but not dimmed. There used to be opacity: 0.65 on top, and it was
	 * measured against the white card: nine of the sixteen marks came out under
	 * 3:1, the floor for a graphic, and the palest — Уніплит, Мілвуд, Вертикаль,
	 * Electrolux — sat between 1.7 and 2.9, which is where "I can't read that"
	 * starts. Dropping the dimming lifts every one of them by half again.
	 *
	 * Darkening instead of dimming was tried and rejected: several of these
	 * files are JPEGs with a white background rather than transparent artwork,
	 * so any brightness() turns their card into a grey square.
	 */
	filter: grayscale( 1 );
	transition: filter var( --sx-transition-base ) var( --sx-ease );
}

.sx-clients__item:hover img {
	filter: none;
}

@media ( prefers-reduced-motion: reduce ) {
	.sx-clients__item img {
		transition: none;
	}
}

/* Fewer across as the row narrows — eight 150px tiles need about 1200px, and
   below that they turn into stamps. The half tile on a phone is deliberate:
   a partly visible next item is the clearest signal that the row scrolls. */
@media ( max-width: 1200px ) {
	.sx-clients__item {
		width: calc( ( 100cqw - 5 * 12px ) / 6 );
	}
}

@media ( max-width: 900px ) {
	.sx-clients__item {
		width: calc( ( 100cqw - 3 * 12px ) / 4 );
	}
}

@media ( max-width: 600px ) {
	.sx-clients__item {
		width: calc( ( 100cqw - 1.5 * 12px ) / 2.5 );
	}
}

/* ---- Testimonials ----
   One quote given room and two beside it, rather than three equal cards: three
   of a size read as equally weighted and equally skippable, and none of them
   gets read. */

.sx-testimonials {
	margin-top: var( --wp--preset--spacing--70 );
}

/* The heading sits in the shared section head, so the "see all" link lines up
   with the ones on the blocks above it. */
.sx-testimonials__title {
	margin: 0;
	font-size: var( --sx-title-section );
	line-height: 1.1;
}

/*
 * The carousel. A scroll container with snap points, not a slider: the browser
 * already does momentum, touch, trackpad, keyboard and a scrollbar, and the
 * arrows are only a shortcut on top of it.
 *
 * align-items: stretch keeps every card the height of the tallest one on the
 * current row, so the author lines stay level as you scroll past.
 */
.sx-testimonials__track {
	container-type: inline-size;
	display: flex;
	align-items: stretch;
	gap: 20px;
	overflow-x: auto;
	padding-block: 3px;

	/*
	 * No scroll snapping, deliberately. Eight cards of 423px do not divide into
	 * a 1310px track, so the last card can never reach the start position that
	 * `scroll-snap-align: start` asks for: under `mandatory` the browser drags
	 * the scroll back off the end of the row, and under `proximity` it settles
	 * a few pixels short of the maximum, which leaves the "next" arrow looking
	 * live when there is nothing left to show. The arrows already move by
	 * exactly one card, so snapping was only ever going to duplicate that.
	 */
	scrollbar-width: none;
}

.sx-testimonials__track::-webkit-scrollbar {
	display: none;
}

.sx-testimonials__track:focus-visible {
	outline: 3px solid var( --sx-brand );
	outline-offset: 3px;
}

/* Three across, measured against the track rather than the row: a percentage
   would resolve against the flex container, which has already stretched to fit
   every card. */
.sx-testimonials__track > .sx-testimonial {
	flex: 0 0 auto;
	width: calc( ( 100cqw - 2 * 20px ) / 3 );
}

.sx-carousel__nav {
	flex: 0 0 auto;
	display: flex;
	gap: 8px;
}

.sx-carousel__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 1px solid var( --sx-border-strong );
	border-radius: 50%;
	background: var( --sx-white );
	color: var( --sx-text );
	cursor: pointer;
	transition: border-color var( --sx-transition-fast ) var( --sx-ease ),
		color var( --sx-transition-fast ) var( --sx-ease );
}

.sx-carousel__btn svg {
	width: 20px;
	height: 20px;
}

.sx-carousel__btn:hover:not( :disabled ) {
	border-color: var( --sx-brand-text );
	color: var( --sx-brand-text );
}

.sx-carousel__btn:disabled {
	color: var( --sx-icon-disabled );
	border-color: var( --sx-border );
	cursor: default;
}

.sx-testimonial {
	display: flex;
	flex-direction: column;
	margin: 0;
	padding: 28px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-lg );
	background: var( --sx-white );
}


/* Decorative, and set in a serif because the body face draws a straight
   typographic quote rather than the curled one this wants to be. */
.sx-testimonial__mark {
	display: block;
	margin-bottom: 4px;
	color: var( --sx-brand-100 );
	font-family: Georgia, "Times New Roman", serif;
	font-size: 3rem;
	line-height: 0.7;
}


.sx-testimonial__quote {
	margin: 0;
	color: var( --sx-text );
	font-size: 0.9375rem;
	line-height: 1.6;
}

.sx-testimonial__quote p {
	margin: 0 0 12px;
}

.sx-testimonial__quote p:last-child {
	margin-bottom: 0;
}


/* margin-top auto pins the author to the bottom, so the two small cards line
   their authors up with each other however unevenly the quotes run. */
.sx-testimonial__author {
	display: flex;
	align-items: center;
	gap: 14px;
	margin-top: auto;
	padding-top: 24px;
}

.sx-testimonial__photo {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	overflow: hidden;
	border-radius: 50%;
	background: var( --sx-brand-50 );
}


.sx-testimonial__photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.sx-testimonial__monogram {
	color: var( --sx-brand-text );
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: 0.02em;
}

.sx-testimonial__who {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

/*
 * Ukrainian company names are frequently one long compound word —
 * «Прикарпатспецбудтранс», «Нафтотранссервіс», «Веллхімсолюш» — and a word
 * has nowhere to break. In a 101px column that pushed the card, the carousel
 * and eventually the page 8px past the right edge of a 320px screen.
 *
 * min-width: 0 above lets the box shrink; this lets the word inside it give
 * way too. break-word rather than anywhere: it only breaks when a word truly
 * cannot fit, and leaves normal wrapping alone everywhere else.
 */
.sx-testimonial__name,
.sx-testimonial__role,
.sx-testimonial__company,
.sx-testimonial__source,
.sx-testimonial__quote {
	overflow-wrap: break-word;
}

.sx-testimonial__name {
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1.3;
}

.sx-testimonial__role,
.sx-testimonial__company {
	color: var( --sx-text-secondary );
	font-size: 0.8125rem;
	line-height: 1.35;
}

.sx-testimonial__company {
	font-weight: 500;
}

/*
 * Where a quote came from, when it was not written for us — a Google review,
 * say. Deliberately lighter than the company line: it is provenance, not part
 * of the person's identity, and it should read as a quiet footnote rather than
 * compete with their name.
 */
.sx-testimonial__source {
	color: var( --sx-text-secondary );
	font-size: 0.75rem;
	line-height: 1.35;
	opacity: 0.85;
}

@media ( max-width: 1023px ) {
	.sx-testimonials__track > .sx-testimonial {
		width: calc( ( 100cqw - 20px ) / 2 );
	}
}

/* One at a time on a phone, minus a sliver: the edge of the next card is the
   clearest signal that the row goes on. */
@media ( max-width: 700px ) {
	.sx-testimonials__track > .sx-testimonial {
		width: calc( 100cqw - 44px );
	}
}

/* ---- Blog listing ---- */

.sx-blog {
	margin-top: var( --wp--preset--spacing--60 );
}

.sx-blog__list {
	gap: 28px 20px;
}

.sx-blog__card {
	display: flex;
	flex-direction: column;
	gap: 0;
	height: 100%;
}

.sx-blog__thumb {
	margin: 0 0 14px;
}

.sx-blog__thumb img {
	border-radius: var( --sx-radius-md );
	object-fit: cover;
}

/* Posts with no picture would otherwise start at a different height from the
   ones that have one, and the grid rows would stop lining up. */
.sx-blog__card > .sx-blog__cat {
	margin: 0 0 6px;
}

.sx-blog__cat a {
	color: var( --sx-brand-text );
	font-weight: 600;
	text-decoration: none;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	font-size: 0.75rem;
}

.sx-blog__title {
	margin: 0 0 8px;
	line-height: 1.3;
}

.sx-blog__title a {
	color: inherit;
	text-decoration: none;
}

.sx-blog__title a:hover {
	color: var( --sx-brand-text );
}

.sx-blog__excerpt {
	margin: 0;
	color: var( --sx-text-secondary );
	line-height: 1.55;
}

/* Pushed to the bottom so the dates sit on one line across the row. */
.sx-blog__date {
	margin: 14px 0 0;
	padding-top: 0;
	color: var( --sx-text-secondary );
	margin-block-start: auto;
}

.sx-blog__excerpt .wp-block-post-excerpt__more-text {
	margin-top: 6px;
}

@media ( max-width: 900px ) {
	.sx-blog__list {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) ) !important;
	}
}

@media ( max-width: 600px ) {
	.sx-blog__list {
		grid-template-columns: minmax( 0, 1fr ) !important;
	}
}

/* ---- Page lead ---- */

.sx-page__lead {
	max-width: 620px;
	margin-top: 16px;
	color: var( --sx-text-secondary );
}

/* ---- Results band ---- */

.sx-results {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) auto;
	align-items: center;
	gap: 40px;
	margin-top: var( --wp--preset--spacing--70 );
	padding: 40px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-lg );
	background: var( --sx-surface );
}

.sx-results__title {
	margin: 0;
	font-size: var( --sx-title-section );
	line-height: 1.2;
}

.sx-results__lead {
	margin: 8px 0 0;
	max-width: 460px;
	color: var( --sx-text-secondary );
	font-size: 0.9375rem;
}

.sx-results__stats {
	display: flex;
	flex-wrap: wrap;
	gap: 48px;
	margin: 0;
}

.sx-results__stat {
	text-align: center;
}

.sx-results__num {
	margin: 0;
	color: var( --sx-brand-text );
	font-size: 2.25rem;
	font-weight: 700;
	line-height: 1.1;
}

.sx-results__label {
	margin: 4px 0 0;
	color: var( --sx-text-secondary );
	font-size: 0.8125rem;
}

/* ---- Tariffs section on the services page ---- */

.sx-tariffs {
	margin-top: var( --wp--preset--spacing--70 );
}

.sx-tariffs__lead {
	margin: 8px 0 var( --wp--preset--spacing--50 );
	color: var( --sx-text-secondary );
}

@media ( max-width: 900px ) {
	.sx-results {
		grid-template-columns: minmax( 0, 1fr );
		padding: 28px;
	}

	.sx-results__stats {
		gap: 32px;
	}
}

/* ---- Footer ---- */

.sx-footer__grid {
	display: grid;
	grid-template-columns: minmax( 0, 1.4fr ) repeat( 4, minmax( 0, 1fr ) );
	gap: 40px 32px;
	max-width: var( --sx-container );
	margin-inline: auto;
}

/* Matches the header's 52px. At 36 the mark sat smaller in the footer than
   anywhere else on the site and read as an afterthought rather than a signature.
   The file is 160x88, so 52px of height is 95px of width — well inside the
   column. */
.sx-footer__logo img {
	display: block;
	width: auto;
	height: 52px;
}

.sx-footer__tagline {
	margin: 16px 0 0;
	max-width: 260px;
	color: var( --sx-text-secondary );
	font-size: 0.875rem;
	line-height: 1.55;
}

.sx-footer__title {
	margin: 0 0 14px;
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: 0;
}

.sx-footer__list {
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: 0.875rem;
	line-height: 1.5;
}

.sx-footer__list li + li {
	margin-top: 10px;
}

.sx-footer__list a {
	color: var( --sx-text-secondary );
	text-decoration: none;
}

.sx-footer__list a:hover {
	color: var( --sx-brand-text );
}

.sx-footer__list--plain li {
	color: var( --sx-text-secondary );
}

/* Five numbers in a column need less air between them than four links do, or
   the contacts column runs longer than the three beside it. */
.sx-footer__list--plain li + li {
	margin-top: 7px;
}

/*
 * The operator marks, the same ones the contacts page shows.
 *
 * Their base styles live in contacts.css, which only that page loads, so the
 * footer states its own — smaller, because the footer's type is 14px against
 * the contacts card's 16px.
 */
.sx-footer__phone {
	display: flex;
	align-items: center;
	gap: 8px;
}

.sx-footer__phone .sx-phone__badge {
	display: inline-flex;
	flex: 0 0 auto;
}

.sx-footer__phone .sx-phone__badge img {
	width: 18px;
	height: 18px;
	border-radius: 50%;
	object-fit: contain;
	transition: filter var( --sx-transition-base ) var( --sx-ease ),
		opacity var( --sx-transition-base ) var( --sx-ease );
}

/* Grey at rest, the operator's own colours only under the pointer — the same
   rule the contacts page follows, and for the reason set out in tokens.css:
   three vendor palettes sitting permanently in the footer would put more colour
   there than the rest of the page uses. Devices without a pointer keep the
   colours, since they have no way to reveal them. */
@media ( hover: hover ) {
	.sx-footer__phone .sx-phone__badge img {
		filter: grayscale( 1 );
		opacity: 0.55;
	}

	.sx-footer__phone:hover .sx-phone__badge img,
	.sx-footer__phone:focus-within .sx-phone__badge img {
		filter: none;
		opacity: 1;
	}
}

.sx-footer__phone .sx-phone__icon {
	display: inline-flex;
	flex: 0 0 auto;
	color: var( --sx-text-muted );
	transition: color var( --sx-transition-fast ) var( --sx-ease );
}

.sx-footer__phone .sx-phone__icon svg {
	width: 16px;
	height: 16px;
}

.sx-footer__phone:hover .sx-phone__icon,
.sx-footer__phone:focus-within .sx-phone__icon {
	color: var( --sx-brand-text );
}

.sx-footer__bottom {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 16px;
	max-width: var( --sx-container );
	margin: var( --wp--preset--spacing--60 ) auto 0;
	padding-top: 24px;
	border-top: 1px solid var( --sx-border );
}

.sx-footer__copy {
	margin: 0;
	color: var( --sx-text-muted );
	font-size: 0.8125rem;
}

.sx-footer__social {
	display: flex;
	gap: 12px;
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: 0.8125rem;
}

/* A circle per network, the way the kit draws them: hairline ring, grey mark,
   brand colour on hover. */
.sx-social {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border: 1px solid var( --sx-border-strong );
	border-radius: 50%;
	color: var( --sx-text-secondary );
	text-decoration: none;
	transition: color var( --sx-transition-fast ) var( --sx-ease ),
		border-color var( --sx-transition-fast ) var( --sx-ease );
}

.sx-social svg {
	width: 18px;
	height: 18px;
}

.sx-social:hover {
	border-color: var( --sx-brand-text );
	color: var( --sx-brand-text );
}

.sx-social:focus-visible {
	outline: 2px solid var( --sx-brand );
	outline-offset: 2px;
}

/* A network with no mark keeps its name, so the row still reads. */
.sx-social--text {
	width: auto;
	padding-inline: 14px;
	border-radius: 999px;
}

@media ( max-width: 1023px ) {
	.sx-footer__grid {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	}

	.sx-footer__brand {
		grid-column: 1 / -1;
	}
}

@media ( max-width: 600px ) {
	/*
	 * The two columns stay on a phone. They used to collapse into one here,
	 * which turned the footer into 1349px of single-file links — most of a
	 * screen and a half of scrolling past things nobody was looking for. Two
	 * narrow columns halve that, and a footer is scanned rather than read, so
	 * the shorter measure costs nothing.
	 *
	 * The gap comes in a little, because at 360px two columns and 32px between
	 * them leave the longer labels wrapping three lines deep.
	 */
	.sx-footer__grid {
		gap: 32px 20px;
	}

	/*
	 * Contacts sit beside «Компанія» rather than across the bottom, so the
	 * grid stays a tidy 2×2 and nothing is left standing next to an empty
	 * half-row.
	 *
	 * That measure is tight, and a phone number is the one thing here that
	 * must not break: at 158px it wrapped as "+38 (050) 338-" / "14-70", which
	 * reads as two numbers. Measured, at 390px: the number wants 141px, the
	 * operator mark 18px, the gap 8px — 167px into 158px, and at 360px the
	 * column is 146px and it is 20px over.
	 *
	 * So the number is held on one line and given the room: a smaller step on
	 * the type scale, a tighter gap, and the operator mark stepping aside
	 * below 600px. The mark is the only thing dropped, and it is the only
	 * thing here that is decoration — the operator's name still reaches a
	 * screen reader through the link, and the number itself is what somebody
	 * came to the footer to read.
	 */
	.sx-footer__col--contacts .sx-footer__list {
		gap: 10px;
	}

	.sx-footer__phone {
		gap: 6px;
	}

	.sx-footer__phone a {
		font-size: 0.8125rem;
		white-space: nowrap;
	}
}

/*
 * Whether the operator mark fits is a question about the column, not about the
 * screen — and asking the wrong one is what dropped the marks on a 555px
 * tablet where the column is 238px wide and there was room to spare.
 *
 * A number holds 132px, the gap 6px and the mark 18px: 156px. Below 168px the
 * three of them stop fitting on one line and the mark steps aside; above it
 * everything stays. Measured, that keeps the marks from 414px up and drops
 * them at 390px and below, which is where the column really does run out.
 */
.sx-footer__col--contacts {
	container-type: inline-size;
}

@container ( max-width: 168px ) {
	.sx-footer__phone .sx-contacts__mark,
	.sx-footer__phone img,
	.sx-footer__phone svg {
		display: none;
	}
}

/*
 * Below this the two columns stop being possible: the number holds 132px and
 * the column is down to 123px, so nowrap pushes it through the right edge of
 * the page. Contacts take the full width again — the 2×2 grid holds from
 * 360px up, which covers every phone still in use; this is the escape hatch
 * for the narrowest of them.
 */
@media ( max-width: 340px ) {
	.sx-footer__col--contacts {
		grid-column: 1 / -1;
	}
}


/* ---- About Softex ---- */

.sx-about {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) minmax( 0, 46% );
	align-items: center;
	gap: 56px;
}

.sx-about__title {
	margin: 0;
	max-width: 18ch;
	font-size: var( --sx-title-section );
	line-height: 1.15;
	letter-spacing: -0.02em;
}

.sx-about__lead {
	margin: 20px 0 0;
	max-width: 60ch;
	color: var( --sx-text-secondary );
	line-height: 1.65;
}

.sx-about__points {
	margin: 28px 0 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 14px;
}

.sx-about__points li {
	display: grid;
	grid-template-columns: 20px minmax( 0, 1fr );
	gap: 12px;
	max-width: 62ch;
	font-size: 0.9375rem;
	line-height: 1.5;
}

/* Nudged down to sit on the first line's optical centre rather than its box
   top, which is where a 20px glyph beside 15px text otherwise lands. */
.sx-about__tick {
	display: block;
	width: 20px;
	height: 20px;
	margin-top: 1px;
	color: var( --sx-brand-text );
}

.sx-about__tick svg {
	display: block;
	width: 100%;
	height: 100%;
}

.sx-about__more {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin-top: 28px;
	color: var( --sx-brand-text );
	font-size: 0.9375rem;
	font-weight: 600;
	text-decoration: none;
}

.sx-about__more:hover {
	color: var( --sx-brand-hover );
	text-decoration: underline;
}

/* ---- The scheme in the "Технології мають працювати на бізнес" block ----
   A drawn panel where a photograph used to be. Built from the kit's own
   surface, radius and shadow so it reads as part of the site rather than as
   an illustration dropped into it. */

.sx-about__scheme {
	padding: 28px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-lg );
	background: var( --sx-gradient-surface );
	box-shadow: var( --sx-shadow-card );
}

.sx-about__scheme-title {
	margin: 0 0 18px;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var( --sx-text-muted );
}

.sx-about__areas {
	display: grid;
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	gap: 12px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Two by two rather than a column: the text beside this is already a list of
   bullets, and a second vertical list would read as its echo. */
.sx-about__area {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 16px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-md );
	background: var( --sx-white );
}

.sx-about__area-icon {
	display: inline-flex;
	margin-bottom: 8px;
	color: var( --sx-brand-text );
}

.sx-about__area-icon svg {
	width: 22px;
	height: 22px;
}

.sx-about__area-name {
	font-weight: 600;
	line-height: 1.25;
}

.sx-about__area-note {
	color: var( --sx-text-secondary );
	font-size: 0.875rem;
	line-height: 1.3;
}

/* The line that turns four boxes into an offer: the areas are what the system
   covers, this is who makes it work. */
.sx-about__scheme-foot {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 18px 0 0;
	padding-top: 16px;
	border-top: 1px solid var( --sx-border );
	color: var( --sx-text-secondary );
	font-size: 0.875rem;
	line-height: 1.4;
}

.sx-about__scheme-foot-icon {
	display: inline-flex;
	flex: 0 0 auto;
	color: var( --sx-brand-text );
}

.sx-about__scheme-foot-icon svg {
	width: 20px;
	height: 20px;
}

@media ( max-width: 900px ) {
	.sx-about {
		grid-template-columns: minmax( 0, 1fr );
		gap: 28px;
	}

	/*
	 * The order on a phone, where the two columns become one long strip.
	 *
	 * The rule here used to be `.sx-about__art { order: -1 }` — "photo first
	 * on a phone", written when that slot held the team photograph. A picture
	 * first does work: you look, then you read the heading. But the slot holds
	 * a labelled diagram and a list of AI features now, and text that arrives
	 * before its heading is text with nothing to attach itself to. Scrolling
	 * down, the section opened on a scheme nobody had introduced.
	 *
	 * So: the heading, then the one thing it is really promising — ШІ у вашому
	 * обліку — and only then who we are and since when. Claim, proof, company.
	 *
	 * The wrapper is dissolved with display:contents so the heading can be
	 * ordered apart from the rest of its own column; it carries no styles of
	 * its own, so nothing is lost with it. Their top margins go with it too —
	 * spacing is the grid's gap now, and keeping both would double it.
	 */
	.sx-about__text {
		display: contents;
	}

	.sx-about__title {
		order: 1;
		max-width: none;
	}

	.sx-about__art {
		order: 2;
	}

	.sx-about__lead {
		order: 3;
		margin-top: 0;
	}

	.sx-about__points {
		order: 4;
		margin-top: 0;
	}

	.sx-about__more {
		order: 5;
		margin-top: 0;
		justify-self: start;
	}

	/*
	 * And shortened. The four areas and the card's own title are the longest
	 * part of the section on a phone and the least load-bearing: the heading
	 * above already says the systems run the business, and the AI rows below
	 * are the specific thing worth stopping for. They stay on desktop, where
	 * they fill the second column and cost nothing.
	 */
	.sx-about__scheme-title,
	.sx-about__areas {
		display: none;
	}

	/*
	 * And with the areas gone, the card around them has nothing left to frame
	 * but another card. Its chrome comes off on a phone so the AI block stands
	 * on its own — one border instead of two, and the support line below it
	 * sits on the page rather than in a box.
	 */
	.sx-about__scheme {
		padding: 0;
		border: 0;
		background: none;
		box-shadow: none;
	}
}

/* ---- Process timeline ---- */

.sx-process__list {
	/* Named so the connecting rule below and the grid cannot drift apart: the
	   rule's geometry is derived from this exact number. */
	--sx-process-gap: 24px;
	--sx-process-marker: 38px;

	position: relative;
	display: grid;
	grid-template-columns: repeat( 5, minmax( 0, 1fr ) );
	gap: var( --sx-process-gap );
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * The rule runs between the centres of the first and last markers so it does
 * not stick out past them. The markers sit at the *left* of their columns, not
 * centred in them, so the right end is a whole column short of the end minus
 * half a marker — measuring to the column centres instead leaves the rule
 * visibly offset to the right.
 */
.sx-process__list::before {
	content: "";
	position: absolute;
	top: calc( var( --sx-process-marker ) / 2 );
	left: calc( var( --sx-process-marker ) / 2 );
	right: calc(
		( 100% - 4 * var( --sx-process-gap ) ) / 5 - var( --sx-process-marker ) / 2
	);
	height: 1px;
	background: var( --sx-border );
}

.sx-process__step {
	position: relative;
}

/* Opaque, so it masks the rule passing behind it instead of being crossed
   out by it. */
.sx-process__marker {
	position: relative;
	z-index: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var( --sx-process-marker, 38px );
	height: var( --sx-process-marker, 38px );
	border: 1px solid var( --sx-border-strong );
	border-radius: 50%;
	background: var( --sx-white );
	color: var( --sx-brand-text );
	font-size: 0.9375rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

.sx-process__title {
	margin: 20px 0 0;
	font-size: 1.0625rem;
	line-height: 1.3;
}

.sx-process__text {
	margin: 8px 0 0;
	color: var( --sx-text-secondary );
	font-size: 0.9375rem;
	line-height: 1.55;
}

/* Vertical below the point where five columns stop giving the copy a readable
   measure. The rule moves to the left of the markers and runs between them. */
@media ( max-width: 1023px ) {
	.sx-process__list {
		grid-template-columns: minmax( 0, 1fr );
		gap: 28px;
	}

	.sx-process__list::before {
		content: none;
	}

	.sx-process__step {
		padding-left: 58px;
	}

	.sx-process__step:not( :last-child )::before {
		content: "";
		position: absolute;
		top: 42px;
		bottom: -32px;
		left: 19px;
		width: 1px;
		background: var( --sx-border );
	}

	.sx-process__marker {
		position: absolute;
		top: 0;
		left: 0;
	}

	.sx-process__title {
		margin-top: 7px;
	}
}

/* ---- Wide CTA card ---- */

.sx-cta-card {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) auto;
	align-items: center;
	gap: 32px;
	margin-top: var( --wp--preset--spacing--70 );
	/* Tight top and bottom on purpose: the artwork is the tallest thing in the
	   card, so this padding is what stands between it and the card's edge. */
	padding: 18px 40px;
	border-radius: var( --sx-radius-lg );
	/* The same drifting ground as the hero, so the page opens and closes on the
	   same note. It was a flat --sx-surface, which this ramp passes through. */
	background: var( --sx-gradient-drift );
	position: relative;
	/* Also what keeps the moving layer inside the rounded corners. */
	overflow: hidden;
	isolation: isolate;
}

/*
 * Absolutely positioned, which is load-bearing beyond placing it: this card is
 * a two-column grid, and an in-flow pseudo-element would become a third grid
 * item and take a column of its own. Out of flow, it is not a grid item at all.
 */
.sx-cta-card::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	z-index: -1;
	width: 400%;
	height: 100%;
	background: var( --sx-gradient-drift );
	animation: sx-gradient-drift 8s ease infinite;
	will-change: transform;
	pointer-events: none;
}

@media ( prefers-reduced-motion: reduce ) {
	.sx-cta-card::before {
		animation: none;
		transform: none;
		will-change: auto;
	}
}

.sx-cta-card__title {
	margin: 0;
	font-size: var( --sx-title-section );
	line-height: 1.2;
}

.sx-cta-card__lead {
	margin: 10px 0 24px;
	max-width: 480px;
	color: var( --sx-text-secondary );
}

.sx-cta-card__btn {
	display: inline-flex;
	align-items: center;
	min-height: var( --sx-control-height );
	padding-inline: 24px;
	border-radius: var( --sx-radius-btn );
	background: var( --sx-brand );
	color: var( --sx-white );
	font-size: 0.875rem;
	font-weight: 600;
	text-decoration: none;
}

.sx-cta-card__btn:hover {
	background: var( --sx-brand-hover );
	color: var( --sx-white );
}

/* Sized by height. The artwork sets the card's height, so this number and the
   card's vertical padding are the only two things deciding how close it comes
   to the edge — there is no separate "image size" to tune. */
.sx-cta-card__art {
	max-width: 100%;
}

.sx-cta-card__art svg {
	display: block;
	width: auto;
	height: 210px;
	max-width: 100%;
}

/* ---- Feature lists ---- */

.sx-features {
	margin-top: var( --wp--preset--spacing--70 );
	padding: 40px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-lg );
	background: var( --sx-white );
}

.sx-features__title {
	margin: 0 0 var( --wp--preset--spacing--40 );
	font-size: var( --sx-title-section );
	line-height: 1.2;
}

.sx-features__list {
	display: grid;
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	gap: 20px 32px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.sx-features__list--rich {
	grid-template-columns: repeat( 4, minmax( 0, 1fr ) );
	align-items: start;
}

.sx-features__item {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	font-size: 0.9375rem;
}

.sx-features__item .sx-icon {
	flex: 0 0 auto;
	display: inline-flex;
}

.sx-features__item .sx-icon svg {
	width: 20px;
	height: 20px;
}

.sx-features__body {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.sx-features__name {
	font-weight: 600;
}

.sx-features__text {
	color: var( --sx-text-secondary );
	font-size: 0.8125rem;
	line-height: 1.5;
}

@media ( max-width: 1023px ) {
	.sx-features__list,
	.sx-features__list--rich {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	}
}

@media ( max-width: 700px ) {
	/* The artwork stays beside the copy rather than dropping underneath it —
	   stacked, it left the button with an empty half-row next to it and pushed
	   the card a long way down the page. It only has to get small enough that
	   the heading still has a sensible measure.

	   The column gets an explicit width because the intrinsic one does not
	   survive here: an auto track sizes to its content, the SVG's max-width is
	   a percentage of that same track, and the circular reference resolves to a
	   zero contribution — the track collapses and the graphic hangs out past
	   the card. */
	.sx-cta-card {
		grid-template-columns: minmax( 0, 1fr ) 104px;
		gap: 14px;
		padding: 24px;
	}

	.sx-cta-card__title {
		font-size: 1.25rem;
	}

	.sx-cta-card__art svg {
		width: 100%;
		height: auto;
	}

	/* Buys the heading and the button the width the artwork took. */
	.sx-cta-card__btn {
		padding-inline: 18px;
	}

	.sx-features {
		padding: 24px;
	}

	.sx-features__list,
	.sx-features__list--rich {
		grid-template-columns: minmax( 0, 1fr );
	}
}

/* ---- Compact case tile (homepage) ---- */

.sx-case-tile {
	min-height: 200px;
}

.sx-case-tile__mark {
	display: flex;
	align-items: center;
	min-height: 48px;
}

.sx-case-tile__mark img {
	max-width: 130px;
	max-height: 44px;
	width: auto;
	height: auto;
	object-fit: contain;
	filter: grayscale( 1 );
	opacity: 0.75;
	transition: filter var( --sx-transition-base ) var( --sx-ease ),
		opacity var( --sx-transition-base ) var( --sx-ease );
}

.sx-case-tile:hover .sx-case-tile__mark img {
	filter: none;
	opacity: 1;
}

/*
 * The photo runs to the card's edges, so it takes the padding back with a
 * negative margin and rounds only its own two corners — one pixel tighter than
 * the card, which is the border it sits inside.
 */
.sx-case-tile__thumb {
	position: relative;
	display: block;
	overflow: hidden;
	margin: -24px -24px 16px;
	height: 140px;
	border-radius: calc( var( --sx-radius-lg ) - 1px ) calc( var( --sx-radius-lg ) - 1px ) 0 0;
	background: var( --sx-surface );
}

.sx-case-tile__thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var( --sx-transition-base ) var( --sx-ease );
}

.sx-case-tile:hover .sx-case-tile__thumb img {
	transform: scale( 1.04 );
}

/* Cases whose client is not on the partners list show the sector instead. */
.sx-case-tile__industry {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var( --sx-brand-text );
}

/* Over a photo the sector becomes a chip, so it stays readable whatever the
   picture underneath happens to be. */
.sx-case-tile__thumb .sx-case-tile__industry {
	position: absolute;
	top: 12px;
	left: 12px;
	padding: 5px 10px;
	border-radius: 999px;
	background: rgba( 255, 255, 255, 0.92 );
	font-size: 0.6875rem;
	line-height: 1;
}

.sx-case-tile__text {
	margin-top: 16px;
	color: var( --sx-text );
	font-size: 0.9375rem;
	font-weight: 500;
	line-height: 1.4;
}

@media ( prefers-reduced-motion: reduce ) {
	.sx-case-tile__mark img,
	.sx-case-tile__thumb img {
		transition: none;
	}
}

/* ---- 03. Trust / Statistics ----
 * Lucide icon, red accent, thin dividers between items.
 *
 * The rules are drawn as inset pseudo-elements rather than borders on the
 * cells: a border runs the full cell height and butts into the card edge,
 * which reads as a heavy table rule. Inset to 60% and hairline-thin it reads
 * as a separator instead of a frame.
 */

.sx-stats {
	display: grid;
	grid-template-columns: repeat( 4, minmax( 0, 1fr ) );
	margin: 0;
	padding: 8px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-lg );
	background: var( --sx-white );
}

/* The row used to be the flex container, with the icon and a wrapper div as its
   two children. The wrapper had to go — see about.php — so the flexing moved
   down onto the term itself, and the label is indented to stay under the number
   rather than under the icon. */
.sx-stats__item {
	position: relative;
	padding: 18px 24px;
	/*
	 * The mark's size, read by the caption below so its left edge meets the
	 * number's rather than the icon's.
	 *
	 * A taller mark, spanning the number and the caption together, was tried
	 * and taken back out: out of the flow it could only measure itself against
	 * the cell, and the cells in this row are stretched to the tallest of the
	 * four — so wherever the caption fitted on one line the mark hung below the
	 * words. Beside the number it is the same height in all four.
	 */
	--sx-stat-icon: clamp( 30px, 3.4vw, 40px );
}

.sx-stats__item + .sx-stats__item::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	top: 20%;
	height: 60%;
	border-inline-start: 1px solid var( --sx-border );
}

.sx-stats__num {
	display: flex;
	align-items: center;
	gap: 14px;
	margin: 0;
	font-size: 1.75rem;
	font-weight: 700;
	line-height: 1.1;
	letter-spacing: -0.02em;
}

.sx-stats__icon {
	flex: 0 0 auto;
	display: inline-flex;
	color: var( --sx-brand-text );
}

.sx-stats__icon svg {
	width: var( --sx-stat-icon );
	height: var( --sx-stat-icon );
}

.sx-stats__num-text {
	min-width: 0;
}

.sx-stats__label {
	/* The mark plus the gap beside it: the caption lines up with the number,
	   not with the icon. Derived from the same custom property, so the two
	   cannot drift apart when the mark's size changes. */
	margin: 2px 0 0;
	padding-inline-start: calc( var( --sx-stat-icon ) + 14px );
	color: var( --sx-text-secondary );
	font-size: 0.8125rem;
	line-height: 1.35;
}

@media ( max-width: 900px ) {
	.sx-stats {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	}

	/* Two per row: the vertical rule restarts on each row, and a horizontal
	   one separates the rows. */
	.sx-stats__item:nth-child( odd )::before {
		content: none;
	}

	.sx-stats__item:nth-child( n + 3 )::after {
		content: "";
		position: absolute;
		top: 0;
		inset-inline: 10%;
		border-top: 1px solid var( --sx-border );
	}
}

@media ( max-width: 520px ) {
	.sx-stats {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-stats__item {
		padding: 16px 18px;
	}

	.sx-stats__item::before {
		content: none;
	}

	.sx-stats__item + .sx-stats__item::after {
		content: "";
		position: absolute;
		top: 0;
		inset-inline: 10%;
		border-top: 1px solid var( --sx-border );
	}
}

/* ---- 404 ----
   The page someone reaches when something has already gone wrong, so it is
   built as a set of exits rather than an apology. Sized off the shared title
   tokens so it reads as a page of this site. */

.sx-404 {
	padding-block: clamp( 32px, 6vw, 72px ) clamp( 48px, 8vw, 96px );
}

.sx-404__code {
	margin: 0 0 12px;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	color: var( --sx-text-muted );
}

.sx-404__title {
	margin: 0;
	font-size: var( --sx-title-page );
	line-height: 1.1;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

.sx-404__lede {
	max-width: 56ch;
	margin: 16px 0 0;
	color: var( --sx-text-secondary );
	font-size: 1.0625rem;
}

.sx-404__search {
	max-width: 480px;
	margin-top: 28px;
}

.sx-404__subtitle {
	margin: 48px 0 20px;
	font-size: var( --sx-title-section );
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.sx-404__links {
	display: grid;
	grid-template-columns: repeat( auto-fit, minmax( 240px, 1fr ) );
	gap: 12px;
}

.sx-404__link {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 18px 20px;
	border: 1px solid var( --sx-border );
	border-radius: var( --sx-radius-md );
	background: var( --sx-white );
	text-decoration: none;
	transition: border-color var( --sx-transition-fast ) var( --sx-ease ),
		background-color var( --sx-transition-fast ) var( --sx-ease );
}

.sx-404__link:hover {
	border-color: var( --sx-brand-200 );
	background: var( --sx-brand-50 );
}

.sx-404__link:active {
	transform: translateY( 1px );
}

.sx-404__link-title {
	font-weight: 600;
	color: var( --sx-text );
}

.sx-404__link-note {
	font-size: 0.875rem;
	color: var( --sx-text-secondary );
}

/* The legal link sits next to the copyright line rather than in the column
   list above it: it is a notice, not a navigation destination. */
.sx-footer__legal {
	margin-left: 14px;
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 3px;
}

.sx-footer__legal:hover {
	color: var( --sx-brand-text );
}

/*
 * The closing row, once it stops being a row.
 *
 * Above 760px the copyright, the notice beside it and the social marks share
 * one line with the marks pushed to the far end. Below that the marks drop
 * underneath, and by about 410px the notice itself wraps — badly, because the
 * 14px that separated it from the copyright while they shared a line became a
 * stray indent once it had a line of its own. Left aligned, the three parts
 * then read as things that failed to fit rather than as a footer.
 *
 * Centred and stacked, they read as an ending. The breakpoint is the theme's
 * usual phone one rather than the exact width the wrap happens at: between the
 * two the row is already stacked, and a centred stack is right there too.
 *
 * Written here, below the two rules it overrides, and not up with the other
 * footer media queries — which is where it went first. A media query adds no
 * weight of its own, so a block of the same single-class selectors placed
 * earlier in the file loses to them: the margin-left below stayed on, and the
 * link sat 14px right of the centre it was supposed to be at.
 */
@media ( max-width: 560px ) {
	.sx-footer__bottom {
		flex-direction: column;
		align-items: center;
		text-align: center;
	}

	.sx-footer__legal {
		display: block;
		margin-left: 0;
		margin-top: 6px;
	}
}

/* ---- The narrowest phones ----
   Below roughly 360px the call-to-action card ran out of room. Its two columns
   are the text and a fixed 104px graphic, so the text was left with
   viewport - 206px: at 320 that is 114px against the 152px the heading
   "Готові автоматизувати бізнес?" needs, and the card pushed the page sideways.

   The graphic carries aria-hidden, so dropping it costs nothing a reader was
   meant to get; the heading and the button are the point of the card. 380px
   rather than 358 so the text has room to breathe rather than only just fit. */

@media ( max-width: 380px ) {
	.sx-cta-card {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-cta-card__art {
		display: none;
	}
}

/* Two columns need about 127px per tile for "Бухгалтерія" to sit on one line
   with its padding. Below this the pair no longer has the room, and the word
   spills over the tile's edge — so the four become a single column, where they
   read as wide rows rather than cramped squares. */
@media ( max-width: 420px ) {
	.sx-about__areas {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-about__area {
		flex-direction: row;
		align-items: baseline;
		flex-wrap: wrap;
		gap: 0 6px;
		padding: 14px 16px;
	}

	.sx-about__area-icon {
		flex-basis: 100%;
		margin-bottom: 6px;
	}
}



/* ---- The two AI products inside the scheme ----
   Tinted and linked, because these are the one thing in this block a competitor
   cannot copy off a price list — and each already has an article to read. */

.sx-about__ai {
	margin-top: 16px;
	padding: 14px 16px;
	border: 1px solid var( --sx-brand-200 );
	border-radius: var( --sx-radius-md );
	background: var( --sx-brand-50 );
}

.sx-about__ai-title {
	margin: 0 0 10px;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var( --sx-brand-text );
}

.sx-about__ai-row {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 8px 0;
	color: inherit;
	text-decoration: none;
}

.sx-about__ai-row + .sx-about__ai-row {
	border-top: 1px solid var( --sx-brand-200 );
}

.sx-about__ai-icon {
	display: inline-flex;
	flex: 0 0 auto;
	margin-top: 2px;
	color: var( --sx-brand-text );
}

.sx-about__ai-icon svg {
	width: 20px;
	height: 20px;
}

.sx-about__ai-name {
	display: block;
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1.3;
}

.sx-about__ai-text {
	display: block;
	margin-top: 2px;
	color: var( --sx-text-secondary );
	font-size: 0.8125rem;
	line-height: 1.4;
}

.sx-about__ai-row:hover .sx-about__ai-name {
	color: var( --sx-brand-text );
}

/* The closing line is a footnote to the whole panel; the tinted block above
   already separates it from the tiles, so it drops its own rule. */
.sx-about__ai + .sx-about__scheme-foot {
	margin-top: 12px;
	padding-top: 0;
	border-top: 0;
}

/* ---- Page headers ----

   One rule for the three pages that open with a heading, a lead and the cube
   beside it: Проєкти, Блог and Про нас.

   They used to have three. Each was sensible on its own — the cube was 200px
   wide here, 140px tall there and 300px tall on the third — and each carried a
   comment explaining the number it had settled on. What none of them could
   have is a family: side by side the same artwork appeared at 144, 200 and 308
   pixels, which reads as three sites rather than three pages.

   What is shared is not the size but the measure. The cube is as tall as the
   words beside it and no taller, which is the thing every one of those three
   comments was reaching for: an image taller than the text opens empty bands
   above and below it, because the row takes the height of whatever is tallest
   in it. Написане так, the difference between the pages stops being arbitrary
   — Про нас has an eyebrow, a longer lead and two buttons, so its cube is
   bigger for a reason a reader can see.

   Lives here rather than in projects.css, blog.css and about.css because this
   file is loaded on every page and those three are loaded after it: a shared
   rule they could each override is not a shared rule. */

.sx-cases-hero,
.sx-blog-hero,
.sx-about-hero {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) auto;
	/* stretch, not center: the art column has to take the row's full height
	   before the picture inside it can be measured against it. */
	align-items: stretch;
	gap: var( --wp--preset--spacing--50 );
	margin-bottom: var( --wp--preset--spacing--50 );
	/*
	 * A floor under the whole band, which is what the cube is measured against
	 * when a page has little to say. Проєкти and Блог carry a title and two
	 * lines of lead — 104px of words — and a cube that size beside a 34px
	 * heading reads as an afterthought rather than as part of the composition.
	 * Про нас needs none of this: its own text is taller than the floor.
	 */
	min-height: 176px;
}

/* Centred in a band that may be taller than it. */
.sx-cases-hero__text,
.sx-blog-hero__text,
.sx-about-hero__text {
	align-self: center;
}

/*
 * The column has a width of its own and the picture is taken out of the flow
 * inside it. Both halves matter.
 *
 * Left in the flow and told to be as tall as its row, the picture is asked to
 * measure itself against something it is itself part of. The browser resolves
 * that circle by letting the picture win: it grew to its own ceiling and
 * stretched the text beside it to match, so all three headers came out at
 * exactly 300px and the About header at twice that. The whole point was the
 * other way round.
 *
 * Absolutely positioned, it contributes no height at all. The row is then as
 * tall as the words, full stop, and the picture fills that height without ever
 * being consulted about it.
 */
.sx-cases-hero__art,
.sx-blog-hero__art,
.sx-about-hero__art {
	position: relative;
	/* A definite width is what breaks the circle: with this known, nothing
	   below needs the row's height to work out how wide the column is. */
	width: clamp( 132px, 22vw, 320px );
}

.sx-cases-hero__art img,
.sx-blog-hero__art img,
.sx-about-hero__art img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	/* contain, so the cube is as tall as the text on a page whose text is
	   short and as wide as the column on one whose text is long — never
	   stretched out of its own proportions to reach either. */
	object-fit: contain;
	object-position: right center;
}

/* One breakpoint for all three — it was 782 on Проєкти and 900 on the other
   two. Below it the cube would sit above the heading and push the first row of
   content off the screen, so it goes; it is decoration and carries
   aria-hidden, so nothing is lost with it. */
@media ( max-width: 900px ) {
	.sx-cases-hero,
	.sx-blog-hero,
	.sx-about-hero {
		grid-template-columns: minmax( 0, 1fr );
	}

	.sx-cases-hero__art,
	.sx-blog-hero__art,
	.sx-about-hero__art {
		display: none;
	}
}
