/*
Theme Name: ULS Logistic
Theme URI: https://3pl.uz/
Author: Freebuff
Author URI: https://freebuff.com/
Description: Kompleks 3PL-logistika uchun korporativ WordPress mavzusi. Figma dizayni asosida qurilgan: hero, xizmatlar, WMS jarayoni, xizmat modeli taqqoslash, terminallar, 3PL kalkulyator, CTA, mijozlar va footer.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: uls-logistic
Tags: business, portfolio, custom-menu, custom-logo, featured-images, translation-ready, full-width-template
*/

/* =========================================================================
   01. DESIGN TOKENS
   ========================================================================= */
:root {
	--uls-bg: #04081c;
	--uls-bg-2: #070d29;
	--uls-bg-3: #0a1136;
	--uls-surface: rgba(255, 255, 255, 0.028);
	--uls-surface-2: rgba(255, 255, 255, 0.05);
	--uls-border: rgba(141, 166, 255, 0.16);
	--uls-border-strong: rgba(141, 166, 255, 0.32);

	--uls-blue: #2b4bf2;
	--uls-blue-hover: #3a5bff;
	--uls-blue-soft: #4d6dff;
	--uls-blue-text: #6f8dff;
	--uls-accent: #e8402a;

	--uls-text: #ffffff;
	--uls-muted: #9aa3bd;
	--uls-muted-2: #6f7896;

	--uls-radius: 18px;
	--uls-radius-lg: 24px;
	--uls-radius-pill: 999px;

	/*
	 * Two faces, because running text and display text are different jobs.
	 *
	 * Manrope is the voice the design was drawn in: geometric, slightly
	 * condensed, confident at 24px and up. It is the display face.
	 *
	 * Inter is the reading face. Its big x-height, open apertures and taller
	 * ascenders keep 13–16px Cyrillic crisp on a dark background — and on
	 * Windows, where most of this site is read, ClearType turns Manrope's
	 * tighter small sizes thin and washed out. Inter also has real tabular
	 * figures, which the numbers in the rail and the counters need.
	 *
	 * Both come from one Google Fonts request and share the same fallback
	 * chain, so a font that fails to load is replaced by the same metrics
	 * either way.
	 */
	--uls-font: "Inter", "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--uls-font-display: "Manrope", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	/*
	 * Type scale (Правки 29.10.2026, п. 3). Every text on the site takes one of
	 * these steps instead of its own pixel value, so a heading, a card title or a
	 * caption is the same size on every page. Headings are fluid between a 375px
	 * phone and a 1440px desktop; reading sizes are fixed, because body text that
	 * shrinks with the window only gets harder to read.
	 *
	 *   display  page / hero H1          32 → 54
	 *   h2       section title           28 → 42
	 *   h3       large card title        22 → 26  (terminal, figure)
	 *   h4       card / row title        19 → 21
	 *   h5       small card title        18
	 *   lead     intro paragraph         16 → 18
	 *   body     paragraphs              16
	 *   sm       secondary text, UI      15  (buttons, nav, footer links)
	 *   xs       labels, notes           14
	 *   micro    eyebrows, dates         13  (tracked caps stay legible at 13)
	 *   2xs      tiny tracked labels     12
	 */
	--uls-fs-display: clamp(32px, 2.4vw + 18px, 54px);
	--uls-fs-h2: clamp(28px, 1.8vw + 16px, 42px);
	--uls-fs-h3: clamp(22px, 0.9vw + 13px, 26px);
	--uls-fs-h4: clamp(19px, 0.5vw + 14px, 21px);
	--uls-fs-h5: 18px;
	--uls-fs-lead: clamp(16px, 0.3vw + 14px, 18px);
	--uls-fs-body: 16px;
	--uls-fs-sm: 15px;
	--uls-fs-xs: 14px;
	--uls-fs-micro: 13px;
	--uls-fs-2xs: 12px;
	/* Manrope at 800 reads as a blot in Cyrillic at card sizes; 700 keeps the
	   display voice and opens the counters of «ш», «щ», «ж». */
	--uls-fw-heading: 700;
	--uls-lh-heading: 1.15;
	--uls-lh-body: 1.6;

	--uls-container: 1440px;
	--uls-gutter: clamp(20px, 5vw, 88px);
}

/* =========================================================================
   02. RESET / BASE
   ========================================================================= */
*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	scroll-behavior: smooth;
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--uls-bg);
	color: var(--uls-text);
	font-family: var(--uls-font);
	font-size: var(--uls-fs-body);
	line-height: var(--uls-lh-body);
	font-weight: 400;
	overflow-x: hidden;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

body.uls-menu-open {
	overflow: hidden;
}

img,
svg,
video {
	max-width: 100%;
	height: auto;
	display: block;
}

a {
	color: inherit;
	text-decoration: none;
	transition: color 0.2s ease, opacity 0.2s ease;
}

button {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	cursor: pointer;
}

h1, h2, h3, h4, h5, h6 {
	margin: 0;
	font-family: var(--uls-font-display);
	font-weight: var(--uls-fw-heading);
	line-height: var(--uls-lh-heading);
	letter-spacing: -0.02em;
}

p {
	margin: 0;
}

ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

::selection {
	background: var(--uls-blue);
	color: #fff;
}

:focus-visible {
	outline: 2px solid var(--uls-blue-soft);
	outline-offset: 3px;
	border-radius: 6px;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px !important;
	height: 1px !important;
	min-width: 0 !important;
	padding: 0 !important;
	margin: -1px !important;
	overflow: hidden !important;
	clip: rect(0, 0, 0, 0) !important;
	clip-path: inset(50%) !important;
	white-space: nowrap !important;
	border: 0 !important;
}

.skip-link:focus {
	position: fixed;
	top: 12px;
	left: 12px;
	z-index: 9999;
	width: auto;
	height: auto;
	clip: auto;
	padding: 12px 20px;
	background: var(--uls-blue);
	color: #fff;
	border-radius: 10px;
}

/* Page glow background */
.uls-page {
	position: relative;
	background:
		radial-gradient(1200px 620px at 50% -10%, rgba(43, 75, 242, 0.20), transparent 62%),
		radial-gradient(900px 500px at 100% 8%, rgba(43, 75, 242, 0.10), transparent 60%),
		linear-gradient(180deg, var(--uls-bg-2) 0%, var(--uls-bg) 48%, #03061a 100%);
}

/* =========================================================================
   03. LAYOUT HELPERS
   ========================================================================= */
.uls-container {
	width: 100%;
	max-width: var(--uls-container);
	margin-inline: auto;
	padding-inline: var(--uls-gutter);
}

.uls-section,
.uls-cta,
.uls-hero,
.uls-footer {
	scroll-margin-top: 96px; /* sticky header offset for in-page anchors */
}

.uls-section {
	padding-block: clamp(56px, 7vw, 110px);
	position: relative;
}

.uls-section--tight {
	padding-block: clamp(40px, 5vw, 72px);
}

.uls-section-head {
	max-width: 900px;
	margin-inline: auto;
	text-align: center;
	margin-bottom: clamp(36px, 4.5vw, 64px);
}

/*
 * Wide tracking at 13px is the hardest combination to read on a dark ground,
 * so the label takes the brighter muted tone: `--uls-muted-2` on `--uls-bg`
 * lands at about 4.5:1, which is where small tracked caps start to smear.
 */
.uls-eyebrow {
	display: block;
	font-size: var(--uls-fs-micro);
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--uls-muted);
	margin-bottom: 18px;
}

.uls-h2 {
	font-size: var(--uls-fs-h2);
	margin-bottom: 20px;
}

.uls-h3 {
	font-size: var(--uls-fs-h3);
}

.uls-lead {
	color: var(--uls-muted);
	font-size: var(--uls-fs-lead);
	line-height: 1.6;
	max-width: 760px;
	margin-inline: auto;
	text-wrap: pretty;
}

.uls-text-blue {
	color: var(--uls-blue-text);
}

/* =========================================================================
   04. BUTTONS
   ========================================================================= */
/*
 * The reference build hangs two hover effects on every one of its buttons
 * (`theme-btn` in inotek): a band of light crossing the pill, and an arrow that
 * swaps itself for a second copy. Both are copied here, and both need the same
 * two things — a positioned box to hang the pseudo-elements on, and
 * `overflow: hidden` so the light and the outgoing arrow are cut off by the
 * pill's own edge instead of flying across the page.
 *
 * The arrow is painted as a **mask** of `currentColor`, so one rule gives the
 * blue button a white arrow and the white button a navy one without a second
 * asset — the theme already reaches for masks for this kind of job (the marquee
 * edges, 15).
 */
.uls-btn {
	--uls-btn-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m13 6 6 6-6 6'/%3E%3C/svg%3E");

	position: relative;
	overflow: hidden;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	padding: 15px 28px;
	border-radius: var(--uls-radius-pill);
	font-size: var(--uls-fs-sm);
	font-weight: 700;
	line-height: 1;
	white-space: nowrap;
	border: 1px solid transparent;
	transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.uls-btn:hover {
	transform: translateY(-1px);
}

.uls-btn--primary {
	background: var(--uls-blue);
	color: #fff;
	box-shadow: 0 12px 30px -12px rgba(43, 75, 242, 0.9);
}

.uls-btn--primary:hover {
	background: var(--uls-blue-hover);
	color: #fff;
	box-shadow: 0 16px 34px -12px rgba(43, 75, 242, 0.95);
}

.uls-btn--glass {
	background: rgba(255, 255, 255, 0.06);
	border-color: var(--uls-border);
	color: #fff;
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
}

.uls-btn--glass:hover {
	background: rgba(255, 255, 255, 0.12);
	border-color: var(--uls-border-strong);
	color: #fff;
}

.uls-btn--light {
	background: #fff;
	color: #0d1330;
}

.uls-btn--light:hover {
	background: #eef1ff;
	color: #0d1330;
}

/*
 * Header buttons: the design's pill labels measure 15px (label span 197.6 CSS px
 * against 177.75 px at 13.5px), while the pill height grows by exactly the font
 * difference, so the padding stays as it is.
 */
.uls-btn--sm {
	padding: 11px 18px;
	font-size: var(--uls-fs-sm);
}

/*
 * The light. `left: -200%` parks a band two pill-widths off the left edge; on
 * hover it crosses to `200%` once (`pxl_btn_shine` in the reference, 1.4s with a
 * 100ms delay). The animation is not `forwards`, so the band returns to its
 * parked spot and the next hover runs it again — and because it is declared on
 * `:hover` rather than on the element, a pointer that never arrives costs
 * nothing.
 */
.uls-btn::before {
	content: "";
	position: absolute;
	top: 0;
	left: -200%;
	width: 200%;
	height: 100%;
	background-image: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.35), transparent);
	transform: skewX(-20deg);
	pointer-events: none;
}

.uls-btn:hover::before {
	animation: uls-btn-shine 1.4s ease 0.1s;
}

@keyframes uls-btn-shine {
	100% {
		left: 200%;
	}
}

/*
 * The arrow swap. Two mask layers of the same arrow sit in one 16px window: one
 * on the box, one parked 22px to the left of it (outside the box, so invisible —
 * masks do not paint past their element). On hover the two trade places over
 * 250ms: the arrow the visitor can see slides out to the right while its copy
 * comes in from the left. The reference does exactly this with two stacked SVGs.
 */
.uls-btn::after {
	content: "";
	flex: none;
	width: 16px;
	height: 16px;
	background-color: currentColor;
	-webkit-mask-image: var(--uls-btn-arrow), var(--uls-btn-arrow);
	mask-image: var(--uls-btn-arrow), var(--uls-btn-arrow);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-size: 16px 16px;
	mask-size: 16px 16px;
	-webkit-mask-position: 0 center, -22px center;
	mask-position: 0 center, -22px center;
	transition: -webkit-mask-position 0.25s ease-out, mask-position 0.25s ease-out;
}

.uls-btn:hover::after {
	-webkit-mask-position: 22px center, 0 center;
	mask-position: 22px center, 0 center;
}

/*
 * The label rolls up. This is the reference build's third button effect — its
 * `.link-effect` window holds two stacked copies of the label and
 * `.theme-btn:hover .effect-1 { top: -100% }` lifts both by exactly one label
 * height, so the copy the visitor can see leaves through the top of the window
 * and its twin takes its place (0.3s). The markup is built by main.js, which
 * keeps the label written down once in PHP and marks the twin `aria-hidden`.
 *
 * The three numbers here are one decision, not three. The window **is** the
 * line box: `height: 1.35em` with `line-height: 1.35em`, and the copies are
 * `height: 100%` of it, so `top: -100%` lands a copy exactly where the other
 * one was — the same arithmetic as the reference's `height: 26px` window.
 *
 * 1.35em rather than 1em is the part that is easy to get wrong: a 15px font's
 * glyph box (ascent + descent, ~1.2em) is *taller* than `line-height: 1`, so a
 * one-em window would shave the ascenders and cut the descenders of every
 * Cyrillic label — and, worse, the twin parked below would have its own
 * ascenders poking up through the clip line while the button sat still. A line
 * box with ~0.15em of slack on each side holds both copies whole: the outgoing
 * one leaves the clip completely, the incoming one is completely outside it
 * until the hover starts.
 *
 * The window is put back to the height it had before this effect — the button
 * measures 48px either way — with `margin-block`, not with padding: padding
 * would extend the clip past the line box and let the twin's ascenders show at
 * rest. `box-sizing: content-box` keeps `1.35em` meaning the content height,
 * since the theme sets border-box globally.
 */
.uls-btn__label {
	position: relative;
	display: block;
	overflow: hidden;
	box-sizing: content-box;
	height: 1.35em;
	line-height: 1.35em;
	margin-block: -0.175em;
}

.uls-btn__label-in {
	display: block;
	height: 100%;
	position: relative;
	top: 0;
	transition: top 0.3s ease;
}

.uls-btn:hover .uls-btn__label-in {
	top: -100%;
}

.uls-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	align-items: center;
}

.uls-actions--center {
	justify-content: center;
}

/* =========================================================================
   05. CARDS / PILLS
   ========================================================================= */
.uls-card {
	position: relative;
	background: var(--uls-surface);
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	overflow: hidden;
}

.uls-card::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 46%;
	background: radial-gradient(60% 100% at 50% 100%, rgba(43, 75, 242, 0.16), transparent 70%);
	pointer-events: none;
}

.uls-pill {
	display: inline-flex;
	align-items: center;
	padding: 9px 18px;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-pill);
	font-size: var(--uls-fs-xs);
	color: #e7ebff;
	background: rgba(255, 255, 255, 0.02);
	transition: border-color 0.2s ease, background 0.2s ease;
}

.uls-pill:hover {
	border-color: var(--uls-border-strong);
	background: rgba(255, 255, 255, 0.05);
}

/*
 * A pill that is a link (the «Услуги» block): every service in a category opens
 * its own page, so the whole pill is the target and the hover state has to say
 * so. The plain tag pill is not interactive and stays quiet.
 */
.uls-pill--link {
	text-decoration: none;
}

.uls-pill--link:hover,
.uls-pill--link:focus-visible {
	color: #fff;
	border-color: var(--uls-border-strong);
	background: rgba(43, 75, 242, 0.18);
}

/* =========================================================================
   06. HEADER
   ========================================================================= */
.uls-header {
	position: sticky;
	top: 0;
	z-index: 60;
	background: rgba(4, 8, 28, 0.72);
	border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

/*
 * The blur lives on a pseudo element on purpose: `backdrop-filter` on the
 * header itself would turn it into a containing block for the fixed mobile
 * navigation, which then escapes the viewport and adds horizontal scroll.
 */
@supports ( ( backdrop-filter: blur(1px) ) or ( -webkit-backdrop-filter: blur(1px) ) ) {
	.uls-header {
		background: transparent;
		border-bottom: 0;
	}

	.uls-header::before {
		content: "";
		position: absolute;
		inset: 0;
		background: rgba(4, 8, 28, 0.72);
		backdrop-filter: blur(16px);
		-webkit-backdrop-filter: blur(16px);
		border-bottom: 1px solid rgba(255, 255, 255, 0.05);
		z-index: 0;
	}
}

.uls-header__inner {
	position: relative;
	z-index: 1;
}

.uls-header__inner {
	display: flex;
	align-items: center;
	gap: clamp(28px, 3vw, 56px);
	min-height: 84px;
}

.uls-logo {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	flex: none;
}

.uls-logo img,
.uls-logo svg {
	height: 34px;
	width: auto;
}

/* The design's header mark is 98x53 px at 1.25 DPR = 42 CSS px tall. */
.uls-header .uls-logo img {
	height: 42px;
}

/*
 * The bar is a single row: mark, menu, language switcher. Now that the ticker
 * and the row of action buttons are gone the menu has the free width to sit in,
 * so `margin-inline: auto` opens the distance between the mark and the first
 * item by itself; the flex gap above is only the floor that distance never
 * falls under when the viewport gets tight.
 */
.uls-nav {
	margin-inline: auto;
}

.uls-logo:not([href]),
.uls-nav a:not([href]) {
	cursor: default;
}

/*
 * The drawer's own way out. Above 1024px the menu is a row in the bar and the
 * button means nothing, so it is hidden.
 */
.uls-nav__close {
	display: none;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	color: #cfd5ea;
	background: rgba(255, 255, 255, 0.04);
	border: 1px solid var(--uls-border);
	border-radius: 12px;
	cursor: pointer;
	transition: color 0.2s ease, border-color 0.2s ease;
}

.uls-nav__close:hover,
.uls-nav__close:focus-visible {
	color: #fff;
	border-color: rgba(255, 255, 255, 0.28);
}

.uls-nav ul {
	display: flex;
	align-items: center;
	gap: clamp(12px, 1.5vw, 26px);
}

.uls-nav a {
	font-size: var(--uls-fs-sm);
	color: #cfd5ea;
	position: relative;
	padding-block: 6px;
	white-space: nowrap;
	transition: color 0.2s ease;
}

/*
 * The rule under a menu item belongs to the pointer alone: it is parked off the
 * far end of the link and slides in on hover, so a menu never shows a standing
 * underline. The current page is told apart by weight and colour instead.
 */
.uls-nav a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 100%;
	bottom: 0;
	height: 1px;
	background: var(--uls-blue-text);
	transition: right 0.25s ease;
}

.uls-nav a:hover {
	color: #fff;
}

/*
 * Current page, plus the parents and ancestors of the current page: white and
 * bold. The heavier weight is what carries the state now that the underline
 * appears on hover only.
 */
.uls-nav .current-menu-item > a,
.uls-nav .current_page_item > a,
.uls-nav .current-menu-ancestor > a,
.uls-nav .current-menu-parent > a {
	color: #fff;
	font-weight: 700;
}

.uls-nav a:hover::after {
	right: 0;
}

/*
 * The design's action buttons are gone from the bar; the slot is left holding
 * the burger that opens the drawer below 1024 px.
 */
.uls-header__actions {
	display: flex;
	align-items: center;
	flex: none;
}

.uls-burger {
	display: none;
	width: 44px;
	height: 44px;
	border: 1px solid var(--uls-border);
	border-radius: 12px;
	padding: 11px;
	flex: none;
}

.uls-burger__bar {
	display: block;
	height: 2px;
	width: 100%;
	background: #fff;
	border-radius: 2px;
	transition: transform 0.25s ease, opacity 0.25s ease;
}

.uls-burger__bar + .uls-burger__bar {
	margin-top: 5px;
}

.uls-menu-open .uls-burger__bar:nth-of-type(1) { transform: translateY(7px) rotate(45deg); }
.uls-menu-open .uls-burger__bar:nth-of-type(2) { opacity: 0; }
.uls-menu-open .uls-burger__bar:nth-of-type(3) { transform: translateY(-7px) rotate(-45deg); }

/* =========================================================================
   07. HERO
   ========================================================================= */
/*
 * Front page composition (one-to-one with Figma): the photo bleeds to the very
 * top of the document and the header floats on top of it. From 100px of scroll
 * on, the header pins with a blurred bar (`PIN_AT` in main.js) — the menu then
 * travels down the page with the reader instead of scrolling out of reach.
 */
.uls-front .uls-header {
	position: absolute;
	inset: 0 0 auto 0;
	z-index: 61;
	background: transparent;
	border-bottom: 0;
}

.uls-front .uls-header::before {
	display: none;
}

.uls-front .uls-header.is-pinned {
	position: fixed;
	inset: 0 0 auto 0;
	transform: translateY(-100%);
	transition: transform 0.28s ease;
	will-change: transform;
}

/*
 * `is-shown` is the second half of the slide: the bar lands in the fixed slot
 * first and only then travels back to its place, so the swap from the hero's
 * static bar to the pinned one is a slide instead of a jump. Un-pinning drops
 * both classes at once, which is why the transform above is declared on the
 * pinned state alone: on the way back the bar returns to the document in a
 * single frame.
 */
.uls-front .uls-header.is-pinned.is-shown {
	transform: translateY(0);
}

.uls-front .uls-header.is-pinned::before {
	display: block;
}

.uls-hero {
	position: relative;
	min-height: max(560px, min(96vh, 60vw));
	display: flex;
	align-items: stretch;
	isolation: isolate;
	overflow: hidden;
}

.uls-hero__media {
	position: absolute;
	inset: 0;
	z-index: -2;
}

.uls-hero__media img,
.uls-hero__media svg,
.uls-hero__video {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The background video keeps its poster frame visible from the first paint, so
 * there is nothing to fade in and no layout shift. Playback itself is started by
 * main.js only when reduced-motion, Save-Data and slow connections allow it.
 *
 * `pointer-events: none` is not needed (the clip is absolutely positioned behind
 * the overlay), but the video must never steal clicks from the hero buttons.
 */
.uls-hero__video {
	display: block;
	pointer-events: none;
}

/*
 * Three layers, not one flat sheet: the frame is a bright warehouse shot, so a
 * uniform dim had to be heavy enough to carry white type — which is why the
 * video read as a dark smear. The copy instead gets its own pool of shade
 * (layer 2), and everything outside it is much lighter, so the footage stays
 * visible at the edges while the headline keeps the same contrast it had.
 *
 * Effective dimming: ~0.94 behind the header, ~0.76 directly under the
 * headline and the lede, ~0.47 down the sides, ~0.90 under the metrics row.
 */
.uls-hero__overlay {
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		linear-gradient(180deg, rgba(4, 8, 28, 0.88) 0%, rgba(5, 10, 32, 0.42) 22%, rgba(5, 10, 32, 0.28) 45%, rgba(4, 8, 28, 0.55) 70%, rgba(4, 8, 28, 0.86) 100%),
		radial-gradient(64% 42% at 50% 40%, rgba(3, 7, 24, 0.52) 0%, rgba(3, 7, 24, 0.34) 45%, rgba(3, 7, 24, 0) 80%),
		linear-gradient(180deg, rgba(12, 24, 72, 0.16), rgba(12, 24, 72, 0.16)),
		radial-gradient(80% 60% at 50% 38%, rgba(43, 75, 242, 0.14), transparent 70%);
}

/*
 * On a phone the copy stacks: the lede falls to roughly two thirds of the
 * screen, well below the 40% line the pool is centred on, so the pool grows and
 * slips down to stay under it. Same breakpoint as the mobile video source.
 */
@media (max-width: 860px) {
	.uls-hero__overlay {
		background:
			linear-gradient(180deg, rgba(4, 8, 28, 0.87) 0%, rgba(5, 10, 32, 0.46) 16%, rgba(5, 10, 32, 0.32) 32%, rgba(4, 8, 28, 0.6) 74%, rgba(4, 8, 28, 0.9) 100%),
			radial-gradient(96% 52% at 50% 40%, rgba(3, 7, 24, 0.5) 0%, rgba(3, 7, 24, 0.3) 55%, rgba(3, 7, 24, 0) 84%),
			linear-gradient(180deg, rgba(12, 24, 72, 0.16), rgba(12, 24, 72, 0.16)),
			radial-gradient(110% 62% at 50% 40%, rgba(43, 75, 242, 0.12), transparent 72%);
	}
}

/*
 * The hero is a column: headline and lede sit at the top of the free space and
 * the metrics row is pushed to the bottom edge, so the two auto margins split
 * whatever room the screen has between them — the same distribution the design
 * uses. When the copy is taller than the screen the auto margins collapse to
 * zero and the block simply grows (the padding keeps the header clearance).
 */
.uls-hero__inner {
	width: 100%;
	display: flex;
	flex-direction: column;
	padding-block: clamp(120px, 19vh, 250px) clamp(56px, 6.4vw, 92px);
}

/*
 * Headline slider (Figma Frame 185). The slides are stacked in one grid cell,
 * so the block keeps the height of its tallest headline and the block never
 * jumps when the copy rotates. Every slide but the active one is transparent
 * *and* invisible: visibility is what takes the inactive copy out of the
 * accessibility tree, and its delayed transition keeps the text on screen for
 * the whole cross-fade. Without JavaScript the markup arrives with the first
 * slide already active, so the block still renders one static headline.
 */
.uls-hero__title {
	/*
	 * Wide enough for the longest typed line at the display size of the type
	 * scale; `balance` keeps a line that still wraps from leaving one word alone.
	 */
	max-width: 1040px;
	text-wrap: balance;
	margin: auto auto clamp(20px, 2.6vh, 34px);
	text-align: center;
	font-size: var(--uls-fs-display);
	/*
	 * A shadow rather than more dimming: the pool above is the size of the
	 * copy, and a lit frame (a lamp, a white container) can still sit inside
	 * it. The shadow costs the footage nothing.
	 */
	text-shadow: 0 1px 3px rgba(3, 6, 20, 0.55), 0 10px 34px rgba(3, 6, 20, 0.6);
}

.uls-hero__slides {
	display: grid;
}

.uls-hero__slide {
	grid-area: 1 / 1;
	opacity: 0;
	visibility: hidden;
	transform: translate3d(0, 16px, 0);
	transition: opacity 0.7s ease, transform 0.7s ease, visibility 0s linear 0.7s;
}

.uls-hero__slide.is-active {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition: opacity 0.7s ease, transform 0.7s ease, visibility 0s;
}

.uls-hero__slide.is-leaving {
	opacity: 0;
	transform: translate3d(0, -16px, 0);
}

.uls-hero__lead {
	max-width: 820px;
	margin: 0 auto clamp(28px, 4vh, 56px);
	text-align: center;
	/* Lighter than the muted grey used on flat surfaces: this paragraph sits on
	 * moving footage, where #9aa3bd loses too much of its contrast. */
	color: #ced6e8;
	font-size: var(--uls-fs-lead);
	line-height: 1.55;
	text-shadow: 0 1px 2px rgba(3, 6, 20, 0.6), 0 6px 22px rgba(3, 6, 20, 0.55);
}

@media (prefers-reduced-motion: reduce) {
	.uls-hero__slide,
	.uls-hero__slide.is-active {
		transition: none;
		transform: none;
	}
}

/*
 * Stats.
 *
 * The row carries as many tracks as it has figures (up to six, then it wraps on
 * four), and the template states that count in a `uls-stats--cols-N` class
 * because CSS cannot count its own children. It is a class rather than a
 * custom property on purpose: `repeat(var(--count), …)` is not a valid track
 * list, so a variable there would drop the declaration and stack every card in
 * one column. `1fr` plus a fixed `gap` is what makes the spacing even: every
 * card is the same width and every space between two cards is the same 16px,
 * whether there are three figures in the row or six.
 */
.uls-stats {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 16px;
	margin-top: auto;
}

.uls-stats--cols-1 {
	grid-template-columns: minmax(0, 1fr);
}

.uls-stats--cols-2 {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.uls-stats--cols-3 {
	grid-template-columns: repeat(3, minmax(0, 1fr));
}

.uls-stats--cols-5 {
	grid-template-columns: repeat(5, minmax(0, 1fr));
}

.uls-stats--cols-6 {
	grid-template-columns: repeat(6, minmax(0, 1fr));
}

/*
 * The figure and its caption sit in the middle of the card. Left-aligned they
 * read as five lists that happen to be side by side — the columns have different
 * widths after the wrap and a card holding "36" looked half empty — while a
 * centred card reads as one figure. The row itself is a flex line, so the icon
 * and the number are centred together as a unit rather than the icon being
 * pushed to an edge.
 */
/*
 * The card is the design's own: a rounded panel of deep navy glass over the
 * hero photograph, a round badge holding the icon at the top, the figure under
 * it and the caption under that. Everything is centred, and the three parts
 * are spaced by the flex `gap` rather than by margins, so a card with a long
 * caption grows as a block instead of pushing its figure off centre.
 *
 * The badge is the one bright element: an inner glow under the icon, a hairline
 * ring, and a shadow that lifts it off the panel. It is deliberately a little
 * larger than the line height of the figure below, which is what gives the row
 * its rhythm at five cards across.
 */
.uls-stat {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: flex-start;
	gap: 12px;
	text-align: center;
	padding: 24px 18px 22px;
	border: 1px solid rgba(150, 178, 255, 0.22);
	border-radius: 18px;
	background: linear-gradient(
		180deg,
		rgba(48, 72, 132, 0.52) 0%,
		rgba(17, 28, 60, 0.74) 60%,
		rgba(9, 15, 36, 0.82) 100%
	);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09), 0 20px 42px -30px rgba(2, 8, 30, 0.95);
	overflow: hidden;
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

.uls-stat__icon {
	position: relative;
	z-index: 1;
	display: grid;
	place-items: center;
	width: 64px;
	height: 64px;
	margin-bottom: 2px;
	border: 1px solid rgba(160, 190, 255, 0.34);
	border-radius: 50%;
	background: radial-gradient(circle at 50% 30%, rgba(92, 132, 214, 0.5), rgba(12, 22, 48, 0.78) 72%);
	box-shadow: inset 0 0 20px rgba(96, 146, 255, 0.26), 0 12px 24px -18px rgba(0, 0, 0, 0.9);
	color: #e9f0ff;
	transition: color 0.35s ease, background 0.35s ease, border-color 0.35s ease;
}

.uls-stat__icon i {
	font-size: 24px;
	line-height: 1;
}

.uls-stat__icon svg {
	width: 27px;
	height: 27px;
}

.uls-stat__value {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	font-family: var(--uls-font-display);
	font-size: var(--uls-fs-h3);
	font-weight: var(--uls-fw-heading);
	letter-spacing: -0.02em;
	font-variant-numeric: tabular-nums; /* the count-up must not jitter in width */
	line-height: 1.15;
	text-wrap: balance;
}

.uls-stat__value svg {
	width: 26px;
	height: 26px;
	flex: none;
	opacity: 0.95;
}

.uls-stat__value sup {
	font-size: 0.55em;
	top: -0.6em;
	position: relative;
	margin-left: 0.15em;
}

/*
 * The figure's caption wraps instead of running on one line. Held to `nowrap`
 * the longest ones ("Пропускная способность Ж/Д терминалов") ran past the card's
 * right edge and were cut off by its `overflow: hidden` — at 1440px already,
 * not just on the phone. Two lines lose nothing; the cards in a row are grid
 * items, so they simply grow together.
 */
.uls-stat__label {
	margin: 0;
	color: var(--uls-muted);
	font-size: var(--uls-fs-xs);
	line-height: 1.45;
	text-wrap: pretty;
}

/* =========================================================================
   08. SERVICES (number rows)
   ========================================================================= */
.uls-services {
	border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.uls-service {
	display: grid;
	grid-template-columns: 90px minmax(240px, 1fr) minmax(0, 1.15fr);
	gap: 28px;
	align-items: start;
	padding-block: 34px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

.uls-service__index {
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-sm);
	font-weight: 600;
	padding-top: 6px;
}

.uls-service__title {
	font-size: var(--uls-fs-h4);
	font-weight: var(--uls-fw-heading);
	letter-spacing: -0.01em;
}

.uls-service__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	justify-content: flex-start;
}

/*
 * The two ways out of a service page (`single-services.php`): back to the list
 * and on to the contact form. Kept on one line, wrapping on narrow screens.
 */
.uls-service-back {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin: 40px 0 80px;
}

/* =========================================================================
   09. PROCESS TIMELINE (sticky rail + scroll-driven panels)
   ========================================================================= */
.uls-process {
	display: grid;
	grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
	gap: clamp(32px, 5vw, 80px);
	align-items: start;
}

/*
 * The rail pins itself for the whole read of the four chapters, so the chapter
 * list never leaves the screen while the panels scroll past it.
 *
 * `position: sticky` only travels inside the box that contains it, and a grid
 * item with `align-items: start` is exactly as tall as its own content — pinned
 * there it would already sit at the end of its travel and never move. The
 * wrapper therefore stretches to the height of the panel track instead, and the
 * rail pins inside that.
 */
.uls-process__side {
	align-self: stretch;
}

.uls-steps {
	position: sticky;
	top: 110px; /* the pinned header is 84px tall; keep the same value in main.js */
	padding-left: 4px;
}

/*
 * A sticky rail taller than the room left under the header would trap its last
 * line above the fold with no way to scroll it back into view, so on a very
 * short viewport the rail simply scrolls with the page instead.
 */
@media (max-height: 560px) {
	.uls-steps {
		position: static;
	}
}

/*
 * Each chapter is now one line: the counter that used to sit above the name
 * was dropped from the design, so the name alone carries the row and gets the
 * room the number held — which is also why it is set larger than before. The
 * dot keeps its column and is nudged down to sit on the name's centre line
 * (`align-items: start` would pin it to the line's cap instead).
 */
.uls-step {
	position: relative;
	display: grid;
	grid-template-columns: 30px 1fr;
	gap: 16px;
	align-items: start;
	padding-block: 18px;
	cursor: pointer;
}

.uls-step:hover .uls-step__title {
	color: #fff;
}

/*
 * The rule runs dot to dot: from under this chapter's dot (18px of padding +
 * the dot's 6px nudge + the 13px dot) down past the row's bottom edge into the
 * next dot.
 */
.uls-step::before {
	content: "";
	position: absolute;
	left: 6px;
	top: 36px;
	bottom: -25px;
	width: 1px;
	background: rgba(255, 255, 255, 0.14);
}

.uls-step:last-child::before {
	display: none;
}

.uls-step__dot {
	width: 13px;
	height: 13px;
	border-radius: 50%;
	border: 1px solid rgba(255, 255, 255, 0.4);
	margin-top: 6px;
	position: relative;
	z-index: 1;
	transition: background 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

.uls-step.is-active .uls-step__dot {
	background: var(--uls-accent);
	border-color: var(--uls-accent);
	box-shadow: 0 0 0 5px rgba(232, 64, 42, 0.18);
}

/*
 * The weight stays put between states on purpose: a scroll-driven bolder
 * chapter would re-measure and nudge the rail every time the highlight moved,
 * so only the colour changes. The size carries the block on its own now that
 * the counter is gone.
 */
.uls-step__title {
	font-family: var(--uls-font-display);
	font-size: var(--uls-fs-h4);
	font-weight: var(--uls-fw-heading);
	line-height: 1.25;
	letter-spacing: -0.015em;
	color: #c3cadf;
	transition: color 0.25s ease;
}

.uls-step.is-active .uls-step__title {
	color: #fff;
}

/*
 * The chapter cards are dealt like a deck: every card pins itself under the
 * header, so the photo being read holds still until the next card scrolls up
 * and covers it — the move the reference site makes with GSAP's `pin: true`,
 * done here with plain CSS. The chapter list on the left keeps the click and
 * the highlight, the deck on the right carries the motion.
 *
 * That is also why the track is block flow and not a grid: a sticky item only
 * travels inside its own grid area, so inside a grid each card would stop dead
 * at the end of its own row and never stack. The space between cards therefore
 * lives on the card itself (`margin-block-end`) and doubles as the scroll
 * distance a card stays pinned — roughly one card height per chapter.
 *
 * `--uls-i` is the card's index, written inline by the template, and lifts each
 * pinned card 14px further down so the deck shows the top edge of the card it
 * has just covered. `position: relative` is what main.js measures against.
 *
 * The card's surface is opaque, and it has to be: `--uls-surface` is a 2.8%
 * white wash, so a covering card was actually a window — the title and the body
 * copy of the card underneath showed straight through it, exactly where the
 * arriving card had its own text, and the two chapters read as one mess. A wash
 * over the flat page background (`--uls-bg-2`) keeps the same glassy tone while
 * the composite stays solid.
 */
.uls-process__panels {
	position: relative;
	display: block;
}

.uls-panel {
	position: sticky;
	top: calc(110px + min(var(--uls-i, 0) * 14px, 56px)); /* keep in sync with main.js */
	background:
		linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.02)),
		var(--uls-bg-2);
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-lg);
	padding: 18px 18px 26px;
	margin-block-end: clamp(24px, 3vw, 44px);
	scroll-margin-top: 110px; /* matches the rail's sticky top above */
	transition: border-color 0.3s ease;
	transform-origin: 50% 0;
}

.uls-panel:last-child {
	margin-block-end: 0;
}

/*
 * Same very short viewport as the rail above: a 500px card pinned under the
 * header would fill the whole screen and hide the cards queued behind it, so
 * below 560px of height the deck lies down and the cards follow each other.
 * This has to sit *after* the rule above — both selectors have the same weight,
 * so the later one is the one that wins.
 */
@media (max-height: 560px) {
	.uls-panel {
		position: static;
	}
}

/*
 * The card that is on top of the deck. The motion itself (the recede of a card
 * as the next one covers it) is written inline by main.js, one frame at a time;
 * this is only the state outline.
 */
.uls-panel.is-active {
	border-color: rgba(141, 166, 255, 0.34);
}

/* Shared by the blocks that swap their own content in (terminals, panels). */
@keyframes uls-fade {
	from { opacity: 0; transform: translateY(10px); }
	to { opacity: 1; transform: none; }
}

.uls-panel__media {
	border-radius: 16px;
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background: linear-gradient(140deg, #101a45, #060b22);
	margin-bottom: 22px;
}

.uls-panel__media img,
.uls-panel__media svg {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.uls-panel__title {
	font-size: var(--uls-fs-h5);
	line-height: 1.25;
	margin-bottom: 10px;
	padding-inline: 6px;
}

.uls-panel__text {
	color: var(--uls-muted);
	font-size: var(--uls-fs-body);
	line-height: 1.65; /* 15.5px/1.55 read as a slab on the dark card */
	padding-inline: 6px;
	text-wrap: pretty;
}

/* =========================================================================
   10. WMS GRID
   ========================================================================= */
/*
 * The WMS block is a grid of photo cards with a dialog of its own, and both the
 * cards and that dialog are styled as one piece: see `assets/css/wms-cards.css`,
 * which `uls_wms_assets()` enqueues on the pages that print the block.
 */

/* =========================================================================
   11. COMPARE (model)
   ========================================================================= */
/*
 * Both columns carry the same list, one with fewer rows than the other, so the
 * cards are stretched to a shared height and every row grows by the same
 * amount. That is what keeps the two lists reading as one table: the rows line
 * up only as long as the cards match, and the shorter card spreads its rows
 * instead of ending early.
 */
.uls-compare {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 22px;
	align-items: stretch;
}

.uls-compare__card {
	padding: clamp(24px, 2.6vw, 38px);
	display: flex;
	flex-direction: column;
}

.uls-compare__title {
	font-size: var(--uls-fs-h4);
	margin-bottom: 26px;
}

.uls-compare__card--pro {
	border-color: rgba(111, 141, 255, 0.4);
	box-shadow: 0 30px 90px -50px rgba(43, 75, 242, 0.9);
}

.uls-compare__row {
	display: grid;
	gap: 6px;
	padding-block: 18px;
	flex: 1 1 auto;
	border-top: 1px dashed rgba(255, 255, 255, 0.12);
}

.uls-compare__row:first-of-type {
	border-top: 0;
	padding-top: 0;
}

.uls-compare__label {
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-sm);
}

.uls-compare__value {
	font-size: var(--uls-fs-body);
	font-weight: 600;
	color: #eaeefc;
}

/* =========================================================================
   12. TERMINALS
   ========================================================================= */
.uls-terminals {
	display: grid;
	gap: 22px;
}

.uls-terminal {
	display: grid;
	grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
	gap: 0;
	align-items: stretch;
}

.uls-terminal--reverse .uls-terminal__media {
	order: 2;
}

/*
 * The photo sits *inside* the card: the design frames it with a few pixels of
 * breathing room on every side instead of letting it bleed to the card edge.
 * The gradient stays behind the image, so the inset reads as a frame and not
 * as a gap when the photo is still loading.
 */
.uls-terminal__media {
	min-height: 340px;
	padding: clamp(10px, 1.1vw, 16px);
	background: linear-gradient(150deg, #0d1740, #060b22);
}

.uls-terminal__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: calc(var(--uls-radius) - 6px);
}

.uls-terminal__body {
	padding: clamp(26px, 3vw, 46px);
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 16px;
}

.uls-terminal__eyebrow {
	font-size: var(--uls-fs-micro);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--uls-muted-2);
}

.uls-terminal__title {
	font-size: var(--uls-fs-h3);
}

.uls-terminal__location {
	color: var(--uls-muted);
	font-size: var(--uls-fs-sm);
}

.uls-terminal__text {
	color: #c3cae0;
	font-size: var(--uls-fs-body);
	max-width: 580px;
}

.uls-terminal__text + .uls-terminal__text {
	margin-top: 12px;
}

.uls-terminal .uls-btn {
	align-self: flex-start;
	margin-top: 8px;
}

/* =========================================================================
   12b. GEOGRAPHY
   ========================================================================= */
.uls-geo {
	display: grid;
	grid-template-columns: minmax(0, 517fr) minmax(0, 704fr);
	gap: clamp(24px, 3.6vw, 52px);
	align-items: start;
}

.uls-geo__map {
	position: relative;
	aspect-ratio: 436 / 309;
	border-radius: var(--uls-radius);
	overflow: hidden;
	isolation: isolate;
	background: linear-gradient(150deg, #0d1740, #060b22);
}

/* Still image: the no-JS / offline fallback painted behind the live map. */
.uls-geo__fallback {
	position: absolute;
	inset: 0;
	z-index: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.uls-geo__canvas {
	position: absolute;
	inset: 0;
	z-index: 1;
}

/* Leaflet, tuned to the dark theme. */
.uls-geo__map .leaflet-container {
	background: transparent;
	font: inherit;
}

.uls-geo__map .leaflet-tile-pane {
	/* The basemap is light; this turns it into the dark map of the design
	   without depending on a keyed dark style. */
	filter: invert(1) hue-rotate(180deg) brightness(0.92) saturate(0.7) contrast(1.05);
}

/* Scoped under .leaflet-container on purpose: Leaflet's own stylesheet is
   injected later and sets the same properties at the same specificity. */
.uls-geo__map .leaflet-container .leaflet-control-attribution {
	margin: 0;
	padding: 2px 8px;
	background: rgba(4, 8, 28, 0.72);
	border-radius: 10px 0 0 0;
	color: var(--uls-muted-2);
	font-size: 10px;
	line-height: 1.6;
}

.uls-geo__map .leaflet-container .leaflet-control-attribution a {
	color: var(--uls-muted);
}

.uls-geo__map .leaflet-bar a {
	background: rgba(4, 8, 28, 0.82);
	border-bottom-color: var(--uls-border);
	color: var(--uls-text);
}

.uls-geo__map .leaflet-bar a:hover,
.uls-geo__map .leaflet-bar a:focus {
	background: #0d1740;
}

.uls-geo__map .leaflet-popup-content-wrapper,
.uls-geo__map .leaflet-popup-tip {
	background: #0a1130;
	color: var(--uls-text);
}

.uls-geo__map .leaflet-popup-content-wrapper {
	border: 1px solid var(--uls-border);
	border-radius: 12px;
	box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.9);
}

.uls-geo__map .leaflet-popup-content {
	margin: 12px 14px;
	max-width: 240px;
	font-size: 13.5px;
	line-height: 1.45;
}

.uls-geo__map .leaflet-popup-content strong {
	display: block;
	margin-bottom: 4px;
	font-size: 15px;
}

/* Terminal pins. */
.uls-geo__map .uls-pin-wrap {
	width: 0;
	height: 0;
	background: none;
	border: 0;
}

.uls-geo__pin {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	transform: translate(-50%, -50%);
	padding: 4px 11px 4px 9px;
	background: rgba(10, 17, 48, 0.92);
	border: 1px solid var(--uls-border-strong);
	border-radius: 999px;
	color: #fff;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.06em;
	white-space: nowrap;
	box-shadow: 0 10px 24px -12px rgba(0, 0, 0, 0.95);
}

.uls-geo__pin::before {
	content: "";
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--uls-blue-text);
	box-shadow: 0 0 0 3px rgba(111, 141, 255, 0.22);
}

.uls-geo__map.is-live {
	box-shadow: inset 0 0 0 1px var(--uls-border);
}

.uls-geo__list {
	display: flex;
	flex-direction: column;
}

.uls-geo__item + .uls-geo__item {
	margin-top: 16px;
	padding-top: 17px;
	border-top: 1px solid var(--uls-border);
}

.uls-geo__title {
	font-size: var(--uls-fs-h5);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--uls-text);
}

.uls-geo__text {
	margin-top: 16px;
	color: #c3cae0;
	font-size: var(--uls-fs-body);
	line-height: 1.4;
}

/* =========================================================================
   13. (calculator — removed; the number is kept so later references hold)
   ========================================================================= */

/* =========================================================================
   14. CTA
   ========================================================================= */
.uls-cta {
	text-align: center;
	padding-block: clamp(56px, 7vw, 110px);
}

.uls-cta__title {
	font-size: var(--uls-fs-h2);
	max-width: 900px;
	margin-inline: auto;
	margin-bottom: 22px;
}

.uls-cta__text {
	color: var(--uls-muted);
	max-width: 640px;
	margin-inline: auto;
	margin-bottom: 34px;
	font-size: var(--uls-fs-lead);
}

/* =========================================================================
   15. CLIENTS MARQUEE
   ========================================================================= */
/*
 * The strip sits on the same width as the rest of the content band, so the row
 * of logos is centred on the page instead of bleeding off both edges.
 */
.uls-clients {
	width: 100%;
	max-width: var(--uls-container);
	margin-inline: auto;
	overflow: hidden;
	mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

/*
 * The track holds several identical groups and travels exactly one group per
 * loop, so the strip never ends on empty space: `--uls-marquee-shift` is one
 * group wide (set by `assets/js/main.js`, which also tops the track up with as
 * many copies as the band needs). The `-25%` fallback matches the four copies
 * the template renders for a visitor without JavaScript.
 */
@keyframes uls-marquee {
	from { transform: translateX(0); }
	to { transform: translateX(var(--uls-marquee-shift, -25%)); }
}

.uls-clients__track {
	display: flex;
	width: max-content;
	animation: uls-marquee var(--uls-marquee-duration, 34s) linear infinite;
}

.uls-clients__group {
	display: flex;
	align-items: center;
	gap: clamp(40px, 6vw, 96px);
	padding-inline: clamp(20px, 3vw, 48px);
}

.uls-client {
	font-size: clamp(26px, 3.2vw, 44px);
	font-weight: 800;
	letter-spacing: -0.02em;
	color: #aab6d6;
	opacity: 0.9;
	white-space: nowrap;
	flex: none;
}

.uls-client--script {
	font-style: italic;
	font-weight: 700;
	letter-spacing: -0.04em;
}

/*
 * A client slot can carry an uploaded logo instead of a name. The height is
 * capped where the marquee's wordmarks sit, so a logo file and a text fallback
 * can share the same row without the strip changing height.
 */
.uls-client--logo img {
	display: block;
	height: clamp(25px, 3vw, 44px);
	width: auto;
	max-width: 220px;
	object-fit: contain;
}

/*
 * A linked slot behaves like the link it is: the wordmark brightens on hover and
 * the pointer says it goes somewhere. Slots without a page (repeater rows) keep
 * the plain cursor, and so do the logo and the "Главная" item while the front
 * page is on screen.
 */
.uls-clients a.uls-client {
	color: #aab6d6;
	transition: color 0.2s ease, opacity 0.2s ease;
}

.uls-clients a.uls-client:hover,
.uls-clients a.uls-client:focus-visible {
	color: #fff;
	opacity: 1;
}

.uls-clients a.uls-client--logo:hover img,
.uls-clients a.uls-client--logo:focus-visible img {
	filter: brightness(1.25);
}

.uls-clients a.uls-client img {
	transition: filter 0.2s ease;
}

.uls-clients:hover .uls-clients__track {
	animation-play-state: paused;
}

/* ------------------------------------------------- single client page ---- */
.uls-client-hero__logo {
	margin: 22px 0 24px;
}

.uls-client-hero__logo img {
	display: block;
	height: clamp(38px, 5vw, 62px);
	width: auto;
	max-width: 260px;
	object-fit: contain;
}

.uls-client-hero__site {
	margin-top: 26px;
}

.uls-client-back {
	max-width: 820px;
	margin: 0 auto clamp(40px, 5vw, 64px);
}

.uls-client-back a {
	color: var(--uls-blue-text);
	font-weight: 600;
}

.uls-client-back a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* =========================================================================
   16. FOOTER
   ========================================================================= */
.uls-footer {
	margin-top: clamp(40px, 6vw, 90px);
	border-top: 1px dashed rgba(255, 255, 255, 0.14);
	background: linear-gradient(180deg, rgba(4, 8, 28, 0) 0%, rgba(3, 6, 22, 0.85) 100%);
	padding-block: clamp(40px, 5vw, 70px);
}

/*
 * Five tracks: the brand, the three link columns, and the social column on the
 * right ("ULS" over one row of icons, "HLC" over the next). The brand and the
 * social column carry text as wide as a logo or a circle, so they take the two
 * elastic tracks — the link columns between them share what is left evenly.
 */
.uls-footer__grid {
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) repeat(3, minmax(0, 1fr)) minmax(200px, 0.85fr);
	gap: clamp(24px, 3vw, 56px);
}

/*
 * The social column is a stack of brand rows, each a caption over its icons.
 * `align-content: start` keeps both rows at the top: the column is much shorter
 * than the address beside it and must not spread to match it.
 */
.uls-footer__social {
	display: grid;
	gap: 24px;
	align-content: start;
}

.uls-social-group {
	display: grid;
	gap: 10px;
}

/*
 * The caption is smaller than a column heading on purpose: it names two rows of
 * circles, not a section, and at the heading size it would compete with the
 * column titles beside it.
 */
.uls-social-group__title {
	display: block;
	font-size: var(--uls-fs-2xs);
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--uls-muted-2);
}

.uls-footer__brand p {
	margin-top: 20px;
	color: var(--uls-muted);
	font-size: var(--uls-fs-sm);
	max-width: 320px;
}

/* `h2` since the footer columns follow the page's own outline (h1 → h2), not a
   jump to h4; `h4` stays matched for markup printed by older templates. */
.uls-footer__title,
.uls-footer__col h4 {
	font-size: var(--uls-fs-micro);
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--uls-muted-2);
	margin-bottom: 18px;
}

.uls-footer__col ul {
	display: grid;
	gap: 12px;
}

.uls-footer__col a,
.uls-footer__col li {
	color: #dbe0f0;
	font-size: var(--uls-fs-sm);
}

.uls-footer__col a:hover {
	color: #fff;
	text-decoration: underline;
	text-underline-offset: 3px;
}

/*
 * Social row: round targets, one per network, laid out in a single line —
 * wrapping rather than scrolling when an editor adds more than a handful.
 *
 * 42px is the smallest box that still reads as a button with a thumb, and the
 * 10px gap keeps two of them from touching on a phone. The brand glyph is drawn
 * at 20px inside it so the circle stays a frame, not a filled logo.
 */
.uls-social {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.uls-social__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 42px;
	height: 42px;
	border: 1px solid rgba(255, 255, 255, 0.14);
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.04);
	color: #dbe0f0;
	transition: color 0.22s ease, background-color 0.22s ease, border-color 0.22s ease, transform 0.22s ease;
}

/*
 * The footer's link rule underlines on hover; a circle around an icon has no
 * text to underline, so it only lifts. `transform` is dropped for anyone who
 * asked the system for less motion.
 */
.uls-social__link:hover,
.uls-social__link:focus-visible {
	text-decoration: none;
	color: #fff;
	background: var(--uls-blue);
	border-color: var(--uls-blue);
	transform: translateY(-2px);
}

.uls-social__link img {
	width: 20px;
	height: 20px;
	object-fit: contain;
}

@media (prefers-reduced-motion: reduce) {
	.uls-social__link:hover,
	.uls-social__link:focus-visible {
		transform: none;
	}
}

/*
 * The copyright line sits in the middle of the footer, under the columns — the
 * legal menu (a site may add one) lands beside it instead of pushing the line
 * to the left edge.
 */
.uls-footer__bottom {
	margin-top: clamp(30px, 4vw, 56px);
	padding-top: 24px;
	border-top: 1px solid rgba(255, 255, 255, 0.07);
	display: flex;
	flex-wrap: wrap;
	gap: 12px 24px;
	justify-content: center;
	text-align: center;
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-xs);
}

/* =========================================================================
   17. INNER PAGES
   ========================================================================= */
.uls-page-hero {
	padding-block: clamp(48px, 6vw, 90px);
	border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

.uls-page-hero__title {
	font-size: var(--uls-fs-display);
	margin-bottom: 14px;
}

.uls-entry {
	max-width: 820px;
	margin-inline: auto;
	padding-block: clamp(36px, 5vw, 72px);
	color: #ccd3e6;
}

.uls-entry > * + * {
	margin-top: 22px;
}

.uls-entry h2,
.uls-entry h3 {
	color: #fff;
	margin-top: 38px;
}

.uls-entry a {
	color: var(--uls-blue-text);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.uls-entry img {
	border-radius: var(--uls-radius);
}

.uls-entry blockquote {
	margin: 0;
	padding: 20px 24px;
	border-left: 2px solid var(--uls-blue);
	background: var(--uls-surface);
	border-radius: 0 var(--uls-radius) var(--uls-radius) 0;
	color: #e3e8f7;
}

.uls-entry ul {
	list-style: disc;
	padding-left: 22px;
	display: grid;
	gap: 8px;
}

.uls-blog-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
	gap: 22px;
}

.uls-post-card {
	overflow: hidden;
	display: flex;
	flex-direction: column;
}

.uls-post-card__media {
	aspect-ratio: 16 / 10;
	background: linear-gradient(140deg, #101a45, #060b22);
}

.uls-post-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.uls-post-card__body {
	padding: 22px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.uls-post-card__meta {
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-micro);
}

.uls-post-card__title {
	font-size: var(--uls-fs-h5);
}

/* =========================================================================
   17b. SEARCH + 404
   ========================================================================= */
.uls-search {
	display: flex;
	gap: 12px;
	max-width: 520px;
	margin-inline: auto;
}

.uls-search__input {
	flex: 1 1 auto;
	min-width: 0;
	padding: 15px 20px;
	border-radius: var(--uls-radius-pill);
	border: 1px solid var(--uls-border);
	background: rgba(255, 255, 255, 0.03);
	color: #fff;
	font: inherit;
	font-size: var(--uls-fs-sm);
}

.uls-search__input::placeholder {
	color: var(--uls-muted-2);
}

.uls-search__input:focus {
	border-color: var(--uls-border-strong);
	outline: none;
}

.uls-404 {
	text-align: center;
	padding-block: clamp(56px, 8vw, 120px);
	max-width: 760px;
	margin-inline: auto;
}

.uls-404__code {
	font-size: clamp(90px, 16vw, 180px);
	font-weight: 800;
	line-height: 0.9;
	letter-spacing: -0.05em;
	margin: 0 0 12px;
	background: linear-gradient(180deg, #ffffff 0%, #2b4bf2 130%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

.uls-404__title {
	font-size: var(--uls-fs-h3);
	margin-bottom: 18px;
}

.uls-404__search {
	margin-top: 38px;
}

/* =========================================================================
   19. RESPONSIVE
   ========================================================================= *//*
 * The header type is set to the design sizes (15 / 42 px). With the ticker and
 * the action buttons gone the bar has room to spare, so on narrower desktops
 * only the gaps inside the menu tighten a little.
 */
@media (max-width: 1420px) {

	.uls-nav ul {
		gap: clamp(10px, 1.05vw, 22px);
	}

	.uls-header__inner {
		gap: clamp(24px, 2.4vw, 44px);
	}

}



@media (max-width: 1200px) {

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

@media (max-width: 1024px) {
	/*
	 * The drawer is a full-height panel over the page. Its height is stated
	 * instead of taken from `inset`, because a height is the one thing that
	 * survives an ancestor turning into a containing block (see below): with
	 * `inset: 0 0 0 auto` alone the panel would be as tall as that ancestor.
	 *
	 * `dvh` is the mobile answer — the viewport with the browser's own toolbars
	 * taken out — and the plain `vh` line above it is the fallback for a browser
	 * that does not know the unit yet.
	 */
	.uls-nav {
		position: fixed;
		inset: 0 0 0 auto;
		height: 100vh;
		height: 100dvh;
		width: min(360px, 86vw);
		padding: 100px 28px 40px;
		background: #060b22;
		border-left: 1px solid var(--uls-border);
		opacity: 0;
		visibility: hidden;
		transition: opacity 0.25s ease, visibility 0.25s ease;
		z-index: 70;
		overflow-y: auto;
		box-shadow: -30px 0 70px -30px rgba(0, 0, 0, 0.9);
	}

	.uls-menu-open .uls-nav {
		opacity: 1;
		visibility: visible;
	}

	/*
	 * Why the bar must not be transformed while the drawer is open.
	 *
	 * A transformed element becomes the containing block of the fixed elements
	 * inside it. The front page's bar is pinned with `translateY(-100%)` and
	 * dropped in with `translateY(0)` — a transform that is visually an identity
	 * but is still a transform, and it stays on the header for as long as the
	 * bar is pinned. The drawer then no longer measures against the viewport: it
	 * became 140px tall (the bar's height) and hid the menu behind
	 * `overflow-y: auto`, so only the first item was left on screen.
	 *
	 * Dropping the transform is free here: while the menu is open the bar sits
	 * in its resting slot (`translateY(0)`, i.e. where `none` puts it too), the
	 * page behind cannot scroll (`body.uls-menu-open`), and the way out of the
	 * drawer is its own close button. The blur lives on the bar's pseudo element
	 * for exactly the same reason (section 06).
	 *
	 * `will-change: transform` turns an element into a containing block just as
	 * the transform itself does, so it goes in the same breath. These two
	 * selectors repeat the pin's own classes on purpose: a plain
	 * `body.uls-menu-open .uls-header` (two classes) would lose to
	 * `.uls-front .uls-header.is-pinned.is-shown` (four) and change nothing.
	 * `uls-front` sits on the body as well (`body_class()`), hence the compound
	 * `body.uls-menu-open.uls-front` rather than a descendant step.
	 */
	body.uls-menu-open.uls-front .uls-header.is-pinned,
	body.uls-menu-open.uls-front .uls-header.is-pinned.is-shown {
		transform: none;
		will-change: auto;

		/* Both values are identities, so there is nothing to travel between:
		without this the browser still opens a transition and keeps it alive
		for as long as the drawer is open. */
		transition: none;
	}

	.uls-nav ul {
		flex-direction: column;
		align-items: flex-start;
		gap: 18px;
	}

	.uls-nav a {
		font-size: 19px;
	}

	/*
	 * The menu is a drawer below this width, so the bar carries only the mark,
	 * the language switcher and the burger. The mark keeps the left edge through
	 * its own auto margin and the trailing pair is packed against the right one;
	 * that holds whether or not a language switcher is rendered at all.
	 */
	.uls-header__inner {
		justify-content: flex-end;
	}

	.uls-header .uls-logo {
		margin-right: auto;
	}

	.uls-burger {
		display: block;
	}

	/*
	 * The drawer covers the bar (it is fixed and sits above it), so the burger’s
	 * X is out of reach while the menu is open: the close button is the way out.
	 */
	.uls-nav__close {
		display: inline-flex;
		position: absolute;
		top: 22px;
		right: 24px;
	}

	.uls-process,
	.uls-compare,
	.uls-terminal,
	.uls-geo {
		grid-template-columns: minmax(0, 1fr);
	}

	/*
	 * One column: the rail sits above the panels and there is nothing left to
	 * pin, so the sticky wrapper goes back to its natural height.
	 */
	.uls-process__side {
		align-self: auto;
	}

	.uls-steps {
		position: static;
	}

	/*
	 * One column: every card would pin at the same place and hide the ones under
	 * it, so the deck is off and the cards simply follow each other.
	 */
	.uls-panel {
		position: static;
	}

	.uls-terminal--reverse .uls-terminal__media {
		order: 0;
	}

	.uls-terminal__media {
		min-height: 260px;
	}

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

	.uls-service {
		grid-template-columns: 60px 1fr;
	}

	.uls-service__tags {
		grid-column: 2;
	}
}

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

	.uls-hero {
		min-height: auto;
	}

	.uls-search {
		flex-direction: column;
	}

	.uls-search__input,
	.uls-search .uls-btn {
		width: 100%;
	}
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}

/* =========================================================================
   18. TILLAR (POLYLANG)
   ========================================================================= */
.uls-header__lang {
	display: flex;
	align-items: center;
}

.uls-language {
	display: flex;
	align-items: center;
	gap: 2px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.uls-language__item {
	font-size: var(--uls-fs-micro);
	font-weight: 600;
	letter-spacing: 0.05em;
	line-height: 1;
}

.uls-language__item > a,
.uls-language__item > span {
	display: inline-block;
	padding: 7px 9px;
	border-radius: 8px;
	color: var(--uls-muted);
	text-decoration: none;
	transition: color 0.2s ease, background-color 0.2s ease;
}

.uls-language__item > a:hover,
.uls-language__item > a:focus-visible {
	color: #fff;
	background: rgba(255, 255, 255, 0.07);
}

.uls-language__item.is-current > span {
	color: #fff;
	background: rgba(255, 255, 255, 0.1);
}

/* =========================================================================
   19. SAHIFA SHABLONLARI
   ========================================================================= */
.uls-page-hero .uls-lead {
	max-width: 720px;
	margin-top: 10px;
}

/* Hero with a background image picked in the page ACF fields. */
.uls-page-hero--media {
	background-image: linear-gradient(180deg, rgba(4, 8, 28, 0.6), rgba(4, 8, 28, 0.94)), var(--uls-page-hero-image);
	background-size: cover;
	background-position: center;
}

.uls-page--wide .uls-entry {
	max-width: 900px;
}

/* Content next to the "Sidebar" widget area. */
.uls-page-layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
	gap: clamp(28px, 4vw, 64px);
	align-items: start;
	padding-block: clamp(36px, 5vw, 72px);
}

.uls-page-layout__main .uls-entry {
	max-width: none;
	margin-inline: 0;
	padding-block: 0;
}

.uls-sidebar {
	display: flex;
	flex-direction: column;
	gap: 18px;
}

.uls-widget {
	display: flex;
	flex-direction: column;
	gap: 14px;
	padding: 24px;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: var(--uls-surface);
}

.uls-widget__title {
	margin: 0;
	color: #fff;
	font-size: var(--uls-fs-h5);
}

.uls-widget__list {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
	color: #c3cae0;
	font-size: var(--uls-fs-sm);
}

.uls-widget__list a {
	color: inherit;
	text-decoration: none;
}

.uls-widget__list a:hover {
	color: #fff;
}

/*
 * Widget areas hold block widgets on a modern WordPress install, which ship
 * their own markup instead of `before_widget`/`before_title`. Styling the
 * children keeps both kinds of widget looking like one card family.
 */
.uls-sidebar > * {
	padding: 24px;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: var(--uls-surface);
}

.uls-sidebar h2,
.uls-sidebar h3,
.uls-sidebar h4 {
	margin: 0 0 12px;
	color: #fff;
	font-size: var(--uls-fs-h5);
	line-height: 1.3;
}

.uls-sidebar ul,
.uls-sidebar ol {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
	color: #c3cae0;
	font-size: var(--uls-fs-sm);
}

.uls-sidebar a {
	color: inherit;
	text-decoration: none;
}

.uls-sidebar a:hover,
.uls-sidebar a:focus-visible {
	color: #fff;
}

.uls-sidebar input[type="search"],
.uls-sidebar input[type="text"],
.uls-sidebar input[type="email"],
.uls-sidebar input[type="url"],
.uls-sidebar textarea,
.uls-sidebar select {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--uls-border);
	border-radius: 10px;
	background: rgba(255, 255, 255, 0.04);
	color: #fff;
	font: inherit;
	font-size: var(--uls-fs-sm);
}

.uls-sidebar input::placeholder {
	color: var(--uls-muted-2);
}

.uls-sidebar .wp-block-search__inside-wrapper {
	display: flex;
	gap: 8px;
}

.uls-sidebar .wp-block-search__button,
.uls-sidebar input[type="submit"],
.uls-sidebar button[type="submit"] {
	width: auto;
	padding: 10px 18px;
	border: 1px solid transparent;
	border-radius: 10px;
	background: #fff;
	color: #0b1020;
	font: inherit;
	font-size: var(--uls-fs-sm);
	font-weight: 600;
	cursor: pointer;
}

.uls-sidebar .wp-block-search__button:hover {
	background: #eef1fb;
}

/* Contact page template. */
.uls-h3 {
	margin: 0;
	color: #fff;
	font-size: var(--uls-fs-h3);
}

.uls-contact-info {
	padding: clamp(24px, 3vw, 40px);
}

.uls-contact-info__list {
	display: grid;
	gap: 14px;
	margin: 18px 0 0;
	padding: 0;
	list-style: none;
}

.uls-contact-info__list li {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	color: #c3cae0;
	font-size: var(--uls-fs-body);
}

.uls-contact-info__list svg {
	flex: none;
	margin-top: 2px;
	color: var(--uls-blue-text);
}

.uls-contact-info__list a {
	color: inherit;
	text-decoration: none;
}

.uls-contact-info__list a:hover {
	color: #fff;
}

.uls-contact-map {
	margin-top: clamp(28px, 4vw, 56px);
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-lg);
	overflow: hidden;
}

.uls-page-links {
	margin-top: 26px;
	color: var(--uls-muted);
}

@media (max-width: 1024px) {
	.uls-page-layout {
		grid-template-columns: minmax(0, 1fr);
	}
}

@media (max-width: 560px) {
	.uls-language__item {
		font-size: 12px;
	}

	.uls-language__item > a,
	.uls-language__item > span {
		padding: 6px 7px;
	}
}

/* =========================================================================
   20. FORMA (BITRIX24)
   ========================================================================= */
.uls-form__lead {
	margin-top: 12px;
	color: var(--uls-muted);
	font-size: var(--uls-fs-body);
}

/*
 * The form is printed by Bitrix24 with its own colours, so the theme owns the
 * frame — width, radius, ring — and leaves the fields alone.
 *
 * The card is deliberately wider than the 760px text column: the CRM form asks
 * for nine fields, and half of a 1000px card is still a comfortable 450px field.
 */
.uls-form__card {
	max-width: 1000px;
	margin-inline: auto;
}

.uls-form__embed {
	min-height: 1px;
}

.uls-form__embed iframe,
.uls-form__embed .b24-form,
.uls-form__embed .b24-form-wrapper {
	width: 100%;
	max-width: 100%;
}

/* Bitrix ships a square, flat panel; bend it into the theme's language. */
.uls-form__embed .b24-form-wrapper {
	border-radius: var(--uls-radius);
}

/*
 * `.b24-form-border-bottom` is Bitrix's 5px white bar under the panel. It reads
 * as a hard edge against the navy background, and once the panel is rounded it
 * turns into an off-centre "smile" at the corners, so it becomes the same
 * hairline the ring above is drawn with.
 */
.uls-form__embed .b24-form-wrapper.b24-form-border-bottom {
	border-bottom: 1px solid var(--uls-border);
}

/*
 * The extra `.b24-form-shadow` class is on purpose: Bitrix's own rule of that
 * name is injected into <head> after this stylesheet, so a plain two-class
 * selector would only tie with it and lose. Three classes win outright.
 */
.uls-form__embed .b24-form-wrapper.b24-form-shadow {
	box-shadow:
		inset 0 0 0 1px var(--uls-border),
		0 40px 90px -50px rgba(3, 6, 26, 0.95);
}

/*
 * Two-column field grid.
 *
 * Bitrix wraps every field in an unnamed <div> inside <form>, so that wrapper
 * becomes the grid: `> div:first-child` is the field list, while the submit row
 * (`.b24-form-btn-container`) is its sibling and keeps its own layout.
 *
 * `Название компании` spans both columns, which leaves the four remaining
 * selects in two tidy pairs instead of a last row with a hole in it.
 */
.uls-form__embed .b24-form-content form > div:first-child {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: clamp(16px, 2.4vw, 28px);
}

.uls-form__embed .b24-form-content form > div:first-child > .b24-form-field {
	min-width: 0;
}

.uls-form__embed .b24-form-field-company-name {
	grid-column: 1 / -1;
}

/*
 * Submit: one column wide and centred, so it reads as the end of the form
 * instead of a 1000px bar, and wears the theme's pill button.
 */
.uls-form__embed .b24-form-btn-container {
	max-width: 470px;
	margin: 6px auto 0;
}

.uls-form__embed .b24-form-btn {
	border-radius: var(--uls-radius-pill);
	background: var(--uls-blue);
	color: #fff;
	font-weight: 700;
	box-shadow: 0 12px 30px -12px rgba(43, 75, 242, 0.9);
	transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.uls-form__embed .b24-form-btn:hover {
	background: var(--uls-blue-hover);
	color: #fff;
	transform: translateY(-1px);
}

.uls-form__note {
	margin-top: 18px;
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-micro);
	text-align: center;
}

/*
 * Below the tablet breakpoint the two-column grid collapses to one column: a
 * phone field squeezed next to a name field is where CRM forms start to look
 * broken. 640px is the same point the rest of the layout stops pairing things.
 */
@media (max-width: 640px) {
	.uls-form__embed .b24-form-content form > div:first-child {
		grid-template-columns: minmax(0, 1fr);
	}

	.uls-form__embed .b24-form-btn-container {
		max-width: none;
	}
}

/* =========================================================================
   20.1 KONTAKTLAR SAHIFASI
   ========================================================================= */
/*
 * The contact page is built from two blocks the rest of the site does not use:
 * a row of channel cards under the hero, and the lead form laid out beside its
 * own pitch instead of centred under it. Both are scoped to `.uls-contact-page`
 * so nothing here leaks onto the landing page, whose form keeps its centred
 * two-column grid.
 */

/*
 * Hero: centred, with the hairline removed — the cards below continue the same
 * panel, so a divider would cut the design in half. The diagonal band is the
 * light sweep the design runs across the header.
 */
.uls-contact-page .uls-page-hero {
	position: relative;
	overflow: hidden;
	text-align: center;
	border-bottom: 0;
}

.uls-contact-page .uls-page-hero::before {
	content: "";
	position: absolute;
	inset: -60% -8% auto -8%;
	height: 220%;
	background: linear-gradient(112deg, rgba(43, 75, 242, 0) 32%, rgba(120, 152, 255, 0.14) 50%, rgba(43, 75, 242, 0) 68%);
	pointer-events: none;
}

.uls-contact-page .uls-page-hero > * {
	position: relative;
	z-index: 1;
}

.uls-contact-page .uls-page-hero {
	padding-bottom: clamp(18px, 2.4vw, 32px);
}

.uls-contact-page .uls-page-hero .uls-lead {
	margin-inline: auto;
}

/*
 * The design shows no editorial copy on this page, and an empty article would
 * still pay its block padding — the cards would drift a screen away from the
 * headline. Copy added in the editor resumes the normal rhythm on its own.
 */
.uls-contact-page .uls-entry {
	padding-block: 0;
}

/* The hero already ends with its own padding, so the cards start right after. */
.uls-contact-page .uls-contacts {
	padding-top: 0;
}

/* ------------------------------------------------------- Kanal kartalari */
.uls-contacts__title {
	margin: 0 0 22px;
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-micro);
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	text-align: center;
}

.uls-contacts__chips {
	display: grid;
	justify-items: center;
	gap: 14px;
}

.uls-contacts__row {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 14px;
}

.uls-contacts__chip {
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 15px 26px 15px 16px;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: rgba(255, 255, 255, 0.03);
}

/* The address card holds two wrapped lines, so it is wider than the pair above. */
.uls-contacts__chip--wide {
	max-width: 820px;
}

.uls-contacts__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 38px;
	height: 38px;
	border-radius: var(--uls-radius-pill);
	background: var(--uls-blue);
	color: #fff;
	box-shadow: 0 12px 26px -14px rgba(43, 75, 242, 0.95);
}

.uls-contacts__lines {
	display: grid;
	gap: 3px;
	text-align: left;
}

.uls-contacts__line {
	color: var(--uls-muted);
	font-size: var(--uls-fs-sm);
	line-height: 1.35;
	text-decoration: none;
}

/* First line of a card is the primary channel, so it reads at full strength. */
.uls-contacts__line--strong {
	color: #fff;
	font-size: var(--uls-fs-body);
	font-weight: 600;
}

a.uls-contacts__line:hover {
	color: #fff;
}

/* ------------------------------------------------- Forma: matn va maydon */
.uls-contact-form__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
	gap: clamp(30px, 4vw, 72px);
	align-items: start;
}

/*
 * One notch down from the landing `.uls-h2`: the split column is about half a
 * container wide, and at 56px the headline the design sets over two lines wraps
 * into three.
 */
.uls-contact-form__intro .uls-h2 {
	margin-bottom: 16px;
	font-size: var(--uls-fs-h2);
}

/*
 * `.uls-form__lead` is centred on the landing page; here it opens the left
 * column, so it sits flush with the headline above it.
 */
.uls-contact-form__intro .uls-form__lead {
	max-width: 46ch;
	margin: 0;
	text-align: left;
}

.uls-contact-form__media {
	margin: clamp(24px, 3vw, 40px) 0 0;
}

.uls-contact-form__media img {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 10;
	object-fit: cover;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
}

/* The card fills its column instead of centring under a headline. */
.uls-contact-form__card {
	max-width: none;
	margin-inline: 0;
}

/*
 * In a half-width column a two-column field grid squeezes the four selects, so
 * every control spans the card and the submit button closes it edge to edge —
 * the arrangement the design shows. The landing form is untouched: these
 * selectors only match inside `.uls-contact-form`.
 */
.uls-contact-form .uls-form__embed .b24-form-field-list {
	grid-column: 1 / -1;
}

.uls-contact-form .uls-form__embed .b24-form-btn-container {
	max-width: none;
	margin: 6px 0 0;
}

@media (max-width: 1024px) {
	.uls-contact-form__grid {
		grid-template-columns: minmax(0, 1fr);
	}

	.uls-contact-form__intro .uls-form__lead {
		max-width: none;
	}
}

@media (max-width: 640px) {
	.uls-contacts__chip {
		align-items: flex-start;
		width: 100%;
	}
}

/* =========================================================================
   20.2 TERMINALLAR SAHIFASI
   ========================================================================= */
/*
 * The terminals page, following the design: its own hero, the terminal cards,
 * the infrastructure parameters, then two "hub" blocks (HLC and ULS) — each with
 * its two cards, its figure strip and its photo wall — and finally the optional
 * lead form the contact page already owns (20.1).
 *
 * What is scoped to `.uls-terminal-page` here is only what exists on this page:
 *
 *   hero     headline beside two staggered terminal photos;
 *   cards    one card per terminal, side by side, with its spec table;
 *   props    the infrastructure parameters, three to a row;
 *   hub      headline, an ability/service list beside the reasons, figures;
 *   strip    the row of figures under a hub block;
 *   gallery  the asymmetric photo wall (tall third photo).
 */

/* ---------------------------------------------------------------- Hero */
/*
 * Two columns: the copy keeps a comfortable measure on the left, the two photos
 * stack on the right. The block pays the fixed header's height as top padding so
 * the headline never tucks under the bar.
 */
.uls-term-hero {
	padding-block: clamp(112px, 15vh, 176px) clamp(44px, 5.6vw, 84px);
}

/*
 * Measured off the design: the copy takes about three fifths of the row and the
 * photo column the rest, so the stack reads narrower than the text beside it.
 */
.uls-term-hero__grid {
	display: grid;
	grid-template-columns: minmax(0, 1.72fr) minmax(0, 1fr);
	gap: clamp(28px, 5vw, 72px);
	align-items: center;
}

.uls-term-hero__body {
	display: flex;
	flex-direction: column;
	gap: 14px;
	max-width: 660px;
}

.uls-term-hero__title {
	margin: 0;
	font-size: var(--uls-fs-display);
	line-height: 1.06;
	letter-spacing: -0.02em;
}

.uls-term-hero__lead {
	margin: 0;
	color: #dfe4f6;
	font-size: var(--uls-fs-lead);
	line-height: 1.5;
}

.uls-term-hero__text {
	margin: 0;
	max-width: 560px;
	color: var(--uls-muted);
	font-size: var(--uls-fs-body);
	line-height: 1.6;
}

/*
 * The design offsets the two photos into a staircase: both are the same size,
 * the upper one sits on the right edge of the column and the lower one starts
 * back at its left edge, so the pair steps down towards the copy. The column
 * keeps a slice of air on its right, as the design does.
 */
.uls-term-hero__media {
	display: grid;
	/* An explicit track keeps the column at the width of the copy block; an
	   implicit one would grow to the photo's own size and push the stack out. */
	grid-template-columns: minmax(0, 1fr);
	gap: clamp(14px, 1.4vw, 20px);
}

.uls-term-hero__figure {
	margin: 0;
	/* Two thirds of the column, one and a half times as wide as it is tall. */
	width: 66.666%;
	aspect-ratio: 3 / 2;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-lg);
	overflow: hidden;
	background: var(--uls-surface);
}

/* The upper photo stops short of the edge, as the design leaves it. */
.uls-term-hero__figure:nth-child(1) {
	justify-self: end;
	margin-inline-end: clamp(0px, 3.4vw, 48px);
}

.uls-term-hero__figure:nth-child(2) {
	justify-self: start;
}

.uls-term-hero__figure img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.uls-term-hero__note {
	margin: 0;
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-xs);
	line-height: 1.5;
}

@media (max-width: 1024px) {
	.uls-term-hero__grid {
		grid-template-columns: minmax(0, 1fr);
	}

	.uls-term-hero__body {
		max-width: 720px;
	}

	/* Side by side and level again: the staircase is a wide-screen device. */
	.uls-term-hero__media {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		align-items: start;
	}

	.uls-term-hero__figure,
	.uls-term-hero__figure:nth-child(1),
	.uls-term-hero__figure:nth-child(2) {
		width: 100%;
		justify-self: stretch;
		margin-inline-end: 0;
	}
}

@media (max-width: 640px) {
	.uls-term-hero__media {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* ------------------------------------------------ Terminal kartalari */
/*
 * The two complexes sit side by side so their specification tables can be read
 * against each other, and stack on a narrow screen. The table is a two-column
 * grid of dashed cells: the value is the strong half, the note sits under it —
 * exactly how the design prints it.
 */
.uls-term-cards__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 22px;
}

.uls-term-card {
	display: flex;
	flex-direction: column;
}

.uls-term-card__media {
	margin: 0;
	aspect-ratio: 16 / 7;
	overflow: hidden;
	background: linear-gradient(150deg, #0d1740, #060b22);
}

.uls-term-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.uls-term-card__body {
	display: flex;
	flex-direction: column;
	gap: 14px;
	padding: clamp(24px, 2.6vw, 38px);
}

.uls-term-card__eyebrow {
	color: var(--uls-blue-text);
	font-size: var(--uls-fs-2xs);
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.uls-term-card__title {
	margin: 0;
	font-size: var(--uls-fs-h3);
	line-height: 1.18;
	letter-spacing: -0.01em;
}

.uls-term-card__text {
	margin: 0;
	color: #c3cae0;
	font-size: var(--uls-fs-body);
	line-height: 1.6;
}

.uls-term-card__text strong,
.uls-term-card__text b {
	color: #fff;
	font-weight: 700;
}

.uls-term-card__specs {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: clamp(18px, 2vw, 34px);
	margin: 6px 0 0;
	padding: 0;
}

.uls-term-card__spec {
	display: grid;
	align-content: start;
	gap: 3px;
	padding: 13px 0 14px;
	border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
}

/*
 * An odd numbered list ends on the whole width instead of on a lone left cell:
 * the row's rule runs under it, so a half row would show as a gap again.
 */
.uls-term-card__specs > :last-child:nth-child(odd) {
	grid-column: 1 / -1;
}

.uls-term-card__spec-value {
	color: #eaeefc;
	font-size: var(--uls-fs-sm);
	font-weight: 700;
	line-height: 1.35;
}

.uls-term-card__spec-label {
	margin: 0;
	color: var(--uls-muted);
	font-size: var(--uls-fs-xs);
	line-height: 1.45;
}

.uls-term-card__note {
	margin: 0;
	padding-top: 4px;
	color: var(--uls-muted-2);
	font-size: var(--uls-fs-xs);
	line-height: 1.6;
}

@media (max-width: 900px) {
	.uls-term-cards__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

@media (max-width: 560px) {
	.uls-term-card__specs {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* ------------------------------------------- Infratuzilma parametrlari */
.uls-term-props__grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 18px;
	margin-top: clamp(28px, 3.4vw, 48px);
}

.uls-term-prop {
	display: grid;
	align-content: start;
	gap: 10px;
	padding: clamp(22px, 2.4vw, 30px);
}

/* Round icon badge with the parameter name beside it, the way the design sets it. */
.uls-term-prop__head {
	display: flex;
	align-items: center;
	gap: 12px;
}

.uls-term-prop__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 40px;
	height: 40px;
	border-radius: var(--uls-radius-pill);
	background: var(--uls-blue);
	color: #fff;
}

.uls-term-prop__label {
	color: #eef1ff;
	font-size: var(--uls-fs-sm);
	font-weight: 600;
	line-height: 1.3;
}

.uls-term-prop__value {
	color: #fff;
	font-family: var(--uls-font-display);
	font-size: var(--uls-fs-h4);
	font-weight: var(--uls-fw-heading);
	line-height: 1.15;
	letter-spacing: -0.01em;
}

.uls-term-prop__text {
	margin: 0;
	color: var(--uls-muted);
	font-size: var(--uls-fs-sm);
	line-height: 1.55;
}

@media (max-width: 1024px) {
	.uls-term-props__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 640px) {
	.uls-term-props__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* ------------------------------------ Hub bloklari (HLC / ULS) */
/*
 * One shape, built twice: a centred headline, two cards beside each other — the
 * ability list on the left, the reasons on the right — and the figures under
 * them. The pair slides in from its own side so the two halves answer each other.
 */
.uls-term-hub__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 22px;
	margin-top: clamp(28px, 3.4vw, 48px);
}

.uls-term-hub__card {
	display: grid;
	align-content: start;
	gap: 16px;
	padding: clamp(24px, 2.6vw, 36px);
}

.uls-term-hub__card-title {
	margin: 0;
	color: #eef1ff;
	font-size: var(--uls-fs-h5);
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/*
 * The ability list fills two columns row by row — item 1 left, item 2 right,
 * item 3 left again — which is the order the editor types them in.
 */
.uls-term-hub__items {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: clamp(18px, 2vw, 34px);
	margin: 0;
	padding: 0;
	list-style: none;
}

.uls-term-hub__item {
	padding: 12px 0 13px;
	border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
	color: #cfd6ea;
	font-size: var(--uls-fs-sm);
	line-height: 1.45;
}

/*
 * An odd item takes the whole last row: each row carries its own divider, so a
 * single leftover line would otherwise sit beside an empty cell and the list
 * would end with a gap instead of a rule.
 */
.uls-term-hub__items > :last-child:nth-child(odd) {
	grid-column: 1 / -1;
}

.uls-term-reason {
	display: grid;
	gap: 4px;
	padding-bottom: 14px;
	border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
}

.uls-term-reason:last-child {
	padding-bottom: 0;
	border-bottom: 0;
}

.uls-term-reason__title {
	margin: 0;
	color: #eef1ff;
	font-size: var(--uls-fs-h5);
	font-weight: 700;
	line-height: 1.35;
}

.uls-term-reason__text {
	margin: 0;
	color: var(--uls-muted);
	font-size: var(--uls-fs-sm);
	line-height: 1.55;
}

@media (max-width: 900px) {
	.uls-term-hub__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

@media (max-width: 560px) {
	.uls-term-hub__items {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* -------------------------------------------------- Raqamlar qatori */
/*
 * Five figures under a hub block, wrapping three plus two exactly as the design
 * does. Cards rather than a plain text row: each value keeps its own frame.
 *
 * Flex, not grid: a three-column grid would break five figures into three plus
 * two and leave the last cell of the second row empty. With a flex basis of one
 * third the rows still fill three per line, but whatever falls to the next line
 * grows to fill it — two halves when two remain, the whole width when one does.
 * The editor can therefore keep any number of figures without a hole appearing.
 */
.uls-strip {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	margin-top: clamp(24px, 3vw, 40px);
}

.uls-strip__item {
	flex: 1 1 calc((100% - 32px) / 3);
	min-width: 0;
	display: grid;
	align-content: start;
	gap: 6px;
	padding: clamp(18px, 2vw, 26px);
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: var(--uls-surface);
}

.uls-strip__value {
	display: flex;
	align-items: center;
	gap: 10px;
	color: #fff;
	font-family: var(--uls-font-display);
	font-size: var(--uls-fs-h4);
	font-weight: var(--uls-fw-heading);
	line-height: 1.15;
	letter-spacing: -0.01em;
}

.uls-strip__value svg {
	flex: none;
	opacity: 0.95;
}

.uls-strip__label {
	margin: 0;
	color: var(--uls-muted);
	font-size: var(--uls-fs-xs);
	line-height: 1.45;
}

@media (max-width: 900px) {
	.uls-strip__item {
		flex-basis: calc((100% - 16px) / 2);
	}
}

@media (max-width: 560px) {
	.uls-strip__item {
		flex-basis: 100%;
	}
}

/* ------------------------------------------------------------ Galereya */
/*
 * The wall is asymmetric on purpose: two photos on the first row, the third
 * stretched over both rows in the right-hand column, then the rest under it.
 * A `nth-child` rule does the stretching, so the editor only fills slots in
 * reading order.
 */
.uls-term-gallery__grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 18px;
}

.uls-term-gallery__item {
	margin: 0;
	overflow: hidden;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: linear-gradient(150deg, #0d1740, #060b22);
	aspect-ratio: 16 / 10;
}

.uls-term-gallery__item:nth-child(3) {
	grid-column: 3;
	grid-row: span 2;
	aspect-ratio: auto;
}

.uls-term-gallery__item img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.5s ease;
}

.uls-term-gallery__item:hover img {
	transform: scale(1.04);
}

/*
 * The photo is a button, not a picture with a click handler: it opens full
 * screen (main.js), so it has to work from the keyboard too. It fills its
 * frame, so the grid and the hover zoom above are untouched.
 */
.uls-term-gallery__zoom {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	padding: 0;
	border: 0;
	background: none;
	color: var(--uls-text);
	cursor: zoom-in;
}

.uls-term-gallery__zoom:focus-visible {
	outline: 2px solid var(--uls-blue-soft);
	outline-offset: -4px;
}

/*
 * The lens in the corner. A pointer device sees it on hover (the cursor's
 * `zoom-in` already says it), a touch screen has no hover, so there it is always
 * on — otherwise nothing on the page would tell a thumb that the photo opens.
 */
.uls-term-gallery__zoom-hint {
	position: absolute;
	right: 14px;
	bottom: 14px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border: 1px solid var(--uls-border-strong);
	border-radius: 50%;
	background: rgba(4, 8, 28, 0.72);
	backdrop-filter: blur(6px);
	opacity: 0;
	transform: translateY(6px);
	transition: opacity 0.25s ease, transform 0.25s ease;
}

.uls-term-gallery__item:hover .uls-term-gallery__zoom-hint,
.uls-term-gallery__zoom:focus-visible .uls-term-gallery__zoom-hint {
	opacity: 1;
	transform: none;
}

@media (hover: none) {
	.uls-term-gallery__zoom-hint {
		opacity: 1;
		transform: none;
	}
}

/* ------------------------------------------------- Foto: to‘liq ekran */
/*
 * The frame main.js fills when a gallery photo is clicked. It lives in a
 * <template> in footer.php, so it costs a page nothing until the first photo is
 * opened; `.is-open` is what fades it in, and the page behind it stops scrolling
 * through `html.uls-lightbox-open`.
 */
html.uls-lightbox-open {
	overflow: hidden;
}

.uls-lightbox {
	position: fixed;
	inset: 0;
	z-index: 900;
	display: grid;
	grid-template-rows: auto minmax(0, 1fr);
	background: rgba(3, 6, 22, 0.94);
	backdrop-filter: blur(10px);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.28s ease, visibility 0.28s ease;
}

.uls-lightbox.is-open {
	opacity: 1;
	visibility: visible;
}

.uls-lightbox__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 18px clamp(18px, 4vw, 44px);
}

.uls-lightbox__count {
	color: var(--uls-muted);
	font-size: var(--uls-fs-xs);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.08em;
}

.uls-lightbox__btn,
.uls-lightbox__nav {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	padding: 0;
	border: 1px solid var(--uls-border-strong);
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.05);
	color: var(--uls-text);
	cursor: pointer;
	transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.uls-lightbox__btn:hover,
.uls-lightbox__nav:hover {
	background: rgba(255, 255, 255, 0.12);
	border-color: rgba(255, 255, 255, 0.42);
}

.uls-lightbox__btn:focus-visible,
.uls-lightbox__nav:focus-visible {
	outline: 2px solid var(--uls-blue-soft);
	outline-offset: 3px;
}

.uls-lightbox__stage {
	min-height: 0;
	margin: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 14px;
	padding: 0 clamp(18px, 6vw, 86px) clamp(24px, 5vw, 48px);
}

.uls-lightbox__img {
	max-width: 100%;
	max-height: 72vh;
	width: auto;
	height: auto;
	object-fit: contain;
	border-radius: 14px;
	box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
}

.uls-lightbox__caption {
	max-width: 70ch;
	margin: 0;
	color: var(--uls-muted);
	font-size: var(--uls-fs-xs);
	line-height: 1.5;
	text-align: center;
}

.uls-lightbox__caption:empty {
	display: none;
}

.uls-lightbox__nav {
	position: fixed;
	top: 50%;
	transform: translateY(-50%);
}

.uls-lightbox__nav--prev {
	left: clamp(8px, 2vw, 28px);
}

.uls-lightbox__nav--next {
	right: clamp(8px, 2vw, 28px);
}

.uls-lightbox__nav--prev svg {
	transform: rotate(180deg);
}

/* One photo in the wall: nothing to step through. */
.uls-lightbox.is-single .uls-lightbox__nav {
	display: none;
}

@media (max-width: 640px) {
	.uls-lightbox__img {
		max-height: 64vh;
	}

	.uls-lightbox__nav {
		width: 40px;
		height: 40px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.uls-lightbox,
	.uls-lightbox__nav,
	.uls-lightbox__btn {
		transition: none;
	}
}

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

	.uls-term-gallery__item:nth-child(3) {
		grid-column: auto;
		grid-row: auto;
		aspect-ratio: 16 / 10;
	}
}

@media (max-width: 560px) {
	.uls-term-gallery__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/*
 * The page's own copy lives in the ACF blocks, so an empty article would only
 * pay its block padding and push the first card a screen down. Copy written in
 * the editor still renders, just closer to the hero.
 */
.uls-terminal-page .uls-entry {
	padding-block: 0;
}

/* =========================================================================
   21. AOS (SCROLL ANIMATSIYA)
   ========================================================================= */
/*
 * AOS ships its own stylesheet (assets/vendor/aos/aos.css) and that file is
 * what actually hides `[data-aos]` blocks. The rules below tune it to the
 * design and make sure nothing can stay invisible:
 *
 *   - AOS travels 100px by default, which reads as "flying in" on a corporate
 *     page. The theme moves a block 44px instead — smaller than the library's
 *     default, large enough to be *seen* — and only for the fade variants it
 *     uses. At the 900ms/28px this used to be, a block had already settled by
 *     the time the scroll came to rest and the reveal read as "it was there all
 *     along"; the travel and the duration below move together (see the iterator
 *     in main.js: 1400ms, `ease-out-sine`) because either one on its own is the
 *     snap this is meant to avoid.
 *   - `html.uls-aos-fallback` is set by main.js when the library is missing or
 *     its init throws, and neutralises the hiding rules outright.
 *   - A `<noscript>` rule printed from functions.php does the same for visitors
 *     with JavaScript switched off.
 *
 * The travel rules are scoped to `html` on purpose: AOS's own
 * `[data-aos][data-aos].aos-animate { transform: none }` is more specific, so it
 * still wins once a block is animated and the shortened offset only describes
 * the waiting state.
 */
html [data-aos="fade-up"] {
	transform: translate3d(0, 44px, 0);
}

html [data-aos="fade-down"] {
	transform: translate3d(0, -44px, 0);
}

html [data-aos="fade-right"] {
	transform: translate3d(-44px, 0, 0);
}

html [data-aos="fade-left"] {
	transform: translate3d(44px, 0, 0);
}

html [data-aos="fade-up-right"] {
	transform: translate3d(-44px, 44px, 0);
}

html [data-aos="fade-up-left"] {
	transform: translate3d(44px, 44px, 0);
}

html [data-aos="fade-down-right"] {
	transform: translate3d(-44px, -44px, 0);
}

html [data-aos="fade-down-left"] {
	transform: translate3d(44px, -44px, 0);
}

html.uls-aos-fallback [data-aos] {
	opacity: 1 !important;
	transform: none !important;
	transition: none !important;
}

/* =========================================================================
   22. HARAKAT (scroll-driven polish)
   ========================================================================= */
/*
 * The reference build (it-helper.uz) animates its pages with GSAP: `[data-speed]`
 * parallax on the photos, `pin: true` ScrollTriggers on the cards, SplitType on
 * the titles. The theme keeps that vocabulary and drops the libraries behind it:
 *
 *   - the card pinning is plain CSS `position: sticky` (see 09);
 *   - the parallax is one rAF pass in main.js writing `--uls-par` onto the
 *     elements marked `data-uls-parallax`;
 *   - the block and list reveals stay AOS, which the theme already ships.
 *
 * All of it is decoration: with JavaScript off nothing is marked, nothing moves,
 * and the page reads exactly as it did before.
 */
[data-uls-parallax] {
	overflow: hidden;
}

/*
 * The photo drifts inside its own frame, so it has to be a touch larger than that
 * frame or a seam would open along the edge it moves away from. 1.06 buys about
 * 3% of slack per side, which is what the 8px travel in main.js needs on the
 * smallest frames in use.
 */
[data-uls-parallax] > img {
	transform: translate3d(0, var(--uls-par, 0px), 0) scale(1.06);
}

/*
 * Cards answer the pointer with a lift of their own. The transform is left alone
 * on purpose: almost every card also carries an AOS variant, and AOS's own
 * `transform: none` on the animated state outranks a `:hover` rule, so a lift
 * written as a transform would simply never show. Border and shadow it is.
 */
.uls-card {
	transition: border-color 0.35s ease, box-shadow 0.35s ease;
}

.uls-card:hover {
	border-color: rgba(141, 166, 255, 0.3);
	box-shadow: 0 24px 60px -34px rgba(43, 75, 242, 0.9);
}

@media (prefers-reduced-motion: reduce) {
	[data-uls-parallax] > img {
		transform: scale(1.06);
	}
}

/* =========================================================================
   23. TITLE REVEAL (word by word)
   ========================================================================= */
/*
 * The reference build sets its headings word by word with SplitType and
 * staggers them in. Every block title in the theme now does the same — the one
 * the template marks `text-anim-left` or `text-anim-right`, which is also what
 * decides the direction the words come in from — but the split is markup main.js
 * builds at run time, so a heading is only ever touched when the script is there
 * to finish the job:
 *
 *   - the direction is *declared in the markup*, not inferred: a heading
 *     carrying neither class is never split at all (main.js), so which way a
 *     title moves is something the template says out loud and a designer can
 *     change without touching a selector;
 *   - no JavaScript: `uls-words` is never added, the heading is plain text;
 *   - reduced motion: the split is skipped outright (see main.js) — a heading
 *     that snaps in is worse than a heading that never moved;
 *   - screen readers: the words stay ordinary text in the document, in order,
 *     with the spaces between them kept as real text nodes.
 *
 * The motion itself is the one the reference build gives its titles (`.sec-title`
 * in inotek's main.js): every **character** starts `20px` to the right of its own
 * place (`{ x: 20 }` in GSAP), at `opacity: 0`, and lands on
 * `{ opacity: 1, x: 0, duration: 0.8, stagger: 0.03, ease: back.out(1.7) }` —
 * a 30ms cascade with a slight overshoot at the end, so the characters arrive
 * with a small spring instead of sliding to a halt. `back.out(1.7)` is the
 * spring; `cubic-bezier(0.34, 1.56, 0.64, 1)` is the same curve in CSS (the
 * `1.56` control point is the overshoot — anything under 1 would land flat).
 *
 * There is deliberately **no mask** here. The reference lets a character pop in
 * with its overshoot visible; a clipped box would cut that spring off, and it
 * would also mean padding the glyphs' ascenders and descenders to keep the line
 * box intact. What is needed instead is one wrapper per *word* (`.uls-word`),
 * because a line may only break between words: with bare inline-block
 * characters a browser would happily break a word in the middle of itself.
 *
 * The stagger is a per-character `transition-delay` fed by `--uls-ci`, which the
 * splitter writes inline: character *n* waits `n × 30ms`. That is one shared
 * counter across the whole heading, not a per-word one, which is what makes the
 * cascade run through the line the way the reference does — a long word carries
 * its characters in, and the next word picks the beat up where it left off.
 *
 * The two directions are the reference's `slide-right` played either way.
 * `text-anim-right` (the default, and the reference's own default) starts a
 * character `20px` to the right of its place; `text-anim-left` starts it `20px`
 * to the left. Both are set through `--uls-cx`, so the direction is a value and
 * not a second set of transform rules — that is what keeps the revealed state
 * (`transform: none`) winning without any specificity arithmetic.
 *
 * The reveal **replays**: the observer watches both ways, so scrolling a heading
 * back out and in runs the same cascade again. Only this one animation repeats
 * for a title — the block around it is marked `data-aos-once` by main.js, so
 * scrolling back shows the characters arriving and nothing else.
 *
 * Nothing is clipped and nothing is padded, so the line box the characters sit
 * in is the line box the plain text had — measured on all ten block titles on
 * the front page: the heading is exactly as tall split as it is unsplit
 * (`96.8 = 96.8`, `48.4 = 48.4`, and the `<br>` headline `101.2 = 101.2`), and
 * no title wraps onto an extra line.
 */
.uls-words .uls-word {
	display: inline-block;
}

.uls-words .uls-char {
	display: inline-block;
	transform-origin: center center;
	opacity: 0;
	transform: translate3d(var(--uls-cx, 20px), 0, 0);
	transition: transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.5s ease-out;
	transition-delay: calc(var(--uls-ci, 0) * 30ms);
}

.uls-words.text-anim-left .uls-char {
	--uls-cx: -20px;
}

.uls-words.is-revealed .uls-char {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.uls-words .uls-char {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* =========================================================================
   24. HOVER — xizmat qatorlari, hero ko'rsatkichlari
   ========================================================================= */
/*
 * A services row answers the pointer with the accent blue on its *text* only:
 * the number and the title change colour and the title steps 6px to the right —
 * and that is the whole answer. There is deliberately no wash behind the row and
 * no pill that fills in: the row keeps the surface it has at rest, so pointing
 * at it never repaints a block of the page, it only lights up the words. No row
 * is painted blue at rest either (the accent belongs to the pointer, not to the
 * markup), which is why `template-parts/sections/services.php` no longer stamps
 * the accent on a row.
 *
 * The title's 6px nudge is deliberately on the title and not on the row: every
 * row carries `data-aos`, and AOS writes `transform: none` on the animated
 * state, so a transform on the row itself would simply never show.
 */
.uls-service__index,
.uls-service__title {
	transition: color 0.3s ease, transform 0.5s cubic-bezier(0.22, 0.68, 0.28, 1);
}

.uls-service:hover .uls-service__index,
.uls-service:hover .uls-service__title {
	color: var(--uls-blue-text);
}

.uls-service:hover .uls-service__title {
	transform: translateX(6px);
}

/*
 * The hero metrics copy the reference build's service card: on hover the card
 * does not warm up, it **turns into a light card**. In inotek the light surface
 * is an image on the card's `::before` that is parked at `width: 0; left: 50%`
 * and, on hover, grows to `width: 100%; left: 0` — it opens out of the middle of
 * the card. That growth is copied here with `clip-path: inset(0 50% 0 50%)` →
 * `inset(0)`, which is the same movement without an animating `width`: a width
 * animation lays the card out again on every frame, and these cards sit over a
 * photograph behind a `backdrop-filter`, so the frames are the one part worth
 * not paying for.
 *
 * The surface is a navy→cyan wash rather than the reference's artwork (the theme
 * has no such asset and does not need one), and the text inverts onto it: the
 * figures go dark navy, the label goes slate, the icon takes the accent blue.
 * That inversion is the whole point — a card that stays dark behind white text
 * cannot be "lit up". Because the surface is opaque, the contents are lifted
 * onto their own layer (`z-index: 1`) instead of relying on a negative one.
 *
 * The divider is the reference's `.border2::before`: a hairline that grows out
 * of the centre (`width: 0` → `96px`, absolutely placed so the card never
 * reflows while it opens).
 */
.uls-stat {
	position: relative;
	overflow: hidden;
	transition: transform 0.45s cubic-bezier(0.22, 0.68, 0.28, 1), border-color 0.45s ease,
		box-shadow 0.45s ease;
}

.uls-stat::before {
	content: "";
	position: absolute;
	inset: 0;
	background: radial-gradient(120% 130% at 14% 4%, #ffffff 0%, #eef5ff 36%, #cfe8f9 68%, #a9dcf0 100%);
	clip-path: inset(0 50% 0 50%);
	opacity: 0;
	transition: clip-path 0.45s ease, opacity 0.45s ease;
	pointer-events: none;
	z-index: 0;
}

.uls-stat:hover::before {
	clip-path: inset(0 0 0 0);
	opacity: 1;
}

.uls-stat__value,
.uls-stat__label {
	position: relative;
	z-index: 1;
}

/* The hairline the reference grows under its card title. Absolutely placed, so
 * the card's own height never moves while it opens. */
.uls-stat__value::after {
	content: "";
	position: absolute;
	left: 50%;
	bottom: -7px;
	width: 0;
	height: 1px;
	background: rgba(11, 19, 56, 0.22);
	transform: translateX(-50%);
	transition: width 0.45s ease;
}

.uls-stat:hover .uls-stat__value::after {
	width: 96px;
}

.uls-stat:hover {
	border-color: transparent;
	box-shadow: 0 26px 54px -30px rgba(4, 10, 36, 0.9);
	transform: translateY(-6px);
}

.uls-stat__value,
.uls-stat__value svg,
.uls-stat__label {
	transition: color 0.35s ease, opacity 0.35s ease;
}

.uls-stat:hover .uls-stat__value {
	color: #0b1338;
}

.uls-stat:hover .uls-stat__value svg {
	color: var(--uls-blue);
}

/*
 * The badge inverts with the rest of the card: on the lit surface it loses its
 * own dark glass and takes the accent blue, so the icon stays readable instead
 * of turning into a pale shape on a pale panel.
 */
.uls-stat:hover .uls-stat__icon {
	color: var(--uls-blue);
	border-color: rgba(11, 19, 56, 0.14);
	background: rgba(255, 255, 255, 0.62);
	box-shadow: inset 0 0 18px rgba(255, 255, 255, 0.6), 0 10px 20px -16px rgba(4, 10, 36, 0.5);
}

.uls-stat:hover .uls-stat__label {
	color: #56658c;
}

@media (prefers-reduced-motion: reduce) {
	.uls-stat,
	.uls-stat::before,
	.uls-stat__value::after,
	.uls-service__index,
	.uls-service__title,
	.uls-btn__label-in {
		transition: none;
	}

	/* The label rolls in place, so without motion it must not move at all. */
	.uls-btn:hover .uls-btn__label-in {
		top: 0;
	}

	.uls-stat:hover {
		transform: none;
	}
}

/* =========================================================================
   25. PAGE LOADER
   ========================================================================= */
/*
 * The overlay that covers the first paint while the page gets its images: a
 * thin track, a blue arc turning inside it and a ring of dots orbiting the other
 * way, all over a soft halo — the shape the reference site opens with.
 *
 * It is not shown by its own rules. `html.uls-loading` is what brings it in, and
 * that class is added by the inline snippet in header.php *before the body is
 * parsed* — so the overlay is painted with the first frame instead of popping in
 * a moment later. Every way out is a way out: a visitor without JavaScript never
 * gets the class and never sees the overlay at all, a reduced-motion visitor is
 * never given it, and the snippet carries a hard 6 second cap so the overlay
 * cannot outlive a stalled video or a lazy image.
 *
 * `visibility` (not just opacity) does the hiding, so the overlay is out of the
 * paint and hit-testing once it is gone.
 */
.uls-loader {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: grid;
	place-items: center;
	background: radial-gradient(120% 120% at 50% 44%, #0b1338 0%, var(--uls-bg) 60%, #02040f 100%);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.55s ease, visibility 0.55s ease;
}

html.uls-loading,
html.uls-loading body {
	overflow: hidden;
}

html.uls-loading .uls-loader {
	opacity: 1;
	visibility: visible;
	will-change: opacity;
}

/*
 * The mark is the box the pointer follows: the grid inside it centres the ring
 * on the halo, and the halo (an absolutely placed disc) hangs off a positioned
 * parent rather than off the full-screen overlay, which is what keeps it centred
 * on the ring instead of in a corner of the screen.
 */
.uls-loader__mark {
	position: relative;
	display: grid;
	place-items: center;
	width: clamp(120px, 16vw, 168px);
	aspect-ratio: 1;
}

.uls-loader__spinner {
	width: 100%;
	height: 100%;
	overflow: visible;
}

/*
 * The halo sits behind the rings and is what gives the mark its glow. It is a
 * blurred disc rather than a `drop-shadow` so it costs one paint and no filter
 * pass on the animated elements.
 */
.uls-loader__halo {
	position: absolute;
	left: 50%;
	top: 50%;
	width: 168%;
	aspect-ratio: 1;
	transform: translate(-50%, -50%);
	border-radius: 50%;
	background: radial-gradient(50% 50% at 50% 50%, rgba(58, 91, 255, 0.38), rgba(43, 75, 242, 0) 72%);
	filter: blur(6px);
	pointer-events: none;
}

.uls-loader__track,
.uls-loader__arc,
.uls-loader__dots {
	fill: none;
	transform-box: fill-box;
	transform-origin: center;
}

.uls-loader__track {
	stroke: rgba(255, 255, 255, 0.09);
	stroke-width: 1.6;
}

/* 2πr with r = 46 is 289: a third of it rides, the rest is the gap. */
.uls-loader__arc {
	stroke: url(#uls-loader-arc);
	stroke-width: 6;
	stroke-linecap: round;
	stroke-dasharray: 92 197;
	animation: uls-loader-turn 1.15s cubic-bezier(0.6, 0.05, 0.4, 0.95) infinite;
	filter: drop-shadow(0 0 12px rgba(58, 91, 255, 0.95));
}

/* r = 54, 36 dots: a dot every 9.42 units of the 339-unit ring. */
.uls-loader__dots {
	stroke: #d9e1ff;
	stroke-width: 3.4;
	stroke-linecap: round;
	stroke-dasharray: 0.1 9.42;
	opacity: 0.8;
	animation: uls-loader-turn 11s linear infinite reverse;
}

@keyframes uls-loader-turn {
	to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
	.uls-loader {
		display: none;
	}

	.uls-loader__arc,
	.uls-loader__dots {
		animation: none;
	}
}

/*
 * The initial paint is not the only load a visitor sees: a browser restored from
 * the back-forward cache puts the page back exactly as it was, overlay and all,
 * if it was captured mid-load. main.js clears the class on `pageshow` for that
 * case (a `visibility: hidden` overlay costs nothing), and the snippet's own cap
 * covers every other path.
 */

/* =========================================================================
   26. YANGILIKLAR (yangiliklar sahifasi)
   ========================================================================= */
/*
 * The news list (`/novosti/`, archive-uls_news.php) and one news item
 * (single-uls_news.php), to the design of Figma node 432-51: the page opens with
 * its headline centred over the dark background, and the items are set three
 * across as a wide photo, the date, the headline, the anons and a pill.
 *
 * The cards carry no panel of their own — in the design the text sits straight
 * on the page — so `.uls-news-card` is not `.uls-card`: no surface, no border,
 * no corner tint. Only the photo and the pill have a shape.
 *
 * Colours, radii and the type scale are the theme's own tokens, so this block
 * needs no new values and follows the rest of the site through a redesign.
 */

.uls-news-hero {
	padding-block: clamp(48px, 8vw, 132px) clamp(24px, 3.4vw, 54px);
	text-align: center;
}

.uls-news-hero__title {
	font-size: var(--uls-fs-display);
	margin-bottom: 12px;
}

.uls-news-hero .uls-lead {
	max-width: 720px;
	margin-inline: auto;
}

/* One item: the same hero, one size down, with the date above the headline. */
.uls-news-hero--item {
	padding-block: clamp(40px, 6vw, 92px) clamp(22px, 2.8vw, 40px);
}

.uls-news-hero__date {
	display: block;
	font-size: var(--uls-fs-xs);
	color: var(--uls-muted-2);
	margin-bottom: 14px;
}

.uls-news {
	padding-bottom: clamp(56px, 7vw, 110px);
}

.uls-news__grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: clamp(28px, 2.6vw, 40px) clamp(18px, 1.8vw, 26px);
}

.uls-news__empty {
	text-align: center;
	color: var(--uls-muted);
}

/* ------------------------------------------------------------------ Card */

.uls-news-card {
	display: flex;
	flex-direction: column;
}

.uls-news-card__media {
	display: block;
	/*
	 * The design's thumbnail measures twice as wide as it is tall (the row of
	 * cards was measured off the frame: 2.05:1), which is what the dedicated
	 * `uls-news` image size crops to as well.
	 */
	aspect-ratio: 2 / 1;
	border-radius: var(--uls-radius);
	overflow: hidden;
	background: linear-gradient(140deg, #101a45, #060b22);
}

.uls-news-card__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.5s ease;
}

.uls-news-card__media:hover .uls-news-card__img {
	transform: scale(1.04);
}

.uls-news-card__body {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	gap: 12px;
	padding-top: 20px;
}

.uls-news-card__date {
	font-size: var(--uls-fs-micro);
	color: var(--uls-muted-2);
}

.uls-news-card__title {
	font-size: var(--uls-fs-h5);
	line-height: 1.35;
	margin: 0;
}

.uls-news-card__title a {
	color: #fff;
	text-decoration: none;
	transition: color 0.2s ease;
}

.uls-news-card__title a:hover {
	color: var(--uls-blue-text);
}

.uls-news-card__text {
	margin: 0;
	font-size: var(--uls-fs-sm);
	line-height: 1.55;
	color: var(--uls-muted);
}

/*
 * The pill is pushed to the foot of the card, so the three buttons sit on one
 * line however different the three anons are — the design's own alignment.
 */
.uls-news-card__more {
	margin-top: auto;
	align-self: flex-start;
	gap: 8px;
	padding: 10px 16px;
	font-size: var(--uls-fs-xs);
}

.uls-news-card__more svg {
	flex: none;
	color: var(--uls-blue-text);
}

.uls-news-card__more:hover svg {
	color: #fff;
}

/* ------------------------------------------------------- One news item */

/*
 * The lead photo keeps its own ratio inside the reading column (the `.uls-entry`
 * width), so nothing is cropped twice and the story stays one scroll away.
 */
.uls-news-single__media {
	margin: 0;
	border-radius: var(--uls-radius-lg);
	overflow: hidden;
}

.uls-news-single__media img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 0;
}

.uls-news-single__entry {
	padding-block: clamp(30px, 4vw, 56px);
}

/*
 * `auto-fit`, not `auto-fill`: two photos should fill the row they are in
 * instead of leaving empty tracks beside them, and the height cap keeps a single
 * photo from becoming a full screen of one picture.
 */
.uls-news-gallery {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
	gap: 16px;
}

.uls-news-gallery__item {
	margin: 0;
	aspect-ratio: 4 / 3;
	max-height: 420px;
	border-radius: var(--uls-radius);
	overflow: hidden;
	background: var(--uls-surface);
}

.uls-news-gallery img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.uls-news-source {
	margin-top: 26px;
	font-size: var(--uls-fs-xs);
	color: var(--uls-muted-2);
}

.uls-news-source a {
	color: var(--uls-blue-text);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.uls-news-nav {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	margin-top: clamp(32px, 4vw, 56px);
	padding-top: clamp(20px, 2.5vw, 32px);
	border-top: 1px solid var(--uls-border);
}

.uls-news-nav__link {
	flex: 1 1 0;
	max-width: 480px;
	display: flex;
	flex-direction: column;
	gap: 6px;
	padding: 18px 20px;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: var(--uls-surface);
	transition: border-color 0.2s ease, background 0.2s ease, transform 0.2s ease;
}

.uls-news-nav__link:hover {
	border-color: var(--uls-border-strong);
	background: var(--uls-surface-2);
	transform: translateY(-1px);
}

/* The last item has nothing after it: the link it does have keeps its side. */
.uls-news-nav__link--next {
	text-align: right;
	align-items: flex-end;
	margin-left: auto;
}

.uls-news-nav__label {
	font-size: var(--uls-fs-2xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--uls-muted-2);
}

.uls-news-nav__title {
	font-size: var(--uls-fs-body);
	font-weight: 600;
	color: #fff;
}

.uls-news-back {
	margin-top: clamp(24px, 3vw, 38px);
}

/* ------------------------------------------------------- Page numbers */

.uls-news .pagination {
	margin-top: clamp(36px, 4.5vw, 64px);
}

.uls-news .nav-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 8px;
}

.uls-news .nav-links > * {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 42px;
	height: 42px;
	padding: 0 14px;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-pill);
	background: rgba(255, 255, 255, 0.02);
	color: #e7ebff;
	font-size: var(--uls-fs-xs);
}

.uls-news .nav-links a:hover {
	border-color: var(--uls-border-strong);
	background: rgba(255, 255, 255, 0.06);
}

.uls-news .nav-links .current {
	background: var(--uls-blue);
	border-color: transparent;
	color: #fff;
	font-weight: 700;
}

.uls-news .nav-links .dots {
	border-color: transparent;
	background: none;
	color: var(--uls-muted-2);
	min-width: 0;
	padding: 0 4px;
}

/* -------------------------------------------------- Responsive (news) */

@media (max-width: 1024px) {
	.uls-news__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 680px) {
	.uls-news__grid {
		grid-template-columns: minmax(0, 1fr);
	}

	.uls-news-nav {
		flex-direction: column;
	}

	.uls-news-nav__link {
		max-width: none;
	}

	.uls-news-nav__link--next {
		text-align: left;
		align-items: flex-start;
	}
}

@media (prefers-reduced-motion: reduce) {
	.uls-news-card__img,
	.uls-news-nav__link {
		transition: none;
	}

	.uls-news-card__media:hover .uls-news-card__img {
		transform: none;
	}

	.uls-news-nav__link:hover {
		transform: none;
	}
}

/* =========================================================================
   27. KOMPANIYA HAQIDA («О компании», Figma Frame 188)
   ========================================================================= */
/*
 * The page opens with its own hero instead of the shared inner-page banner: the
 * design centres the headline and the three-line subtitle on the page's navy
 * gradient and prints the page's main photo under them, with no background
 * picture behind the copy. The subtitle keeps the `.uls-lead` scale the rest of
 * the site uses — only the centring and the photo come from here.
 */
.uls-about-hero {
	padding-block: clamp(52px, 8vw, 150px) 0;
	text-align: center;
}

.uls-about-hero__title {
	font-size: var(--uls-fs-display);
	margin-bottom: 16px;
}

.uls-about-hero__media {
	max-width: 772px;
	margin: clamp(32px, 4.6vw, 64px) auto 0;
	overflow: hidden;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-lg);
	background: linear-gradient(150deg, #0d1740, #060b22);
	/* The frame the design draws for this photo, cropped to fill. */
	aspect-ratio: 772 / 646;
}

.uls-about-hero__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The mission paragraph: one centred column, capped at the width the design
 * wraps it at. It is narrower than the container on purpose — the sentence is
 * the page's statement, not a paragraph of body copy.
 */
.uls-about-mission {
	padding-block: clamp(32px, 4.4vw, 64px);
}

.uls-about-mission__text {
	max-width: 560px;
	margin-inline: auto;
	color: var(--uls-muted);
	font-size: var(--uls-fs-lead);
	line-height: 1.65;
	text-align: center;
}

/*
 * The figures row, when the page asks for it. `.uls-stats` pushes itself to the
 * bottom of the hero with `margin-top: auto`; as a block of its own there is no
 * hero above it, so that push is dropped.
 */
.uls-stats--block {
	margin-top: 0;
}

/*
 * The photo wall: the design's staggered bento. Two photos on the first row, a
 * tall one taking the whole right column, two more under it — and the two rows
 * are *not* cut in the same place, so the grid keeps 22 tracks and lets the five
 * slots land on 8/6/8 (first row) and 6/8 (second row). 22 is the smallest
 * number of tracks that draws both rows with the same right-hand edge and
 * without a hole between them.
 */
.uls-photo-wall__grid {
	display: grid;
	grid-template-columns: repeat(22, minmax(0, 1fr));
	grid-template-rows: repeat(2, minmax(0, 1fr));
	gap: 18px;
	/* Two rows at the design's height (the wall is 1264×448 in the frame). */
	aspect-ratio: 1264 / 448;
}

.uls-photo-wall__item {
	grid-column: span 8;
	grid-row: 1;
	margin: 0;
	overflow: hidden;
	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius);
	background: linear-gradient(150deg, #0d1740, #060b22);
}

.uls-photo-wall__item:nth-child(2) {
	grid-column: 9 / span 6;
}

/* The tall photo of the design: the whole right column, both rows. */
.uls-photo-wall__item:nth-child(3) {
	grid-column: 15 / span 8;
	grid-row: 1 / span 2;
}

.uls-photo-wall__item:nth-child(4) {
	grid-column: 1 / span 6;
	grid-row: 2;
}

.uls-photo-wall__item:nth-child(5) {
	grid-column: 7 / span 8;
	grid-row: 2;
}

/*
 * A wall the editor grew past the design's five photos keeps flowing below in
 * two columns, so nothing ever lands on top of the tall frame.
 */
.uls-photo-wall__item:nth-child(n + 6) {
	grid-column: span 11;
	grid-row: auto;
	aspect-ratio: 16 / 10;
}

.uls-photo-wall__item img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.5s ease;
}

.uls-photo-wall__item:hover img {
	transform: scale(1.04);
}

@media (max-width: 900px) {
	.uls-photo-wall__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		grid-template-rows: none;
		aspect-ratio: auto;
	}

	.uls-photo-wall__item,
	.uls-photo-wall__item:nth-child(2),
	.uls-photo-wall__item:nth-child(3),
	.uls-photo-wall__item:nth-child(4),
	.uls-photo-wall__item:nth-child(5),
	.uls-photo-wall__item:nth-child(n + 6) {
		grid-column: auto;
		grid-row: auto;
		aspect-ratio: 16 / 10;
	}
}

@media (max-width: 560px) {
	.uls-photo-wall__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

@media (prefers-reduced-motion: reduce) {
	.uls-photo-wall__item img,
	.uls-photo-wall__item:hover img {
		transition: none;
		transform: none;
	}
}

/* =========================================================================
   28. BACK TO TOP
   ========================================================================= */
/*
 * One floating circle, in the same material as the glass buttons (04): a
 * translucent navy fill, the 1px blue-tinted border and a backdrop blur, so on
 * the deep-blue page it reads as a chip of the interface rather than a widget
 * bolted on top.
 *
 * `visibility` rather than `display` — it is what keeps the button out of the
 * tab order and out of the accessibility tree while it is not shown, and it
 * flips at the end of the fade-out so the ring does not vanish mid-animation.
 * It sits at z-index 65: above the pinned header (60/61), below the mobile nav
 * (70) and the plans modal (1000), so none of them is ever covered.
 */
.uls-to-top {
	position: fixed;
	right: clamp(16px, 2.2vw, 34px);
	bottom: calc(clamp(16px, 2.2vw, 34px) + env(safe-area-inset-bottom, 0px));
	z-index: 65;

	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 52px;
	height: 52px;
	padding: 0;

	border: 1px solid var(--uls-border);
	border-radius: var(--uls-radius-pill);
	background: rgba(10, 17, 54, 0.72);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	box-shadow: 0 18px 40px -18px rgba(3, 7, 26, 0.9);
	color: var(--uls-text);

	cursor: pointer;
	opacity: 0;
	transform: translateY(14px) scale(0.94);
	visibility: hidden;
	transition: opacity 0.25s ease, transform 0.25s ease, visibility 0s linear 0.25s,
		background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.uls-to-top.is-visible {
	opacity: 1;
	transform: none;
	visibility: visible;
	transition: opacity 0.25s ease, transform 0.25s ease, visibility 0s,
		background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.uls-to-top:hover,
.uls-to-top:focus-visible {
	background: var(--uls-blue);
	border-color: var(--uls-blue-soft);
	box-shadow: 0 18px 40px -14px rgba(43, 75, 242, 0.85);
}

.uls-to-top:focus-visible {
	outline: 2px solid var(--uls-blue-text);
	outline-offset: 3px;
}

/* The icon set has one arrow, pointing right; a quarter turn makes it "up". */
.uls-to-top svg {
	transform: rotate(-90deg);
	transition: transform 0.2s ease;
}

.uls-to-top:hover svg {
	transform: rotate(-90deg) translateX(2px);
}

/* The page start is where focus lands after the jump; a ring around the whole
 * page would only be noise, and <main> is not an interactive control. */
.uls-main:focus {
	outline: none;
}

@media (max-width: 860px) {
	/*
	 * The copyright line runs nearly the full width here, so the corner the
	 * button lives in is the corner the text reaches. The footer opens a lane
	 * for it rather than the button moving somewhere a thumb does not look.
	 */
	.uls-footer {
		padding-bottom: 86px;
	}
}

@media (max-width: 640px) {
	.uls-to-top {
		width: 46px;
		height: 46px;
		right: 14px;
		bottom: calc(14px + env(safe-area-inset-bottom, 0px));
	}
}

@media (prefers-reduced-motion: reduce) {
	.uls-to-top,
	.uls-to-top.is-visible {
		transition: none;
		transform: none;
	}

	.uls-to-top svg,
	.uls-to-top:hover svg {
		transform: rotate(-90deg);
	}
}

@media print {
	.uls-to-top {
		display: none;
	}
}
