/* =========================================================
   БАЙТ — Технологическое партнерство
   Figma: Arbite / node 1931-8326 (base width 1728px)
   ========================================================= */

/* ---------- fonts (self-hosted, assets/fonts) ----------
   Montserrat variable, weight axis 400–700. One file per unicode subset;
   the browser downloads only the ranges the page actually uses. */
@font-face{
  font-family:"Montserrat";
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url("assets/fonts/montserrat-cyrillic.woff2") format("woff2");
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face{
  font-family:"Montserrat";
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url("assets/fonts/montserrat-cyrillic-ext.woff2") format("woff2");
  unicode-range:U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face{
  font-family:"Montserrat";
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url("assets/fonts/montserrat-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:"Montserrat";
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url("assets/fonts/montserrat-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- colour tokens ----------
   Two tiers. Tier 1 holds raw values and is referenced only by tier 2; tier 2
   names the role. Every rule in this sheet uses a tier-2 role, so a colour
   lives in exactly one place and the same role cannot drift between pages.
   The only literals left outside this block are the --g1..--g12 gradient
   recipes, which are animation frames rather than reusable roles. */
:root{
  /* ===== tier 1 — primitives ===== */

  /* neutral ramp */
  --n-000: #fff;
  --n-050: #f6f9fb;   /* field and pager plates */
  /* one light blue-grey: cards, chips, hairlines and the pager hover were
     e9f0f5 / e9eef1 / e4eaef / e6eef6 — a 1.44 dE2000 spread, invisible. */
  --n-100: #e9f0f5;
  --n-250: #efefef;   /* secondary copy on the blue surfaces */
  /* one mid grey: d3dbe2 and c9d3dc were 2.19 dE2000 apart */
  --n-400: #c9d3dc;
  --n-450: #8f9ba6;
  --n-500: #acacac;
  /* the single muted grey: 5.7:1 on white, so 14-15px copy still clears AA.
     Replaces the old 5c5c5c / 696969 / 838383 / 898989 spread. */
  --n-600: #696969;
  --n-800: #484848;
  --n-900: #000;

  /* brand blues (Figma variables + hero/footer fills) */
  --b-950: #001c38;   /* the dimming laid over the pinned hero */
  --b-900: #012a5c;
  /* one deep blue. 004d8f / 0a549b / 084d8f / 045196 all sat within 1.5 dE2000
     of this value — below the threshold at which the eye separates two hues. */
  --b-700: #045196;
  --b-550: #0049a6;
  --b-500: #0263bb;   /* Figma var: основной */
  --b-400: #0171d1;
  --b-200: #81d6f6;
  --b-100: #d2f2ff;   /* Figma var: футер */
  --b-crumb: #6271b1;

  /* accents */
  --a-teal:   #17c7b2;   /* gradient highlight */
  --a-check:  #00adaa;   /* галочки: кружки чек-листа и печати статусов */
  --a-badge:  #68baa9;   /* плашка «Минпромторг» */
  --a-bullet: #0039c8;   /* точки списка преимуществ */
  --a-red:    #c80a0a;   /* единственный красный: метка PDF, снятие фильтра */
  --a-online: #02ff20;   /* «в сети» indicator */
  --a-danger: #ff9a9a;   /* form errors */

  /* ===== tier 2 — roles ===== */

  /* text on light surfaces. Headings and lists are pure black sitewide;
     running paragraphs sit one step down at --text-body; --text-mute is for
     supporting UI (menu captions, pager meta) and never for content. */
  --text:          var(--n-900);   /* headings, list items */
  --text-body:     var(--n-800);   /* paragraphs */
  --text-mute:     var(--n-600);
  --link:          var(--b-500);

  /* text on the blue surfaces */
  --text-inv:       var(--n-000);
  --text-inv-soft:  var(--n-250);   /* secondary copy */
  --text-inv-key:   var(--b-100);   /* footer copy and hover accents */
  --text-inv-dim:   var(--n-450);   /* footnotes on blue */

  /* fills */
  --brand:          var(--b-500);
  --surface:        var(--n-050);   /* kept apart from white: it is the plate
                                       under fields and pager buttons */
  /* one light tone for every tinted surface and every hairline: plates,
     chips, the pager hover and the rules were four roles already sharing a
     value, so they are one role now. */
  --tint:           var(--n-100);
  --num:            var(--n-500);

  /* lines */
  --rail:           var(--n-400);

  /* gradient stops, kept as named pairs */
  /* one dark navy behind every veil: the hero dim, the menu scrim, the
     lightbox and the filter drawer were four near-identical values. */
  --veil:         var(--b-950);
  --hero-a:       var(--b-700);
  --hero-b:       var(--b-400);
  --cons-a:       var(--b-700);
  --cons-b:       var(--b-550);

  /* type */
  --font: "Montserrat", "Segoe UI", system-ui, -apple-system, sans-serif;

  /* layout — design is 1728 wide with 25px gutters => 1678 content */
  --pad: 25px;
  --maxw: 1678px;
  --topbar-h: 76px;
  /* the product page docks a second bar under the first one. --stick-h is the
     total height of whatever is pinned, and it is the only number the anchor
     offsets read, so a page that adds a bar cannot forget to widen them. */
  --subbar-h: 76px;
  --stick-h: var(--topbar-h);
  /* the three plates close the home page's first screen: this is their height
     and the gap over them, and the hero reads both to take what is left of the
     fold. Kept here because the two blocks that share the number are not
     nested and cannot pass it between themselves. */
  --usp-h: 212px;
  --usp-gap: clamp(20px, 2.2vw, 38px);

  /* partner row columns as % of the 1678 content box */
  --c-num:  3.58%;
  --c-logo: 23.48%;
  --c-gap:  12.74%;
  --c-body: 60.2%;

  /* left edge of the text column. The hero copy, the partner copy and the
     pager all hang off this one value so they cannot drift apart. */
  --col-text: calc(var(--c-num) + var(--c-logo) + var(--c-gap));

  /* Same value as --col-text, but unitless, so it can be multiplied by a length.
     Keep the two in sync. */
  --col-text-n: 0.398;

  /* Rule geometry, resolved inside a full-bleed layer where 100% = viewport.
     The horizontal rules keep spanning the whole site width; only the vertical
     guides are snapped to the container's text column, then pulled left by
     --rule-gap so the copy never sits flush against them. */
  --fl: rgba(255,255,255,.18);   /* footer / hero hairline colour */
  /* per-row lift of the vertical ticks, tuned against the live layout */
  --tick-lift:   122px;          /* rows A and D */
  /* Length of the middle pair, hung off its own row. Fluid, because the
     distance between rows A and B grows with the viewport — a fixed value
     left a visible gap under row A on wide screens. */
  --tick-h-b: clamp(210px, calc(26vw - 40px), 410px);
  --tick-lift-d: 240px;          /* the lone tick above the bottom bar */
  --tick-shift:   50px;          /* ticks sit this far left of their guide */
  /* actual tick columns — the breaks in the horizontal rows are cut around
     these same two values, so the two can never drift apart */
  --tick-x1: calc(var(--guide-1) - var(--tick-shift));
  --tick-x2: calc(var(--col-x)   - var(--tick-shift));
  /* Stepped blue edge that rises out of the footer over the photo band
     (Figma 2246-311). Cut out of the section itself with clip-path rather than
     drawn as separate blocks, so the animated gradient fills the steps and they
     always read as one piece with the footer. */
  --steps-h: 154px;
  --step-1: calc(var(--steps-h) * 0.5);    /* the 77px shoulders */
  --step-2: calc(var(--steps-h) * 0.071);  /* the taller 143px column */
  --rule-gap: 28px;
  /* how far the hero hairline sits above the block's lower edge:
     46px padding + the lead + ~30px of air */
  /* vertical framing of the footer clip: 50% is dead centre, higher values
     lift the picture inside the strip */
  --band-focus: 64%;

  --rule-y: 154px;
  --shell-w: min(100% - var(--pad)*2, var(--maxw));
  --shell-x: calc((100% - var(--shell-w)) / 2);
  --col-x:   calc(var(--shell-x) + var(--col-text-n) * var(--shell-w));
  --guide-2: calc(var(--col-x) - var(--rule-gap));
  --guide-1: calc(var(--shell-x) + 0.132 * var(--shell-w));

  /* Inline mask shapes. Kept as data: URIs so they still render when the page
     is opened from disk — external mask URLs are origin-checked and collapse
     to an empty mask under file://, silently hiding the icon. */
  --caret-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 4' fill='none'%3E%3Cpath d='M0.5 0.5L4 3.5L7.5 0.5' stroke='%23000'/%3E%3C/svg%3E");
  --tick-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0Zm4.03 5.86-4.9 4.9a.8.8 0 0 1-1.13 0L3.97 8.53a.8.8 0 1 1 1.13-1.13l1.46 1.47 4.34-4.34a.8.8 0 0 1 1.13 1.13Z' fill='%23000'/%3E%3C/svg%3E");
  --lock-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22' fill='none'%3E%3Crect x='4.5' y='9.5' width='13' height='9' rx='1.5' stroke='%23000' stroke-width='1'/%3E%3Cpath d='M7.5 9.5V7a3.5 3.5 0 1 1 7 0v2.5' stroke='%23000' stroke-width='1'/%3E%3C/svg%3E");
  --seal-mask:  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 23 23'%3E%3Cpath d='M9.37028 2.03077C10.5625 0.893922 12.4375 0.893923 13.6297 2.03077C14.2529 2.62498 15.0959 2.93183 15.9552 2.8772C17.5993 2.77267 19.0356 3.97787 19.2182 5.61511C19.3136 6.47085 19.7622 7.24782 20.4555 7.75832C21.7822 8.73504 22.1077 10.5815 21.1952 11.9531C20.7182 12.6699 20.5624 13.5535 20.7654 14.3902C21.1539 15.9912 20.2164 17.6149 18.6357 18.079C17.8096 18.3216 17.1223 18.8983 16.7399 19.6698C16.0084 21.1458 14.2466 21.7871 12.7374 21.1266C11.9486 20.7813 11.0514 20.7813 10.2626 21.1266C8.75345 21.7871 6.99157 21.1458 6.26005 19.6698C5.87771 18.8983 5.19044 18.3216 4.36427 18.079C2.78361 17.6149 1.84613 15.9912 2.23455 14.3902C2.43757 13.5535 2.28178 12.6699 1.80481 11.9531C0.892262 10.5815 1.21784 8.73504 2.54446 7.75832C3.23784 7.24782 3.68642 6.47085 3.78184 5.61511C3.9644 3.97787 5.40069 2.77267 7.04476 2.8772C7.90407 2.93183 8.74713 2.62498 9.37028 2.03077Z' fill='%23000'/%3E%3C/svg%3E");
  /* the one arrow on the site, straight from Figma: same glyph in the
     solution rows, the bordered calls and the card hover button */
  --arrow-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22.2132 14.7279'%3E%3Cpath d='M1 6.36396H0V8.36396H1V7.36396V6.36396ZM21.9203 8.07107C22.3108 7.68054 22.3108 7.04738 21.9203 6.65685L15.5563 0.292893C15.1658 -0.097631 14.5327 -0.097631 14.1421 0.292893C13.7516 0.683418 13.7516 1.31658 14.1421 1.70711L19.799 7.36396L14.1421 13.0208C13.7516 13.4113 13.7516 14.0445 14.1421 14.435C14.5327 14.8256 15.1658 14.8256 15.5563 14.435L21.9203 8.07107ZM1 7.36396V8.36396H21.2132V7.36396V6.36396H1V7.36396Z' fill='%23000'/%3E%3C/svg%3E");
  --pin-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 14'%3E%3Cpath d='M6 0a6 6 0 0 0-6 6c0 4.2 5.3 7.7 5.5 7.85a.9.9 0 0 0 1 0C6.7 13.7 12 10.2 12 6a6 6 0 0 0-6-6Zm0 8.4A2.4 2.4 0 1 1 6 3.6a2.4 2.4 0 0 1 0 4.8Z' fill='%23000'/%3E%3C/svg%3E");
  --seal-tick-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 23 23'%3E%3Cpath d='M8.09285 11.3387L11.338 13.6299L14.9077 8.51874' stroke='%23000' stroke-width='2' fill='none'/%3E%3C/svg%3E");
}

/* ---------- reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
/* No scroll-behavior:smooth here on purpose. It also animates the scroll
   position the browser restores on reload, so returning to a page scrolled
   half-way down visibly flies from the top. Anchors are smooth-scrolled
   from JS instead. */
html{ -webkit-text-size-adjust:100%; }
body{
  margin:0;
  font-family:var(--font);
  font-size:15px;
  line-height:1.27;
  color:var(--text-body);
  background:var(--n-000);
  /* clip, not hidden: `hidden` turns <body> into a scroll container, which
     makes Chrome repaint composited layers under it while scrolling */
  overflow-x:hidden;
  overflow-x:clip;
}
img,svg{ max-width:100%; height:auto; display:block; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
a{ color:inherit; text-decoration:none; }
ul{ margin:0; padding:0; list-style:none; }
h1,h2,h3,h4,p{ margin:0; }
input{ font:inherit; }

:focus-visible{ outline:2px solid var(--brand); outline-offset:3px; }

.skip-link{
  position:absolute; left:-9999px; top:0; z-index:100;
  background:var(--n-000); color:var(--brand); padding:12px 20px; font-weight:700;
}
.skip-link:focus{ left:12px; top:12px; }

/* readable by assistive tech and search engines, invisible on screen */
.sr-only{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden; white-space:nowrap;
}

.shell{
  width:min(100% - var(--pad)*2, var(--maxw));
  margin-inline:auto;
}

/* decorative hairlines shared by hero + consultation blocks */
.rule{ position:absolute; background:rgba(255,255,255,.18); pointer-events:none; }

/* =========================================================
   TOP BAR
   Always pinned — it must not slide away while the hero's own headline stays
   put. Only its skin changes: transparent over the blue hero, white once the
   content below has taken the whole viewport (or while hovered).
   ========================================================= */
.topbar{
  position:fixed; top:0; left:0; right:0; z-index:60;
  /* the bar no longer sits inside .hero, so it owns its own text colour —
     links, the city and the currentColor caret all inherit from here */
  color:var(--text-inv);
  transition:background-color .25s ease, box-shadow .25s ease, color .25s ease;
}
.topbar.is-light{
  color:var(--text);
  background:var(--n-000);
  box-shadow:inset 0 -1px 0 var(--tint);
}
/* once the white content is under it, the bar earns a drop shadow */
.topbar.is-stuck{
  box-shadow:inset 0 -1px 0 var(--tint), 0 4px 12px rgba(0,0,0,.06);
}

/* Sits under the bar (z 60) but over the page, so the header and its dropdown
   stay bright while everything else recedes. */
.scrim{
  position:fixed; inset:0; z-index:50;
  background:rgb(0 28 56 / .5);
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .25s ease, visibility .25s;
}
.scrim.is-open{ opacity:1; visibility:visible; pointer-events:auto; }

/* =========================================================
   HERO
   ========================================================= */
/* The hero is pinned to the top of the viewport and .site-main slides up over it —
   that is the "white block rides onto the blue" effect.
   Decorative layers deliberately stay at a non-negative z-index: negative-z
   children inside an isolated stacking context get their own composited layer,
   which Chrome scrolls out of sync, and the pinning then looks jittery. */
.hero{
  position:sticky; top:0; z-index:0;
  /* 40vw lands on the design's 569px at 1728 and eases off below it */
  min-height:clamp(430px, 40vw, 569px);
  padding-top:var(--topbar-h);    /* room the top bar used to occupy in flow */
  padding-bottom:46px;
  display:flex; flex-direction:column;
  color:var(--text-inv);
  overflow:hidden;
  background:linear-gradient(190.567deg, var(--hero-a) 28.464%, var(--hero-b) 82.079%);
}
.hero > .shell{ flex:1; display:flex; flex-direction:column; }
/* everything after the hero is opaque and travels above it */
.site-main{ position:relative; z-index:1; background:var(--n-000); }

/* anchors jumped to from the nav must clear everything that is pinned */
[id]{ scroll-margin-top:calc(var(--stick-h) + 14px); }

/* dims the pinned hero as the white block covers it — opacity driven from JS */
.hero__dim{
  position:absolute; inset:0; z-index:2;
  background:var(--veil);
  opacity:0;
  pointer-events:none;
  will-change:opacity;
}
.hero__grad,
.hero__glow,
.hero__rules{ position:absolute; z-index:0; pointer-events:none; }

/* Cross-fading gradient stack (the gradientify.js technique): one layer per
   gradient, all stacked, only one at opacity 1 at a time. JS flips which one
   and a linear transition of the same length does the blending, so the fades
   run back to back with no seam. Layers are built in JS — without it the
   static section background stands in. Shared by the hero and the footer. */
/* Palettes live here, not in the script: JS only reads them and builds the
   layers, so every colour decision stays in the stylesheet. */
.hero__grad,
.cons__grad{ position:absolute; inset:0; z-index:0; pointer-events:none; }

.hero__grad{
  --g1:linear-gradient(190deg, #004d8f 28%, #0171d1 82%);
  --g2:linear-gradient(145deg, #003f7a  8%, #0263bb 58%, #0b8bb4 100%);
  --g3:linear-gradient( 35deg, #084d8f 12%, #0171d1 52%, #17c7b2 108%);
  --g4:linear-gradient(215deg, #0049a6 18%, #045196 62%, #0097c5 100%);
  --g5:radial-gradient(120% 95% at 22% 108%, #17c7b2 0%, #0171d1 42%, #004d8f 100%);
}
.cons__grad{
  --g1:radial-gradient(130% 100% at 22% 108%, #17c7b2 0%, #0263bb 44%, #012a5c 100%);
  --g2:linear-gradient(150deg, #012f66  0%, #0263bb 55%, #0d86c9 100%);
  --g3:linear-gradient(205deg, #0a2f7a  5%, #0171d1 50%, #16b8c4 106%);
  --g4:linear-gradient( 20deg, #003c78 10%, #045196 45%, #0a8fb8 100%);
  --g5:linear-gradient(176deg, #045196 35%, #0049a6 100%);
}
.hero__grad > i,
.cons__grad > i{
  position:absolute; inset:0;
  display:block;
  opacity:0;
  transition-property:opacity;
  transition-timing-function:linear;
}

/* teal wash that bleeds in at the bottom of the frame */
.hero__glow{
  inset:0;
  background:
    radial-gradient(120% 78% at 32% 122%, rgba(23,199,178,.62) 0%, rgba(23,199,178,0) 60%),
    radial-gradient( 70% 60% at 88% 118%, rgba(0,158,205,.45) 0%, rgba(0,158,205,0) 65%);
}

.hero__rules{ inset:0; }

/* content rides above the decorative layers */
.hero > .shell{ position:relative; z-index:1; }
/* Horizontals run the full site width and break around the vertical guide with
   the same --rule-gap on each side, so the gap reads as symmetric. */
.rule--h1{ left:var(--pad);   width:calc(var(--guide-2) - var(--rule-gap) - var(--pad)); bottom:var(--rule-y); height:1px; overflow:hidden; }
.rule--h2{ left:var(--col-x); right:var(--pad);                                          bottom:var(--rule-y); height:1px; overflow:hidden; }
.rule--v1{ left:var(--guide-2); top:20.6%; bottom:calc(var(--rule-y) + 12px); width:1px; overflow:hidden; }
.rule--v3{ left:var(--guide-2); top:calc(100% - var(--rule-y) + 12px); bottom:0; width:1px; overflow:hidden; }

/* Highlights that run along the rules, each in its own direction. Sizes are
   percentages of their own track, so they stay proportional on short and long
   rules alike. JS keeps only two running at a time, picked at random. */
.spark{ position:absolute; opacity:0; pointer-events:none; }
.spark--h{ top:0;  height:1px; width:26%; }
.spark--v{ left:0; width:1px;  height:34%; }

/* the solid end leads, the transparent tail trails */
.spark--ltr{ background:linear-gradient(to right,  rgba(255,255,255,0), var(--n-000)); }
.spark--rtl{ background:linear-gradient(to left,   rgba(255,255,255,0), var(--n-000)); }
.spark--btt{ background:linear-gradient(to top,    rgba(255,255,255,0), var(--n-000)); }
.spark--ttb{ background:linear-gradient(to bottom, rgba(255,255,255,0), var(--n-000)); }

@keyframes spark-h-ltr{
  0%{ left:-26%; opacity:0 } 14%{ opacity:1 } 72%{ opacity:1 } 100%{ left:100%; opacity:0 }
}
@keyframes spark-h-rtl{
  0%{ left:100%; opacity:0 } 14%{ opacity:1 } 72%{ opacity:1 } 100%{ left:-26%; opacity:0 }
}
@keyframes spark-v-btt{
  0%{ top:100%;  opacity:0 } 14%{ opacity:1 } 72%{ opacity:1 } 100%{ top:-34%;  opacity:0 }
}
@keyframes spark-v-ttb{
  0%{ top:-34%;  opacity:0 } 14%{ opacity:1 } 72%{ opacity:1 } 100%{ top:100%;  opacity:0 }
}

/* ---------- header / nav ---------- */
/* three tracks: brand | menu | tools. The menu track starts at --col-text, so the
   first link shares the vertical line with the H1 and the partner copy.
   .nav__tools lives in the header bar at every breakpoint — on phones it is the
   only visible control group besides the burger. */
.nav{
  position:relative;              /* anchor for the full-bleed mega panel */
  display:grid;
  grid-template-columns:var(--col-text) 1fr auto;
  align-items:center;
  padding:18px 0;
  min-height:76px;
}
/* .nav__menu is deliberately NOT positioned — the full-bleed mega panel anchors
   to .nav and would otherwise measure itself against the middle grid column. */

.nav__brand{
  display:flex; align-items:center; min-width:0;
  gap:clamp(16px, 2vw, 34px);
}
/* top:-2px — a couple more px above true centre, by request, on top of the
   centring fix above */
.nav__logo{ position:relative; top:-2px; display:block; width:clamp(96px, 7vw, 121px); flex:none; }
/* display:block — a bare inline <img> keeps a few px of descender space
   under it for text it never sits beside, which grew .nav__logo taller than
   the mark itself and pushed it low in the bar even though the flex row
   around it was already centered correctly */
.nav__logo-img{ display:block; width:100%; transition:opacity .25s ease; }
.nav__logo-img--on-white{
  position:absolute; left:0; top:50%;
  transform:translateY(-50%);
  opacity:0;
}

.nav__city{
  cursor:pointer;
  display:inline-flex; align-items:center; gap:8px;
  font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.01em;
  white-space:nowrap;
  transition:color .25s ease, opacity .25s ease;
}
/* the trigger dims while its own panel is open — the same feedback
   .nav__link gives on hover, read here off the wrapper JS toggles */
.city.is-open > .nav__city{ opacity:.75; }
/* Masked, so the colour is a plain background-color in every header state.
   The shape is inlined as a data: URI on purpose — a CSS mask pointing at an
   external file is origin-checked and renders empty when the page is opened
   straight from disk (file://), which makes the icon vanish. */
.nav__pin{
  flex:none; width:12px; height:14px;
  background:var(--n-000);
  -webkit-mask:var(--pin-mask) no-repeat center / contain;
          mask:var(--pin-mask) no-repeat center / contain;
  transition:background-color .25s ease;
}

/* ---------- city picker ----------
   A small popover anchored to the pin, not a <dialog>: unlike the filter
   drawer or the lightbox it never owns the whole screen, so it needs neither
   a backdrop nor a focus trap — the same opacity/transform toggle .submenu
   uses for the mega panel is enough here too. */
.city{ position:relative; }

.city__panel{
  position:absolute; top:calc(100% + 16px); left:0; z-index:45;
  width:320px; max-width:calc(100vw - var(--pad) * 2);
  padding:18px;
  background:var(--n-000);
  border-radius:4px;
  box-shadow:0 18px 40px rgba(0,32,66,.18);
  opacity:0; visibility:hidden; transform:translateY(8px);
  transition:opacity .2s ease, transform .2s ease, visibility .2s;
}
.city.is-open .city__panel{ opacity:1; visibility:visible; transform:translateY(0); }

.city__search{ position:relative; }
/* the source SVG's stroke is a fixed #333, not currentColor — fine here,
   the panel is always a white card regardless of the header's own theme */
.city__search-icon{
  position:absolute; left:14px; top:50%;
  width:14px; height:14px;
  transform:translateY(-50%);
  pointer-events:none;
}
.city__input{
  width:100%; height:40px; padding:0 14px 0 38px;
  border:1px solid var(--tint); border-radius:2px;
  background:var(--surface);
  font-family:inherit; font-size:14px; font-weight:500;
  color:var(--text);
  transition:border-color .18s ease;
}
.city__input::placeholder{ color:var(--n-450); font-weight:500; }
/* search type for the Escape-to-clear behaviour, not for Chrome's own
   cancel button — that one would sit on top of nothing, since the field
   never carries a second icon on its right */
.city__input::-webkit-search-decoration,
.city__input::-webkit-search-cancel-button{ -webkit-appearance:none; }
.city__input:focus{ outline:none; border-color:var(--brand); }

.city__list{
  max-height:264px; margin-top:12px; padding-right:6px;
  overflow-y:auto;
  /* Firefox's own thin-scrollbar keyword, so it never falls back to the
     full-width default the rest of this rule only fixes for WebKit/Blink */
  scrollbar-width:thin;
  scrollbar-color:var(--n-400) transparent;
}
.city__list::-webkit-scrollbar{ width:5px; }
.city__list::-webkit-scrollbar-track{ background:transparent; }
.city__list::-webkit-scrollbar-thumb{
  background:var(--n-400);
  border-radius:99px;
}
.city__list::-webkit-scrollbar-thumb:hover{ background:var(--n-450); }

.city__item{
  display:block; width:100%;
  padding:9px 10px; border-radius:2px;
  font-size:14px; font-weight:500; text-align:left;
  color:var(--text);
  transition:background .15s ease, color .15s ease;
}
.city__item:hover,
.city__item:focus-visible{ background:var(--surface); color:var(--brand); }
.city__item.is-current{ color:var(--brand); font-weight:700; }
.city__item[hidden]{ display:none; }

.city__empty{ margin-top:12px; font-size:13px; color:var(--text-mute); text-align:center; }
.city__empty[hidden]{ display:none; }

.nav__menu{ display:flex; align-items:center; min-width:0; }
.nav__list{
  display:flex; align-items:center;
  gap:clamp(14px, 1.7vw, 30px);
  flex:0 1 auto;
}
.nav__item{ position:relative; }
.nav__link{
  display:inline-flex; align-items:center; gap:7px;
  padding:6px 0;
  font-size:12px; font-weight:700; text-transform:uppercase;
  white-space:nowrap;
  transition:opacity .18s ease;
}
.nav__link:hover{ opacity:.75; }
/* masked as well — background:currentColor makes it follow the link colour */
.nav__caret{
  flex:none; width:8px; height:4px;   /* matches the icon's 8x4 viewBox */
  background:currentColor;
  -webkit-mask:var(--caret-mask) no-repeat center / contain;
          mask:var(--caret-mask) no-repeat center / contain;
  transition:transform .2s ease;
}
.nav__item.is-open > .nav__link .nav__caret{ transform:rotate(180deg); }

/* script prepends one of these to every screen below the root, but it is
   only ever meant for the full-screen mobile drill-down below — hidden here
   the same way .filters__open is, so it never paints as a bare button on
   a desktop that has no use for it */
.mnav__back{ display:none; }
/* script also appends one .mnav__foot <li> to the root list — same reason,
   same fix: invisible until the mobile menu rule below turns it back on */
.mnav__foot{ display:none; }

.submenu{
  position:absolute; top:100%; left:-18px; z-index:20;
  min-width:250px; padding:10px 0;
  background:var(--n-000);
  box-shadow:0 18px 40px rgba(0,32,66,.18);
  opacity:0; visibility:hidden; transform:translateY(8px);
  transition:opacity .2s ease, transform .2s ease, visibility .2s;
}
.nav__item.is-open > .submenu{ opacity:1; visibility:visible; transform:translateY(0); }
/* :not(--mega) — these would otherwise out-specify .mega__card and force the
   cards back to display:block with a light hover background */
.submenu:not(.submenu--mega) a{
  display:block; padding:9px 22px;
  font-size:14px; color:var(--text);
  transition:background .15s ease, color .15s ease;
}
.submenu:not(.submenu--mega) a:hover,
.submenu:not(.submenu--mega) a[aria-current]{ background:var(--surface); color:var(--brand); }

/* ---------- light header ----------
   Figma node 2232-229. JS sets .is-light when the bar is hovered, when a
   dropdown is open, or when the bar has pinned itself. */
.topbar.is-light .nav__logo-img--on-blue{ opacity:0; }
.topbar.is-light .nav__logo-img--on-white{ opacity:1; }

.topbar.is-light .nav__city{ color:var(--text); }
/* the city picker behaves like any other item in the bar */
.topbar.is-light .city.is-open > .nav__city,
.topbar.is-light .nav__city:hover,
.topbar.is-light .nav__city:focus-visible{ color:var(--brand); opacity:1; }
.topbar.is-light .city.is-open > .nav__city .nav__pin,
.topbar.is-light .nav__city:hover .nav__pin{ background:var(--brand); }
.topbar.is-light .nav__pin{ background:var(--n-400); }

.topbar.is-light .nav__link{ color:var(--text); }
/* Every item lights up the same, whether or not it has a dropdown. The colour
   used to hang off .is-open, which JS only sets on items that have a submenu,
   so «Партнерам» and «Контакты» never turned blue — they just dimmed. */
.topbar.is-light .nav__item.is-open > .nav__link,
.topbar.is-light .nav__link:hover,
.topbar.is-light .nav__link:focus-visible{ color:var(--brand); opacity:1; }

.topbar.is-light .burger span{ background:var(--text); }

@media (min-width:1280px){
  .topbar.is-light .icon-btn{
    background:var(--n-000);
    border:1px solid var(--rail); border-radius:2px;
  }
  .topbar.is-light .icon-btn:hover{ background:var(--surface); }

  .topbar.is-light .nav__contact{
    background:var(--brand); color:var(--text-inv); border-radius:2px;
  }
  .topbar.is-light .nav__contact:hover{ background:var(--b-700); }
  .topbar.is-light .nav__contact img{ filter:brightness(0) invert(1); }
}

/* compact bar: bare icons flip from white to ink */
@media (max-width:1279px){
  .topbar.is-light .icon-btn img,
  .topbar.is-light .nav__contact img{ filter:brightness(0) invert(24%); }
}

/* ---------- mega menu (раздел «Компания») ----------
   Figma node 1931-3015. Cards are --tint by default; the blue card in the
   mock is the :hover state, not a separate variant. */
.nav__item--mega{ position:static; }   /* let the panel anchor to .nav */

.submenu--mega{
  left:calc(50% - 50vw);               /* break out of .shell, full bleed */
  width:100vw;
  min-width:0;
  padding:29px 0 31px;
  box-shadow:0 4px 12px rgba(0,0,0,.04);
  /* a two-row panel is ~550px tall — never let it run past the fold */
  max-height:calc(100vh - var(--topbar-h));
  overflow-y:auto;
}
.mega{
  display:grid;
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:16px;
}
.mega__card{
  position:relative;
  display:flex; flex-direction:column; justify-content:space-between;
  gap:20px;
  min-height:236px;
  padding:23px 30px 27px;
  overflow:hidden;
  background:var(--tint);
  transition:background .25s ease;
}
/* faint grid plate on the right — hidden once the card lights up */
.mega__card::before{
  content:"";
  position:absolute; right:20px; top:0;
  width:379px; height:230px;
  max-width:70%;
  background:url("assets/menu-pattern.svg") no-repeat right top / contain;
  transition:opacity .25s ease;
  pointer-events:none;
}
/* stand-in for the swirl photo in the mock (blend-mode layer, not exported) */
.mega__card::after{
  content:"";
  position:absolute; inset:0;
  opacity:0;
  background:
    radial-gradient(80% 120% at 88% 50%, rgba(255,255,255,.16) 0%, rgba(255,255,255,0) 55%),
    radial-gradient(55% 90% at 72% 108%, rgba(120,220,255,.20) 0%, rgba(120,220,255,0) 60%),
    radial-gradient(60% 100% at 100% 0%, rgba(0,20,90,.30) 0%, rgba(0,20,90,0) 60%);
  transition:opacity .25s ease;
  pointer-events:none;
}
/* Footage behind the card, revealed on hover. Screen-blended at 30% it only
   lightens the blue plate, so no dark scrim is needed to keep the copy legible.
   Sits under the copy, which carries z-index 1. */
.mega__video{
  position:absolute; inset:0; z-index:0;
  width:100%; height:100%;
  object-fit:cover;
  opacity:0;
  mix-blend-mode:screen;
  pointer-events:none;
  transition:opacity .35s ease;
}
.mega__card--video:hover .mega__video,
.mega__card--video:focus-visible .mega__video{ opacity:.3; }

/* A darker plate under the footage — screen blending only lightens, so the
   deeper the base the more the clip reads. Both classes are chained on purpose:
   the generic .mega__card:hover rule sits further down the file and would
   otherwise win on source order. */
.mega__card.mega__card--video:hover,
.mega__card.mega__card--video:focus-visible{ background:var(--b-700); }

.mega__title,
.mega__note{ position:relative; z-index:1; transition:color .25s ease; }

.mega__title{
  max-width:240px;
  font-size:20px; font-weight:600; line-height:1.4;
  color:var(--text);
}
.mega__note{
  max-width:320px;
  font-size:16px; font-weight:500; line-height:1.4;
  color:var(--text-mute);
}

.mega__card:hover,
.mega__card:focus-visible{ background:var(--brand); }
.mega__card:hover::before,
.mega__card:focus-visible::before{ opacity:0; }
.mega__card:hover::after,
.mega__card:focus-visible::after{ opacity:1; }
.mega__card:hover .mega__title,
.mega__card:focus-visible .mega__title{ color:var(--text-inv); }
.mega__card:hover .mega__note,
.mega__card:focus-visible .mega__note{ color:var(--text-inv-soft); }

/* ---------- four-column variant (раздел «Оборудование») ----------
   Figma 2240-282. Same panel and plate treatment, but each column holds a
   heading plus a list instead of one title/note pair. The blue column in the
   mock is again the :hover state. */
.mega--cols{
  grid-template-columns:repeat(4, minmax(0, 1fr));
  gap:18px;
}
.mega__col{
  position:relative;
  min-height:468px;
  padding:34px 36px 30px;
  overflow:hidden;
  background:var(--tint);
  transition:background .25s ease;
}
.mega__col::before{
  content:"";
  position:absolute; right:0; top:0;
  width:325px; height:223px;
  max-width:80%;
  background:url("assets/menu-pattern.svg") no-repeat right top / contain;
  transition:opacity .25s ease;
  pointer-events:none;
}
/* focus-within so keyboard users get the same lit column, otherwise the white
   text below would land on the resting grey */
.mega__col:hover,
.mega__col:focus-within{ background:var(--b-400); }
.mega__col:hover::before,
.mega__col:focus-within::before{ opacity:.35; }

.mega__col-title,
.mega__links,
.mega__rich{ position:relative; z-index:1; }

.mega__col-title{
  display:flex; align-items:center; gap:10px;
  margin-bottom:24px;
  font-size:20px; font-weight:500; line-height:1.4;
  color:var(--text);
  transition:color .25s ease;
}
.mega__badge{ flex:none; width:20px; }

/* plain link list */
.mega__links a{
  display:block;
  font-size:16px; font-weight:600; line-height:36px;
  color:var(--text);
  transition:color .2s ease;
}

/* list of title + description pairs */
/* extra air under the column heading before the first sub-item */
.mega__rich{ display:grid; gap:40px; margin-top:34px; }
.mega__rich-title{
  display:block;
  font-size:16px; font-weight:600; line-height:1.2;
  color:var(--text);
  transition:color .2s ease;
}
.mega__rich-note{
  display:block; margin-top:12px;
  font-size:15px; line-height:1.4;
  color:var(--text-mute);
  transition:color .25s ease;
}
/* Item hover: a colour shift, never an underline. On a resting (grey) column
   that means the brand blue; once the column itself is lit, the shift has to
   go the other way — a light tint against the blue. */
.mega__links a:hover,
.mega__links a:focus-visible,
.mega__rich a:hover .mega__rich-title,
.mega__rich a:focus-visible .mega__rich-title{ color:var(--brand); }

/* everything flips to white once the column lights up */
.mega__col:hover .mega__col-title,
.mega__col:focus-within .mega__col-title,
.mega__col:hover .mega__links a,
.mega__col:focus-within .mega__links a,
.mega__col:hover .mega__rich-title,
.mega__col:focus-within .mega__rich-title{ color:var(--text-inv); }
.mega__col:hover .mega__rich-note,
.mega__col:focus-within .mega__rich-note{ color:var(--text-inv-soft); }

/* the item actually under the pointer, on the lit column */
.mega__col:hover .mega__links a:hover,
.mega__col:focus-within .mega__links a:focus-visible,
.mega__col:hover .mega__rich a:hover .mega__rich-title,
.mega__col:focus-within .mega__rich a:focus-visible .mega__rich-title{ color:var(--text-inv-key); }

.nav__tools{ display:flex; align-items:center; gap:4px; margin-left:clamp(18px, 3vw, 74px); }

.icon-btn{
  display:grid; place-items:center;
  width:41px; height:40px;
  background:var(--tint);
  transition:background .18s ease;
}
.icon-btn:hover{ background:var(--n-000); }
.icon-btn img{ width:16px; }

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.02em;
  transition:background .18s ease, color .18s ease, transform .18s ease;
}
.btn--light{ height:40px; padding:0 16px; background:var(--tint); color:var(--text); }
/* the page's primary action, so it carries more weight than the bar's call:
   a taller box on a wider measure, the label one step up */
.btn--quote{
  height:48px; min-width:180px; padding:0 26px;
  font-size:12px;
}
.btn--light:hover{ background:var(--n-000); }
.nav__contact{ gap:12px; }
.nav__contact img{ width:19px; }
.btn--wide{
  flex:none;                     /* never squeezed — the copy narrows instead */
  width:227px; max-width:100%;
  padding:0 14px; gap:12px; justify-content:flex-start;
}
.btn--wide img,
.btn--wide .btn__lock{ width:22px; flex:none; }
.btn--wide > span:not(.btn__lock){ flex:1; text-align:center; }

/* burger (mobile only) */
.burger{
  display:none;
  width:40px; height:40px;
  padding:12px 9px;              /* glyph 22 wide, matching the other icons */
  flex-direction:column; justify-content:space-between;
}
.burger span{ display:block; height:1px; background:var(--n-000); border-radius:1px; transition:transform .25s ease, opacity .2s ease, background-color .25s ease; }
.burger.is-open span:nth-child(1){ transform:translateY(7.5px) rotate(45deg); }
.burger.is-open span:nth-child(2){ opacity:0; }
.burger.is-open span:nth-child(3){ transform:translateY(-7.5px) rotate(-45deg); }

/* ---------- breadcrumbs ---------- */
/* One trail, two skins: .breadcrumbs rides the blue hero, .crumbs the white
   pages. Type, weight and the gap between the crumbs are the same in both, so
   the line reads identically wherever it appears. */
.breadcrumbs{
  display:flex; align-items:center; flex-wrap:wrap;
  gap:16px;
  margin-top:12px;
  font-size:12px; font-weight:500; color:var(--b-crumb);
}
.breadcrumbs a:hover{ color:var(--text-inv); }
.breadcrumbs__sep{ opacity:.8; }

/* ---------- hero body ---------- */
.hero__body{
  flex:1; display:flex; flex-direction:column;
  margin-left:var(--col-text);   /* same vertical line as the partner copy */
  padding-top:clamp(26px, 3.4vw, 56px);
}
.hero__title{
  max-width:764px;
  font-size:clamp(38px, 4.86vw, 84px);
  font-weight:500;
  line-height:.976;
  letter-spacing:-.03em;
}
.hero__foot{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:clamp(24px, 4vw, 70px);
  /* auto keeps the copy anchored to the foot of the hero at any block height */
  margin-top:auto; padding-top:clamp(40px, 6vw, 120px);
}
.hero__lead{
  max-width:515px;
  font-size:15px; font-weight:600; line-height:1.73;
  color:var(--text-inv-soft);
}

/* =========================================================
   PARTNERS
   ========================================================= */
.partners{ padding:clamp(48px, 5vw, 79px) 0 clamp(40px, 4vw, 60px); }

.partner{
  display:grid;
  grid-template-columns:var(--c-num) var(--c-logo) var(--c-gap) var(--c-body);
  align-items:start;
  margin-bottom:clamp(40px, 3.3vw, 55px);
}
.partner__num{
  grid-column:1;
  font-size:clamp(16px, 1.16vw, 20px); font-weight:500;
  letter-spacing:-.03em; color:var(--num);
  padding-top:1px;
}
.partner__logo{
  grid-column:2;
  display:grid; place-items:center;
  align-self:stretch;            /* grows with the copy so both columns end level */
  min-height:334px; padding:24px;
  background:var(--surface);
}
.partner__logo img{
  width:clamp(120px, 13.6vw, 228px);
  filter:grayscale(1);
  transition:filter .3s ease;
}
.partner__logo:hover img,
.partner__logo:focus-within img{ filter:none; }

.partner__body{
  grid-column:4;
  display:flex; flex-direction:column; align-items:flex-start;
  padding-top:20px;              /* gap between the grey rule and the title */
  border-top:1px solid var(--tint);
  min-height:334px;
}
.partner__title{
  font-size:clamp(24px, 1.85vw, 32px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
  color:var(--text);
}
.partner__title sup{ font-size:.645em; line-height:0; vertical-align:super; }

.partner__text{
  max-width:901px;
  margin-top:22px;
  font-size:15px; font-weight:500; line-height:1.27; letter-spacing:-.03em;
  color:var(--text-body);
}
.partner__subtitle{
  max-width:777px;
  margin-top:24px;
  font-size:15px; font-weight:500; line-height:1.27; letter-spacing:-.03em;
  color:var(--text);
}
.partner__list{ max-width:777px; margin-top:8px; }
.partner__list li{
  position:relative;
  padding-left:18px;
  font-size:15px; font-weight:500; line-height:1.95; letter-spacing:-.03em;
  color:var(--text);
}
.partner__list li::before{ content:"—"; position:absolute; left:0; }

.partner__link{
  display:inline-flex; align-items:center; gap:14px;
  /* auto pushes the link to the bottom of the column, so it lines up with the
     lower edge of the grey logo plate next to it */
  margin-top:auto; padding-top:26px;
  font-size:15px; font-weight:500; letter-spacing:-.03em;
  color:var(--link);
  transition:color .18s ease;
}
.partner__link img{ width:20px; flex:none; }
.partner__link span{ border-bottom:1px solid transparent; transition:border-color .18s ease; }
.partner__link:hover{ color:var(--brand); }
.partner__link:hover span{ border-bottom-color:currentColor; }

/* ---------- pagination ---------- */
.pager{
  display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap;
  gap:20px;
  margin-left:var(--col-text);
  margin-top:clamp(30px, 3vw, 50px);
}
.pager__nav{ display:flex; align-items:center; gap:9px; }
/* WooCommerce renders one flat <ul class="page-numbers"> holding the arrows
   and the digits, so the list carries the whole row. */
.pager__list{ display:flex; align-items:center; gap:9px; }
.pager__btn{
  display:grid; place-items:center;
  width:33px; height:32px;
  border-radius:2px; background:var(--surface);
  font-size:15px; font-weight:600; color:var(--text-mute);
  transition:background .18s ease, color .18s ease;
}
.pager__btn:not(.current):hover{ background:var(--tint); }
/* .current is WooCommerce’s name for the page you are on */
.pager__btn.is-active,
.pager__btn.current{ background:var(--brand); color:var(--text-inv); }
.pager__arrow{
  display:grid; place-items:center;
  width:33px; height:32px;
  border-radius:2px; background:var(--surface);
  transition:background .18s ease, opacity .18s ease;
}
.pager__arrow img{ width:auto; height:9px; }
.pager__arrow:hover{ background:var(--tint); }
.pager__arrow:disabled,
.pager__arrow.is-disabled{ background:var(--surface); opacity:.35; cursor:default; pointer-events:none; }
.pager__count{ font-size:12px; font-weight:500; color:var(--text-mute); }

/* =========================================================
   PHOTO BAND
   ========================================================= */
.band{ margin:0; line-height:0; }
.band img{ width:100%; height:auto; object-fit:cover; }
/* The clip is 16:9 but the band is a wide strip, so it is cropped rather than
   letterboxed. aspect-ratio reserves the box before any byte is fetched, so
   swapping the photo for video costs no layout shift. */
.band__video{
  display:block;
  width:100%; height:auto;
  aspect-ratio:1738 / 598;
  object-fit:cover;
  /* the crop window sits below centre, which lifts the picture inside the
     strip — the strip itself does not move */
  object-position:center var(--band-focus);
  background:var(--b-900);
  /* no interface: nothing to click, nothing to focus, no context menu */
  pointer-events:none;
}
.band__video::-webkit-media-controls,
.band__video::-webkit-media-controls-enclosure,
.band__video::-webkit-media-controls-panel,
.band__video::-webkit-media-controls-start-playback-button{
  display:none !important;
  -webkit-appearance:none;
}


/* ---------- footer grid lines (Figma 2246-311) ----------
   Four full-bleed hairlines. Rows A–C break where the two vertical guides
   cross them; row D runs solid edge to edge. The breaks are painted as
   transparent stops in one gradient, which keeps each row a single element. */
.gridline{
  position:relative;
  left:calc(50% - 50vw); width:100vw;
  height:1px;
  background:linear-gradient(to right,
    var(--fl) 0,
    var(--fl) calc(var(--tick-x1) - 17px),
    transparent calc(var(--tick-x1) - 17px),
    transparent calc(var(--tick-x1) + 17px),
    var(--fl) calc(var(--tick-x1) + 17px),
    var(--fl) calc(var(--tick-x2) - 22px),
    transparent calc(var(--tick-x2) - 22px),
    transparent calc(var(--tick-x2) + 18px),
    var(--fl) calc(var(--tick-x2) + 18px),
    var(--fl) 100%);
}
/* rows C and D break only at the second guide */
.gridline--gap1{
  background:linear-gradient(to right,
    var(--fl) 0,
    var(--fl) calc(var(--tick-x2) - 22px),
    transparent calc(var(--tick-x2) - 22px),
    transparent calc(var(--tick-x2) + 18px),
    var(--fl) calc(var(--tick-x2) + 18px),
    var(--fl) 100%);
}
/* Row A sits at a fixed offset from the section top, above the flow. It has to
   keep the same 100vw box as the in-flow rows: 100% of .cons excludes the
   scrollbar while 100vw includes it, and --tick-x* would then resolve to two
   different columns — the ticks above and below a row visibly split apart. */
.gridline--top{
  position:absolute; top:137px;
  left:calc(50% - 50vw); width:100vw;
  z-index:0; pointer-events:none;
}

/* vertical ticks hanging off a row — 1px stripes drawn as background layers so
   no extra elements are needed */
.gridline--tick1::after,
.gridline--tick2::after{
  content:"";
  position:absolute; left:0; right:0;
  height:377px;
  pointer-events:none;
}
.gridline--tick2::after{
  background:
    linear-gradient(var(--fl), var(--fl)) var(--tick-x1) 0 / 1px 100% no-repeat,
    linear-gradient(var(--fl), var(--fl)) var(--tick-x2) 0 / 1px 100% no-repeat;
}
/* row D */
.gridline--tick1::after{
  top:calc(-35px - var(--tick-lift) - var(--tick-lift-d));
  background:linear-gradient(var(--fl), var(--fl)) var(--tick-x2) 0 / 1px 100% no-repeat;
}
/* the top row's ticks are the short 122px pair */
/* row B — the middle pair */
.gridline--tick2::after{ top:calc(-1 * var(--tick-h-b)); height:var(--tick-h-b); }
/* row A — the short pair at the very top of the block */
.gridline--top.gridline--tick2::after{ top:calc(-15px - var(--tick-lift)); height:122px; }

/* =========================================================
   CONSULTATION + FOOTER
   ========================================================= */
.cons{
  position:relative;
  margin-top:calc(-1 * var(--steps-h));
  padding-top:calc(clamp(40px, 4vw, 68px) + var(--steps-h));
  /* 7 columns of 1/7 each; the steps rise 0, half or all of --steps-h */
  clip-path:polygon(
    0 var(--step-1), 14.29% var(--step-1), 14.29% 0, 28.57% 0,
    28.57% var(--steps-h), 42.86% var(--steps-h), 42.86% var(--step-1), 57.14% var(--step-1),
    57.14% var(--step-2), 71.43% var(--step-2), 71.43% var(--steps-h), 85.71% var(--steps-h),
    85.71% var(--step-1), 100% var(--step-1), 100% 100%, 0 100%);
  color:var(--text-inv);
  /* matches the first animated layer, so there is no jump on mount */
  background:radial-gradient(130% 100% at 22% 108%, var(--a-teal) 0%, var(--b-500) 44%, var(--b-900) 100%);
  overflow:hidden;
}
/* the footer blocks are a level deeper now that they sit in <footer> */
.cons .shell{ position:relative; z-index:1; }

.cons__grid{
  display:grid;
  grid-template-columns:var(--col-text) 1fr;
  padding-bottom:clamp(32px, 3.8vw, 66px);
}
/* second half of the block: same columns, but the intro row already
   carried the logo, so this one only holds the form */
.cons__grid--form{ padding-top:clamp(34px, 4.7vw, 82px); }
/* the tag row above row A */
.cons__grid--intro{ padding-bottom:clamp(30px, 3.4vw, 58px); }
.cons__grid--intro .cons__aside{ margin-bottom:0; }
.cons__grid--form .cons__formtitle{ margin-top:0; }
.cons__aside{ grid-column:1; }
.cons__logo{ display:block; margin-top:40px; }
.cons__logo img{ width:clamp(112px, 8.7vw, 150px); }
.cons__main{ grid-column:2; min-width:0; }

.section-tag{
  display:flex; align-items:center; gap:12px;
  font-size:15px; font-weight:500; letter-spacing:-.03em;
}


.cons__title{
  max-width:738px;
  margin-top:clamp(20px, 2.6vw, 45px);
  font-size:clamp(38px, 5.44vw, 94px);
  font-weight:500; line-height:.873; letter-spacing:-.03em;
}
.cons__copy{
  display:grid;
  grid-template-columns:minmax(0, 384px) minmax(0, 406px);
  gap:clamp(28px, 6vw, 104px);
  margin-top:clamp(24px, 2.4vw, 42px);
  padding-bottom:0;
}
.cons__lead{
  font-size:clamp(18px, 1.4vw, 24px);
  font-weight:500; line-height:1.3; letter-spacing:-.03em;
}
.cons__note{
  font-size:15px; font-weight:500; line-height:1.55; letter-spacing:-.03em;
  color:var(--text-inv-dim);
}

.cons__formtitle{
  margin-top:clamp(34px, 4.7vw, 82px);
  font-size:16px; font-weight:600; text-transform:uppercase; letter-spacing:-.03em;
}

/* Online indicator: a solid dot with a ring that pulses outward, so the
   "Обратная связь" label reads as a live status rather than a bullet. */
.status-dot{
  position:relative;
  flex:none;
  width:6px; height:6px;
  border-radius:50%;
  background:var(--a-online);
}
.status-dot::before,
.status-dot::after{
  content:"";
  position:absolute; inset:0;
  border-radius:50%;
  border:1px solid var(--a-online);
  animation:status-pulse 2.4s cubic-bezier(.2,.6,.35,1) infinite;
}
.status-dot::after{ animation-delay:1.2s; }
@keyframes status-pulse{
  0%   { transform:scale(1);   opacity:.85; }
  70%  { transform:scale(3.6); opacity:0; }
  100% { transform:scale(3.6); opacity:0; }
}

/* ---------- form ---------- */
.form{ max-width:894px; margin-top:clamp(24px, 2.5vw, 42px); }
.field{ position:relative; padding-bottom:22px; }
.field input{
  width:100%;
  padding:6px 0 12px;
  color:var(--text-inv);
  background:none;
  border:0; border-bottom:1px solid rgba(255,255,255,.3);
  font-size:15px; font-weight:500; letter-spacing:-.03em;
  transition:border-color .18s ease;
}
.field input::placeholder{ color:rgba(255,255,255,.39); }
.field input:hover{ border-bottom-color:rgba(255,255,255,.55); }
.field input:focus{ outline:none; border-bottom-color:var(--text-inv); }
.field.has-error input{ border-bottom-color:var(--a-danger); }
.field__error{
  position:absolute; left:0; bottom:3px;
  font-size:12px; color:var(--a-danger);
  opacity:0; transition:opacity .18s ease;
}
.field.has-error .field__error{ opacity:1; }

.btn--submit{
  width:100%; height:58px;
  margin-top:14px;
  background:var(--n-000); color:var(--text);
  font-size:13px; letter-spacing:-.01em;
}
.btn--submit:hover{ background:var(--text-inv-key); }
.btn--submit:disabled{ opacity:.6; cursor:progress; }

.check{
  position:relative;
  display:flex; align-items:flex-start; gap:12px;
  margin-top:22px;
  cursor:pointer;
}
/* the native box stays hit-testable — it just sits invisibly over its skin */
.check input{
  position:absolute; left:0; top:1px;
  width:18px; height:18px; margin:0;
  opacity:0; cursor:pointer;
}
.check__box{
  flex:none;
  display:grid; place-items:center;
  width:18px; height:18px; margin-top:1px;
  border:1px solid var(--text-inv); border-radius:2px;
  pointer-events:none;             /* clicks fall through to the real input */
  transition:background .18s ease, border-color .18s ease;
}
.check__box img{ width:8px; opacity:0; transition:opacity .15s ease; }
.check input:checked + .check__box img{ opacity:1; }
.check input:focus-visible + .check__box{ outline:2px solid var(--text-inv); outline-offset:3px; }
.check.has-error .check__box{ border-color:var(--a-danger); }
.check__text{
  font-size:13px; font-weight:500; line-height:1.23; letter-spacing:-.03em;
  color:rgba(255,255,255,.39);
}
.check__text a{ text-decoration:underline; }
.check__text a:hover{ color:var(--text-inv); }

.form__status{
  min-height:20px; margin-top:14px;
  font-size:14px; font-weight:600;
}
.form__status.is-ok{ color:var(--b-200); }
.form__status.is-bad{ color:var(--a-danger); }

/* ---------- footer ---------- */
.foot{
  display:grid;
  grid-template-columns:var(--col-text) 1fr;
  gap:clamp(32px, 3vw, 48px) 0;
  padding-top:clamp(30px, 3vw, 53px);
  padding-bottom:clamp(18px, 1.5vw, 25px);
}
.foot__contacts{ grid-column:1; }
.foot__phone + .foot__phone{ margin-top:clamp(16px, 1.2vw, 18px); }
.foot__label{
  display:block; margin-bottom:10px;
  font-size:14px; font-weight:500; letter-spacing:-.03em;
  color:var(--text-inv-key);
}
.foot__phone a{
  font-size:clamp(24px, 2.08vw, 36px); font-weight:500; letter-spacing:-.03em;
  transition:color .18s ease;
}
.foot__phone a:hover{ color:var(--b-200); }

.foot__social{ display:flex; gap:8px; margin-top:clamp(22px, 1.8vw, 28px); }
.foot__social a{ transition:transform .18s ease, opacity .18s ease; }
.foot__social a:hover{ transform:translateY(-2px); opacity:.85; }
.foot__social img{ width:47px; }

.foot__addr{
  margin-top:clamp(26px, 3.1vw, 52px);
  font-size:14px; font-style:normal; font-weight:500; line-height:1.6; letter-spacing:-.03em;
}
.foot__addr a{ display:block; margin-top:4px; color:var(--b-200); }
.foot__addr a:hover{ text-decoration:underline; }

.foot__cols{
  grid-column:2;
  display:grid;
  grid-template-columns:32.4% 41% 26.6%;
  gap:30px 0;
}
.foot__head{
  margin-bottom:22px;
  font-size:12px; font-weight:700; text-transform:uppercase;
}
.foot__col li a{
  display:block; padding:5px 0;
  font-size:14px; font-weight:500; line-height:1.4;
  color:var(--text-inv-key);
  transition:color .18s ease;
}
.foot__col li a:hover,
.foot__col li a.is-current{ color:var(--text-inv); }

/* ---------- bottom bar ---------- */
.bottom{
  display:grid;
  grid-template-columns:var(--col-text) 1fr;
  align-items:center;
  padding:20px 0 26px;           /* extra 10px drops the line off row D */
  font-size:12px; font-weight:600; letter-spacing:-.03em;
}
.bottom__copy{ padding-right:24px; }
.bottom__rest{
  display:flex; align-items:center; flex-wrap:wrap;
  gap:14px clamp(24px, 4vw, 60px);
}
.bottom__link{ transition:opacity .18s ease; }
.bottom__link:hover{ opacity:.75; text-decoration:underline; }
.bottom__rits{ margin-left:auto; }
.bottom__rits img{ width:53px; }

/* =========================================================
   RESPONSIVE
   ========================================================= */

/* Between the burger breakpoint and ~1660px the six nav links no longer fit in
   the 60% track and used to run under the search / contact buttons. The brand
   column gives up its fixed --col-text width there and the menu right-aligns. */
@media (max-width:1679px) and (min-width:1280px){
  .nav{ grid-template-columns:auto 1fr auto; }
  .nav__menu{ justify-content:flex-end; }
  .nav__list{ gap:clamp(12px, 1.4vw, 30px); }
}

/* — laptops: nav gets tight, drop to the burger — */
@media (max-width:1279px){
  /* brand left, burger right — the text column no longer drives the header */
  .nav{ position:relative; grid-template-columns:1fr auto; }
  .burger{ display:flex; grid-column:2; justify-self:end; }

  /* Full-screen drill-down: the panel takes the whole screen under the bar,
     and everything in it — the top-level list, each mega submenu, and (one
     level deeper) each equipment group — is one of a stack of full-screen
     screens rather than an accordion that grows the page. Nothing here is
     duplicate markup; the desktop mega menu's own DOM is what gets restyled,
     and script.js drives which screen is current via [data-mnav].
     Every rule below is prefixed with #menu on purpose: the desktop rules it
     is overriding (.mega__card, .submenu--mega, .mega__col…) are themselves
     single classes, so without the extra id this whole block would depend on
     staying physically below them in the file — true today, but one paste
     from breaking. The id makes the win unconditional. */
  #menu{
    position:fixed; left:0; right:0; top:var(--topbar-h); bottom:0; z-index:40;
    display:block; flex:none;
    padding:0;
    background:var(--n-000);
    opacity:0; visibility:hidden;
    transition:opacity .22s ease, visibility 0s linear .22s;
  }
  #menu.is-open{ opacity:1; visibility:visible; transition:opacity .22s ease; }

  /* Compact header: search and the CTA drop their chip background and label and
     become bare white vectors, matching the burger's three bars. The 40px box is
     kept for the tap target — only the paint goes away. */
  .nav__tools{ grid-column:2; justify-self:end; margin-left:0; gap:2px; }
  .icon-btn,
  .nav__contact{
    width:40px; height:40px;
    padding:0; gap:0;
    background:none;
    justify-content:center;
  }
  .icon-btn:hover,
  .nav__contact:hover{ background:none; opacity:.7; }
  /* one 22x22 box for search, headset and burger alike */
  .icon-btn img,
  .nav__contact img{
    width:22px; height:22px; object-fit:contain;
    filter:brightness(0) invert(1);   /* dark source SVGs → white on the blue bar */
  }
  .nav__contact-label{ display:none; }
  /* screen 0: the root list, always underneath — nothing ever transforms it,
     an incoming screen simply covers it */
  #menu .nav__list{
    position:absolute; inset:0;
    display:block; width:100%; margin:0;
    overflow-y:auto; -webkit-overflow-scrolling:touch;
  }
  #menu .nav__item{ position:static; border-bottom:0; }   /* .submenu anchors to .nav__list instead of the row */
  #menu .nav__link{
    width:100%; justify-content:space-between; gap:12px;
    height:56px; padding:0 var(--pad);
    border-top:1px solid var(--tint);
    font-size:15.5px; font-weight:600; letter-spacing:normal; text-transform:none;
    color:var(--text);
  }
  #menu .nav__list > .nav__item:last-child > .nav__link{ border-bottom:1px solid var(--tint); }
  #menu .nav__item:not(.has-sub) .nav__caret{ display:none; }
  /* the desktop caret points down for a dropdown; here it points at the next
     screen, so it borrows the site's one arrow glyph instead */
  #menu .nav__caret{
    width:9px; height:7px;
    background:var(--n-450);
    -webkit-mask:var(--arrow-mask) no-repeat center / contain;
            mask:var(--arrow-mask) no-repeat center / contain;
    transition:none; transform:none;
  }
  #menu .nav__item.is-open > .nav__link .nav__caret{ transform:none; }   /* undo the desktop rotate-on-open */

  /* screens 1+: every submenu is a full screen of its own, off to the right
     until it is pushed onto the stack, and parked off to the left once the
     visitor has drilled past it */
  #menu .submenu{
    position:absolute; inset:0; z-index:1;
    display:block; width:auto;
    min-width:0; max-height:none; padding:0;
    background:var(--n-000); box-shadow:none;
    opacity:1; visibility:visible;
    overflow-y:auto; -webkit-overflow-scrolling:touch;
    transform:translateX(100%);
    transition:transform .34s cubic-bezier(.32,.72,0,1);
  }
  #menu .submenu[data-mnav="active"]{ transform:translateX(0); z-index:2; }
  #menu .submenu[data-mnav="prev"]{ transform:translateX(-100%); }

  /* the back row script prepends to every screen below the root — its label
     is copied from whatever trigger opens that screen, so the two can never
     say different things */
  #menu .mnav__back{
    display:flex; align-items:center; gap:10px;
    width:100%; height:52px; padding:0 var(--pad);
    border:0; border-bottom:1px solid var(--tint); background:none; text-align:left;
  }
  #menu .mnav__back-arrow{
    flex:none; width:9px; height:7px;
    background:var(--n-450);
    -webkit-mask:var(--arrow-mask) no-repeat center / contain;
            mask:var(--arrow-mask) no-repeat center / contain;
    transform:scaleX(-1);
  }
  #menu .mnav__back span{ font-size:13px; font-weight:600; color:var(--n-450); }

  /* the "Связаться с нами" row script appends after the real nav items —
     a call to action, not a list row, so it breaks the row rhythm on purpose */
  #menu .mnav__foot{ display:block; padding:20px var(--pad) 24px; border-top:1px solid var(--tint); }
  #menu .mnav__cta{
    display:flex; align-items:center; justify-content:center;
    height:46px; border-radius:2px;
    background:var(--brand); color:var(--text-inv);
    font-size:13px; font-weight:700; letter-spacing:.02em; text-transform:uppercase;
    text-decoration:none;
  }

  /* flatten the desktop grid to one column of rows; the watermark plates,
     hover video and blue fill are a desktop-hover idea and drop entirely */
  #menu .mega{ display:block; width:auto; padding:0; }
  #menu .mega--cols{ display:block; }
  #menu .mega__col::before,
  #menu .mega__card::before,
  #menu .mega__card::after,
  #menu .mega__video{ display:none; }
  #menu .mega__col{ min-height:0; padding:0; overflow:visible; background:none; }
  #menu .mega__col:hover,
  #menu .mega__col:focus-within{ background:none; }

  #menu .mega__card,
  #menu .mega__links a,
  #menu .mega__rich > li > a{
    display:flex; flex-direction:row; align-items:center; justify-content:space-between; gap:12px;
    width:100%; min-height:0; height:54px; padding:0 var(--pad);
    border-top:1px solid var(--tint);
    font-size:15.5px; font-weight:500; line-height:1.3; text-align:left;
    background:none;
    color:var(--text);
  }
  #menu .mega .mega__card:last-child,
  #menu .mega__links li:last-child a,
  #menu .mega__rich li:last-child a{ border-bottom:1px solid var(--tint); }
  #menu .mega__title{ max-width:none; margin:0; font-size:15.5px; font-weight:500; color:var(--text); }
  #menu .mega__note,
  #menu .mega__rich-note{ display:none; }   /* the long hover copy is desktop-only */

  /* Оборудование's four groups stay ordinary rows in normal flow — .mega__col
     itself is never touched by [data-mnav] and never becomes position:absolute.
     Toggling position on the row would have made it the odd one out: position
     cannot be transitioned, so it would have snapped into place instead of
     sliding, and worse, snapped in from whichever side its static, in-flow
     geometry happened to leave it, not necessarily the right. The screen that
     actually slides is .mega__links/.mega__rich — always position:absolute,
     exactly like .submenu, so it behaves exactly like .submenu. */
  #menu .mega--cols{ position:static; }
  #menu .mega--cols .mega__col{
    position:static;
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    height:54px; padding:0 var(--pad);
    border-top:1px solid var(--tint);
  }
  #menu .mega--cols .mega__col:last-child{ border-bottom:1px solid var(--tint); }
  #menu .mega__col-title{
    flex:1; min-width:0;
    display:flex; align-items:center; gap:10px;
    margin:0; font-size:15.5px; font-weight:500; line-height:1.3; text-align:left;
    color:var(--text);
  }
  #menu .mega__badge{ width:18px; }
  #menu .mega--cols .mega__col::after{
    content:"";
    flex:none; width:9px; height:7px;
    background:var(--n-450);
    -webkit-mask:var(--arrow-mask) no-repeat center / contain;
            mask:var(--arrow-mask) no-repeat center / contain;
  }

  /* the actual screen — same recipe as #menu .submenu, just one level deeper */
  #menu .mega__links,
  #menu .mega__rich{
    position:absolute; inset:0; z-index:1;
    display:block; margin:0;
    background:var(--n-000);
    overflow-y:auto; -webkit-overflow-scrolling:touch;
    transform:translateX(100%);
    transition:transform .34s cubic-bezier(.32,.72,0,1);
  }
  #menu .mega__links[data-mnav="active"],
  #menu .mega__rich[data-mnav="active"]{ transform:translateX(0); z-index:2; }
  #menu .mega__links[data-mnav="prev"],
  #menu .mega__rich[data-mnav="prev"]{ transform:translateX(-100%); }

  @media (prefers-reduced-motion:reduce){
    #menu,
    #menu.is-open,
    #menu .submenu,
    #menu .mega__links[data-mnav],
    #menu .mega__rich[data-mnav]{ transition:none; }
  }
}

/* At 1125px and below the lead wraps onto a fourth line, so the hairline has to
   sit one line higher to keep the same air above the copy. Boundary measured,
   not guessed — a rounder number leaves a visible jump at the seam. */
@media (max-width:1125px){
  :root{ --rule-y:182px; }
}

/* — tablets — */
@media (max-width:1023px){
  :root{ --pad:20px; --steps-h:96px; }

  .hero{ min-height:0; padding-bottom:44px; }
  .hero__rules{ display:none; }
  .hero__body{ margin-left:0; }
  .hero__title{ max-width:none; }
  .hero__foot{ align-items:flex-start; }

  /* partner row: logo left, copy right; number rides above the copy */
  .partner{
    grid-template-columns:minmax(180px, 30%) 1fr;
    gap:0 clamp(24px, 4vw, 56px);
  }
  .partner__num{
    grid-column:2; grid-row:1;
    margin-bottom:10px;
    font-size:16px;
  }
  .partner__logo{ grid-column:1; grid-row:1 / span 2; align-self:start; height:auto; min-height:0; aspect-ratio:394/334; }
  .partner__body{ grid-column:2; grid-row:2; min-height:0; }

  .pager{ margin-left:0; }

  .cons__grid,
  .foot{ grid-template-columns:1fr; }
  .cons__aside,
  .cons__main,
  .foot__contacts,
  .foot__cols{ grid-column:1; }
  .cons__aside{ margin-bottom:36px; }

  /* The vertical ticks belong to the desktop grid only. With them gone the
     breaks in the horizontal rows have nothing to make way for — they just
     read as gaps in mid-air, and rows A/B (two breaks) stop lining up with
     rows C/D (one). So the rows go solid here. */
  .gridline--tick1::after,
  .gridline--tick2::after{ display:none; }
  .gridline--top{ display:none; }
  .gridline,
  .gridline--gap1{ background:var(--fl); }
  .foot__cols{ grid-template-columns:repeat(2, minmax(0,1fr)); gap:34px 24px; }
}

/* — phones — */
@media (max-width:767px){
  :root{ --pad:16px; --steps-h:64px; }
  body{ font-size:14px; }

  :root{ --topbar-h:64px; --subbar-h:64px; }
  .nav{ min-height:64px; padding:12px 0; }
  .nav__city{ font-size:11px; }
  /* the panel would rather anchor to the pin, but on a phone the trigger can
     sit close enough to the left edge that a 320px card runs off the right —
     so here it un-anchors and flushes to the page padding instead, straight
     under the bar, the same way the mega menu already goes full-bleed */
  .city__panel{
    position:fixed; top:var(--topbar-h); left:var(--pad); right:var(--pad);
    width:auto; max-width:none;
  }
  .breadcrumbs{ gap:8px; }

  .hero__foot{ flex-direction:column; gap:28px; margin-top:34px; }
  .hero__lead{ font-size:14px; line-height:1.6; }
  .btn--wide{ width:100%; }

  .partners{ padding-top:34px; }
  .partner{ grid-template-columns:1fr; }
  .partner__num{ grid-column:1; grid-row:1; margin-bottom:8px; }
  .partner__logo{
    grid-column:1; grid-row:2;
    aspect-ratio:auto; height:150px; padding:20px;
    margin-bottom:20px;
  }
  .partner__logo img{ width:min(60%, 180px); }
  .partner__body{ grid-column:1; grid-row:3; }
  .partner__text,
  .partner__subtitle,
  .partner__list li{ font-size:14px; }
  .partner__list li{ line-height:1.6; margin-top:8px; }

  .pager{ justify-content:center; }
  .pager__nav{ gap:5px; }
  .pager__list{ gap:5px; }
  .pager__btn,
  .pager__arrow{ width:30px; height:30px; }
  .pager__count{ width:100%; text-align:center; }

  .band img{ height:230px; }

  .cons__copy{ grid-template-columns:1fr; }
  .btn--submit{ height:52px; }

  /* footer link groups become accordions */
  .foot__cols{ grid-template-columns:1fr; gap:0; }
  .foot__col{ border-bottom:1px solid rgba(255,255,255,.16); }
  .foot__head{
    display:flex; align-items:center; justify-content:space-between;
    margin:0; padding:16px 0;
    cursor:pointer;
  }
  .foot__head::after{
    content:""; flex:none;
    width:9px; height:9px; margin-left:12px;
    border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
    transform:translateY(-3px) rotate(45deg);
    transition:transform .25s ease;
  }
  .foot__col.is-open .foot__head::after{ transform:translateY(1px) rotate(-135deg); }
  .foot__col ul{ max-height:0; overflow:hidden; transition:max-height .3s ease; }
  .foot__col.is-open ul{ max-height:400px; padding-bottom:12px; }

  /* stacked bottom bar reads better centred than ragged-left */
  .bottom{ grid-template-columns:1fr; gap:12px; justify-items:center; text-align:center; }
  .bottom__copy{ padding-right:0; }
  .bottom__rest{ flex-direction:column; align-items:center; gap:12px; }
  .bottom__rits{ margin:6px 0 0; }
}

/* — very narrow phones — the city name always stays; the room comes from the
     logo, the gaps and the icon boxes instead — */
@media (max-width:379px){
  /* the anchor carries the clamp() width, so shrinking only the <img> did
     nothing for the layout — the brand block stayed 96px wide */
  .nav__logo{ width:80px; }
  .nav__brand{ gap:10px; }
  .nav__city{ gap:5px; font-size:10px; }
  .nav__tools{ gap:0; }
  .icon-btn,
  .nav__contact{ width:36px; }
  .icon-btn img,
  .nav__contact img{ width:20px; height:20px; }
  .burger{ width:36px; padding:12px 8px; }
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ transition-duration:.01ms !important; animation-duration:.01ms !important; }

  /* no pinning, no dimming — the hero just scrolls away normally */
  .hero{ position:relative; }
  .hero__dim{ display:none; }
}


/* =========================================================
   ASSO PAGE — «что даёт система» (Figma 1931-8990)
   Reuses the site grid: the claim sits in the left rail, the copy and the
   checklist hang off the same --col-text line as everywhere else.
   ========================================================= */
.promo{
  display:grid;
  grid-template-columns:var(--col-text) 1fr;
  padding:clamp(48px, 5vw, 86px) 0 clamp(40px, 4vw, 70px);
}
.promo__claim{
  /* fills its grid column instead of stopping at 430px; the gutter before the
     right column is the base 24-60px plus the 40px the text gives back */
  max-width:none;
  padding-right:clamp(64px, calc(3.5vw + 40px), 100px);
  font-size:clamp(22px, 1.85vw, 32px);
  font-weight:600; line-height:1.28; letter-spacing:-.03em;
  color:var(--text);
}
.promo__body{ min-width:0; }
.promo__intro{
  max-width:820px;
  font-size:20px; font-weight:600; line-height:140%; letter-spacing:-0.6px;
  color:var(--text);
}

/* checklist with the green tick markers */
.checklist{ margin-top:clamp(24px, 2.4vw, 40px); max-width:900px; }
.checklist li{
  position:relative;
  padding:0 0 0 34px;
  font-size:14px; font-weight:600; line-height:26px;
  color:var(--text);
}
.checklist li + li{ margin-top:18px; }
.checklist li::before{
  content:"";
  /* centred on the first 26px line box: (26 - 16) / 2 */
  position:absolute; left:0; top:5px;
  width:16px; height:16px;
  border-radius:50%;
  background:var(--a-check);
  -webkit-mask:var(--tick-mask) no-repeat center / 16px 16px;
          mask:var(--tick-mask) no-repeat center / 16px 16px;
}

/* footnote under the checklist: a hairline rail on the left, text set in from
   it — the rail runs the full height of the copy, no rule above */
.promo__note{
  max-width:900px;
  margin-top:clamp(40px, 4.4vw, 78px);
  padding:0 0 0 29px;
  border-left:3px solid var(--rail);
  font-size:16px; font-weight:600; line-height:1.75; letter-spacing:-.02em;
  color:var(--text-body);
}

/* the padlock on the hero CTA of this page */
.btn__lock{
  flex:none; width:22px; height:22px;
  background:currentColor;
  -webkit-mask:var(--lock-mask) no-repeat center / contain;
          mask:var(--lock-mask) no-repeat center / contain;
}

/* this page's headline is longer, so it starts a step smaller */
.hero__title--sm{ font-size:clamp(30px, 3.3vw, 58px); line-height:1.06; }

@media (max-width:1023px){
  .promo{ grid-template-columns:1fr; }
  .promo__claim{ max-width:none; padding-right:0; margin-bottom:clamp(24px, 3vw, 40px); }
}

/* =========================================================
   PARTNER PROGRAM — tiers (Figma 1931-8648)
   Left rail carries the claim, the right column is a real comparison table.
   Both hang off --col-text, the same spine as the hero copy and the footer.
   ========================================================= */
.tiers{
  display:grid;
  grid-template-columns:var(--col-text) 1fr;
  padding:clamp(48px, 5vw, 86px) 0 clamp(40px, 4vw, 70px);
}
.tiers__claim{
  max-width:none;
  padding-right:clamp(30px, 3.4vw, 58px);
  font-size:clamp(26px, 2.32vw, 40px);
  font-weight:600; line-height:1.3; letter-spacing:-.03em;
  color:var(--text);
}
.tiers__text{
  margin-top:clamp(26px, 2.8vw, 48px);
  padding-right:clamp(30px, 3.4vw, 58px);
  font-size:15px; font-weight:600; line-height:26px;
  color:var(--text-body);
}
.tiers__aside{ min-width:0; }
.tiers__table{ min-width:0; }

/* ---------- the matrix ----------
   table-layout:fixed with percentage columns lifted off the mock: the three
   status columns are 16.21% each and the last one carries a 3.18% gutter, so
   every seal lands on the centre the design put it on while the row rules
   still run the full width. */
.matrix{
  width:100%;
  border-collapse:collapse;
  table-layout:fixed;
}
.matrix col.matrix__col--label{ width:48.19%; }
.matrix col.matrix__col--tier { width:16.21%; }
.matrix col.matrix__col--last { width:19.39%; }

.matrix th,
.matrix td{
  padding:6px 0;
  border-bottom:1px solid var(--tint);
  /* the status columns read flush left: header label and seal share one edge.
     Swap this to `center` to put both back on the column centre. */
  text-align:left;
  vertical-align:middle;
}
.matrix .matrix__last{ padding-right:3.18%; }

.matrix thead th{
  height:65px;
  /* the whole header row reads flush left, including the status columns */
  text-align:left;
  font-size:13px; font-weight:700; line-height:18px;
  letter-spacing:.01em; text-transform:uppercase;
  color:var(--text-mute);
}

.matrix tbody th{
  height:64px;
  text-align:left;
  font-size:14px; font-weight:600; line-height:26px;
  color:var(--text);
  padding-right:24px;
}
.matrix tbody tr:last-child th,
.matrix tbody tr:last-child td{ border-bottom:0; }

/* the seal: one masked box for the teal rosette, one for the tick on top.
   Both are painted, so the pair recolours from tokens and costs no request. */
.matrix__mark{
  display:inline-block; position:relative;
  width:23px; height:23px;
  background:var(--a-check);
  -webkit-mask:var(--seal-mask) no-repeat center / contain;
          mask:var(--seal-mask) no-repeat center / contain;
}
.matrix__mark::before{
  content:"";
  position:absolute; inset:0;
  background:var(--n-000);
  -webkit-mask:var(--seal-tick-mask) no-repeat center / contain;
          mask:var(--seal-tick-mask) no-repeat center / contain;
}

/* screen readers get a word; the seal itself is decorative */
.matrix__yes{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}

@media (max-width:1023px){
  .tiers{ grid-template-columns:1fr; }
  .tiers__claim,
  .tiers__text{ padding-right:0; }
  .tiers__table{ margin-top:clamp(28px, 4vw, 46px); }
}

/* Below the point where four columns stop fitting, each row becomes a block:
   the benefit on its own line, the three statuses as labelled chips under it. */
@media (max-width:767px){
  .matrix,
  .matrix tbody,
  .matrix tbody tr,
  .matrix tbody th,
  .matrix tbody td{ display:block; width:auto; }
  .matrix thead{ display:none; }
  .matrix colgroup{ display:none; }

  .matrix tbody tr{
    padding:16px 0;
    border-bottom:1px solid var(--tint);
  }
  .matrix tbody tr:last-child{ border-bottom:0; }

  .matrix tbody th{
    height:auto; padding:0 0 12px; border-bottom:0;
  }
  .matrix tbody td{
    display:inline-flex; align-items:center; gap:8px;
    padding:0 20px 0 0; border-bottom:0;
    font-size:12px; font-weight:600; text-transform:uppercase;
    letter-spacing:.01em; color:var(--text-mute);
  }
  .matrix .matrix__last{ padding-right:0; }
  .matrix tbody td::after{ content:attr(data-tier); }
  /* a status the row does not include drops out entirely */
  .matrix tbody td:empty{ display:none; }
}

/* =========================================================
   PRODUCT PAGE (Figma 1931-5954)
   No blue hero, so the bar is white from the first pixel and pinned. The rest
   is the site grid: the info column hangs off --col-text exactly like the hero
   copy on the other pages, so the spine holds when you flip between them.
   ========================================================= */

/* Without a hero above it the bar carries its own hairline, and the content
   has to reserve the height the fixed bar takes out of the flow — on the other
   pages .hero does that with its padding-top. */
.topbar--plain{ box-shadow:inset 0 -1px 0 var(--tint); }
.topbar--plain ~ .site-main{ padding-top:var(--topbar-h); }

/* ---------- sticky action bar ----------
   Figma 1931:6403. Once the CTA in the info column has scrolled up under the
   header, the same two calls follow the reader down the page in a 76px white
   band docked beneath it. It is a shortcut, not new content: both buttons
   point at the enquiry form the CTA already points at.

   The page reserves the height in --stick-h (on <body>) rather than in this
   rule, because the anchor offsets have to account for the bar even while it
   is still hidden — every jump from .anchors lands past the trigger, so the
   bar is always on by the time the scroll finishes. */
.has-subbar{ --stick-h:calc(var(--topbar-h) + var(--subbar-h)); }

.subbar{
  position:fixed; left:0; right:0; top:var(--topbar-h); z-index:40;
  height:var(--subbar-h);
  background:var(--n-000);
  box-shadow:inset 0 1px 0 var(--tint), 0 4px 4px rgba(0,0,0,.06);
  /* parked exactly one bar-height up, so it slides out from under the header
     instead of appearing over it */
  transform:translateY(-100%);
  opacity:0; visibility:hidden;
  transition:transform .28s ease, opacity .28s ease, visibility .28s;
}
:root.subbar-on .subbar{ transform:none; opacity:1; visibility:visible; }

/* with the second bar out, the pair reads as one stack: only the lower edge
   of the lower bar carries the shadow */
:root.subbar-on .topbar.is-stuck{ box-shadow:inset 0 -1px 0 var(--tint); }

.subbar__inner{
  display:flex; align-items:center; justify-content:space-between;
  gap:clamp(16px, 2vw, 34px);
  height:100%;
}

/* left: the product, small enough to be a label rather than a second title */
.subbar__product{
  display:flex; align-items:center; gap:26px;
  min-width:0;                      /* lets the name ellipsis instead of pushing */
}
.subbar__thumb{
  flex:none;
  width:27px; height:52px;
  object-fit:contain;
}
.subbar__name{
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-size:16px; font-weight:500; line-height:19px; letter-spacing:-.03em;
  color:var(--text-body);
}

.subbar__actions{ display:flex; flex:none; gap:11px; }
/* .btn already carries the 11px bold uppercase label; these add the mock's box */
.subbar__btn{
  width:257px; max-width:100%; height:40px;
  padding:0 12px;
  background:var(--brand); color:var(--text-inv);
  text-align:center;
}
.subbar__btn:hover{ background:var(--b-400); }
.subbar__btn--ghost{ background:var(--tint); color:var(--text); }
/* on a white bar the secondary has to darken on hover, not lighten like the
   same button does over the blue hero */
.subbar__btn--ghost:hover{ background:var(--n-400); }

.crumbs{
  padding:12px 0 0;   /* lands the line on the same 88 as the hero's trail */
  font-size:12px; font-weight:500; color:var(--text-mute);
}
.crumbs a{ color:var(--text-mute); }
.crumbs a:hover{ color:var(--link); }
.crumbs__sep{ padding:0 8px; }

/* ---------- product head: gallery + info ---------- */
.site-main > .product{
  display:grid;
  grid-template-columns:var(--col-text) 1fr;
  padding:clamp(28px, 3.2vw, 55px) 0 clamp(40px, 4vw, 64px);
}

/* ---------- gallery ----------
   Nothing sits under it in the left rail, so it pins while the whole right
   column scrolls past. align-self:start is what makes sticky work in a grid —
   a stretched item fills the row and has no room to travel. */
.gallery{
  min-width:0;
  padding-right:max(24px, 18.71%);
  position:sticky;
  top:calc(var(--topbar-h) + 16px);
  align-self:start;
}
.pcol{ min-width:0; }
.gallery__stage{
  position:relative;
  display:grid; place-items:center;
  aspect-ratio:543 / 624;
  padding:clamp(20px, 3vw, 48px);
  background:var(--n-050);
}
/* Every slide fills the stage absolutely and the shot is letterboxed inside
   it. A percentage max-height on a grid item is treated as indefinite by
   Chrome, which let a portrait shot spill past the plate — an absolutely
   positioned box has a definite size, so contain always has something to
   measure against and the stage keeps one size for every proportion. */
.gallery__slide{
  position:absolute; inset:clamp(20px, 3vw, 48px);
  display:none;
}
.gallery__slide.is-active{ display:block; }
.gallery__stage img,
.gallery__stage video{
  width:100%; height:100%;
  object-fit:contain;
}
/* a video slide keeps the native controls: unlike the footer band this one is
   something the visitor chose to open */
.gallery__stage video{ background:var(--b-900); }

.gallery__nav{
  position:absolute; top:50%; transform:translateY(-50%);
  z-index:1;
}
.gallery__nav--prev{ left:clamp(6px, 1.2vw, 20px); }
.gallery__nav--next{ right:clamp(6px, 1.2vw, 20px); }

.gallery__thumbs{
  display:flex; flex-wrap:wrap; gap:7px;
  margin-top:clamp(14px, 1.6vw, 24px);
}
.gallery__thumb{
  position:relative;
  width:87px; height:73px;
  padding:0; border:1px solid transparent;
  background:var(--n-050);
  cursor:pointer;
  transition:border-color .18s ease;
}
.gallery__thumb img{ width:100%; height:100%; object-fit:cover; }
/* the first thumb is the same alpha cut-out as the main shot, so it is fitted
   rather than cropped — cover would slice the tower in half */
.gallery__thumb:first-child img{ object-fit:contain; padding:4px; }
.gallery__thumb:hover{ border-color:var(--rail); }
.gallery__thumb[aria-current="true"]{ border-color:var(--brand); }
/* the video slide gets the same triangle as the big play button */
.gallery__thumb--video::after{
  content:"";
  position:absolute; left:50%; top:50%;
  width:14px; height:16px;
  margin:-8px 0 0 -5px;
  background:var(--n-000);
  filter:drop-shadow(0 0 3px rgba(0,0,0,.45));
  clip-path:polygon(0 0, 100% 50%, 0 100%);
}

/* Round icon button, shared by the gallery and the carousel. The chevron is
   the nav caret mask turned on its side, so this adds no new asset. */
.round{
  display:grid; place-items:center;
  width:45px; height:45px;
  border:0; border-radius:50%;
  background:var(--brand);
  cursor:pointer;
  transition:background .18s ease, opacity .18s ease;
}
.round::before{
  content:"";
  width:16px; height:8px;
  background:var(--n-000);
  -webkit-mask:var(--caret-mask) no-repeat center / contain;
          mask:var(--caret-mask) no-repeat center / contain;
  transform:rotate(-90deg);
}
.round--prev::before{ transform:rotate(90deg); }
.round:hover{ background:var(--b-400); }
.round:disabled{ opacity:.35; cursor:default; }

/* --------------------------------------------------------------
   .round--soft is the same control on a white surface, and it is
   the site's one rule for arrows there: grey at rest, brand on hover.
   Use it on every white block; plain .round belongs on the blue and
   photographic surfaces, where it is already brand-coloured.
   -------------------------------------------------------------- */
.round--soft{ background:var(--tint); }
.round--soft::before{
  background:var(--text-mute);
  transition:background .18s ease;
}
.round--soft:hover{ background:var(--brand); }
.round--soft:hover::before{ background:var(--n-000); }
.round--soft:disabled:hover{ background:var(--tint); }
.round--soft:disabled:hover::before{ background:var(--text-mute); }

/* ---------- info column ---------- */
.info{ min-width:0; }

.badge{
  display:inline-flex; align-items:center; gap:6px;
  height:26px; padding:0 10px;
  border-radius:4px;
  background:var(--a-badge);
  font-size:11px; font-weight:600; letter-spacing:-.02em;
  color:var(--text-inv);
}
.badge img{ width:12px; }

.info__title{
  margin-top:20px;
  font-size:clamp(28px, 2.78vw, 48px);
  font-weight:500; line-height:1.125; letter-spacing:-.03em;
  color:var(--text);
}
.info__registry{
  margin-top:22px;
  font-size:13px; font-weight:500; line-height:18px;
  color:var(--text-mute);
}
.info__lead{
  max-width:610px; margin-top:32px;
  font-size:15px; font-weight:600; line-height:26px;
  color:var(--text-body);
}

/* the CTA plate: button left, phone right */
.cta{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:clamp(20px, 3vw, 46px);
  margin-top:clamp(24px, 2.6vw, 44px);
  padding:clamp(18px, 1.6vw, 24px);
  background:var(--n-050);
}
.cta__btn{
  display:grid; place-items:center;
  width:346px; max-width:100%; height:54px;
  background:var(--brand);
  font-size:11px; font-weight:700; letter-spacing:.02em; text-transform:uppercase;
  color:var(--text-inv);
  transition:background .18s ease;
}
.cta__btn:hover{ background:var(--b-400); }
.cta__aside{ min-width:0; }
.cta__hint{
  font-size:12px; font-weight:500; line-height:16px;
  color:var(--text-mute);
}
.cta__phone{
  display:inline-block; margin-top:6px;
  font-size:16px; font-weight:600; line-height:18px;
  color:var(--text);
}
.cta__phone:hover{ color:var(--link); }

/* ---------- section anchors ----------
   Not tabs: three links that scroll to blocks further down the page. The block
   the reader is in is the one printed in full black. */
.anchors{
  display:flex; flex-wrap:wrap; gap:clamp(26px, 3.4vw, 58px);
  margin-top:clamp(34px, 3.6vw, 60px);
  border-bottom:1px solid var(--tint);
}
.anchors__link{
  padding:0 0 12px;
  font-size:clamp(15px, 1.32vw, 18px);
  font-weight:600; line-height:24px; letter-spacing:-.03em;
  color:var(--text-mute);
  transition:color .18s ease;
}
/* the block the reader is in is marked by weight of colour alone — no rule
   under the label */
.anchors__link:hover{ color:var(--text); }
.anchors__link[aria-current="true"]{ color:var(--text); }

/* The mock leaves 49px between the anchor rule and the first spec row: the rule
   is at y=652 and the first row sits at y=715, its own 14px included. */
.specs-wrap{ padding-top:clamp(24px, 2.9vw, 49px); }

/* the fixed bars must not cover a heading the reader just jumped to */
#specs, #about, #docs{ scroll-margin-top:calc(var(--stick-h) + 22px); }

/* ---------- spec table ---------- */
.specs{ width:100%; border-collapse:collapse; table-layout:fixed; }
.specs col.specs__col--name { width:39.3%; }
.specs col.specs__col--value{ width:60.7%; }
/* Row rules are broken, not solid: the mock draws each one as two segments,
   693-1036 and 1088-1699 of a 1006-wide table, so the gap lands just before the
   value column. Painted as one gradient with hard transparent stops — same
   trick as the footer gridlines — which keeps it to a single element. */
.specs{
  --sp-a: 34.1%;   /* first segment ends */
  --sp-b: 39.3%;   /* second begins, flush with the value column */
}
.specs tbody tr{
  background-image:linear-gradient(to right,
    var(--tint) 0, var(--tint) var(--sp-a),
    transparent var(--sp-a), transparent var(--sp-b),
    var(--tint) var(--sp-b), var(--tint) 100%);
  background-repeat:no-repeat;
  background-position:0 100%;
  background-size:100% 1px;
}
/* the mock has no rule under the last row */
.specs tbody tr:last-child{ background-image:none; }
.specs th,
.specs td{
  padding:10px 24px 10px 0;
  text-align:left; vertical-align:top;
  font-size:13px; font-weight:600; line-height:26px;
}
.specs th{ color:var(--text); }
.specs td{ color:var(--text-body); }
.specs__name{ display:flex; align-items:flex-start; gap:17px; }
.specs__name img{ flex:none; width:30px; }

/* ---------- prose blocks ---------- */
.block{ padding-top:clamp(34px, 3.6vw, 58px); }
.block__title{
  font-size:clamp(20px, 1.4vw, 24px);
  font-weight:500; line-height:1.1; letter-spacing:-.03em;
  color:var(--text);
}
.prose{
  max-width:900px; margin-top:clamp(22px, 2.2vw, 36px);
  font-size:15px; font-weight:600; line-height:24px;
  color:var(--text-body);
}
.prose p + p{ margin-top:24px; }
.prose a{ color:var(--link); }

.bullets{
  max-width:900px; margin-top:clamp(22px, 2.2vw, 36px);
  font-size:15px; font-weight:500; line-height:24px;
  color:var(--text-body);
}
.bullets li{ position:relative; padding-left:22px; }
.bullets li::before{
  content:"";
  position:absolute; left:2px; top:9px;
  width:5px; height:5px; border-radius:50%;
  background:var(--a-bullet);
}

/* ---------- content shots ---------- */
.shots{
  display:grid; gap:clamp(14px, 1.5vw, 21px);
  grid-template-columns:repeat(2, minmax(0, 1fr));
  margin-top:clamp(30px, 3.4vw, 56px);
}
/* the plate belongs to the picture, not to the figure — on .shot it also ran
   behind the caption and boxed it in grey */
.shot{ position:relative; margin:0; }
.shot img{
  display:block; width:100%; height:auto;
  aspect-ratio:492 / 433; object-fit:cover;
  background:var(--n-050);
}
.shot--wide{ margin-top:clamp(14px, 1.5vw, 21px); }
.shot--wide img{ aspect-ratio:1006 / 827; }
.shot__play{
  position:absolute; inset:0;
  display:grid; place-items:center;
  border:0; background:none; cursor:pointer;
}
.shot__play::before{
  content:"";
  width:clamp(46px, 5vw, 80px); aspect-ratio:80 / 92;
  background:var(--n-000);
  filter:drop-shadow(0 2px 10px rgba(0,0,0,.35));
  clip-path:polygon(0 0, 100% 50%, 0 100%);
  transition:transform .2s ease;
}
.shot__play:hover::before{ transform:scale(1.06); }
.shot__video{
  display:block; width:100%; height:auto;
  aspect-ratio:492 / 433;
  object-fit:cover; background:var(--b-900);
}
.shot__note{
  margin-top:18px;
  font-size:13px; font-weight:500; line-height:21px;
  color:var(--text-mute);
}

/* ---------- certificates ---------- */
.certs{ margin-top:clamp(22px, 2.2vw, 34px); border-top:1px solid var(--tint); }
.cert{
  display:flex; align-items:center; gap:clamp(14px, 1.6vw, 26px);
  padding:14px 0;
  border-bottom:1px solid var(--tint);
}
.cert__icon{ flex:none; width:25px; }
.cert__name{
  flex:1; min-width:0;
  font-size:13px; font-weight:600; line-height:26px;
  color:var(--text);
}
.cert__dl{
  display:inline-flex; align-items:center; gap:11px;
  flex:none;
  font-size:12px; font-weight:600;
  color:var(--link);
}
.cert__dl img{ width:19px; }
/* no underline — the hover is carried by the arrow, which drops out of the
   bottom and comes back in from the top, once per pointer entry */
.cert__dl:hover{ color:var(--b-400); }
.cert__dl:hover img,
.cert__dl:focus-visible img{ animation:cert-drop .5s ease; }
@keyframes cert-drop{
  0%   { transform:translateY(0);     opacity:1; }
  45%  { transform:translateY(9px);   opacity:0; }
  55%  { transform:translateY(-9px);  opacity:0; }
  100% { transform:translateY(0);     opacity:1; }
}

/* ---------- related products ---------- */
.related__head{
  display:flex; align-items:center; justify-content:space-between;
  gap:20px;
}
.related__nav{ display:flex; gap:12px; }
/* a slider: the strip holds more products than fit, the arrows page it by one
   card and snap keeps a card edge flush with the column */
.related__strip{
  display:flex; gap:clamp(20px, 3.2vw, 50px);
  margin-top:clamp(24px, 2.4vw, 38px);
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  scroll-behavior:smooth;
  scrollbar-width:none;
  -webkit-overflow-scrolling:touch;
}
@media (prefers-reduced-motion:reduce){
  .related__strip{ scroll-behavior:auto; }
}
.related__strip::-webkit-scrollbar{ display:none; }
.related__strip > li{
  flex:0 0 calc((100% - 2 * clamp(20px, 3.2vw, 50px)) / 3);
  scroll-snap-align:start;
}
.card{
  display:flex; flex-direction:column;
  padding-top:20px;
  border-top:1px solid var(--tint);
}
.card__media{
  position:relative;
  display:grid; place-items:center;
  aspect-ratio:1 / 1;
  /* min-height:0 + overflow keep a portrait cut-out from stretching the plate,
     so every card in the row keeps the same square media box */
  min-height:0; overflow:hidden;
  padding:18px;
  background:var(--n-050);
  transition:background .22s ease;
}
/* the plate itself is the second way into the product. It fills the media box
   rather than wrapping it, so the badge stays a sibling and keeps being read
   out instead of disappearing into the link's name. */
.card__shot{ position:absolute; inset:0; }
.card__media img{
  position:absolute; inset:18px;
  width:calc(100% - 36px); height:calc(100% - 36px);
  object-fit:contain;
  /* these shots ship with a white studio background rather than an alpha
     channel; multiply drops it into the plate instead of boxing the product */
  mix-blend-mode:multiply;
  transition:transform .22s ease;
}
/* hover answers on the whole card, because the card is one product: the plate
   moves one step down the neutral ramp and the product rises inside it. The
   lift stays under the 18px padding, so nothing is clipped. */
.card:hover .card__media,
.card:focus-within .card__media{ background:var(--tint); }
.card:hover .card__media img,
.card:focus-within .card__media img{ transform:translateY(-8px); }
.card__badge{ position:absolute; right:10px; top:10px; }
.card__title{
  margin-top:22px;
  font-size:16px; font-weight:600; line-height:1.2;
  color:var(--text);
}
.card__title a:hover{ color:var(--link); }
.card__note{
  margin-top:14px;
  font-size:12px; font-weight:500; line-height:1.35;
  color:var(--text-mute);
}
.card__specs{ margin-top:18px; }
.card__specs li{
  display:flex; align-items:center; gap:9px;
  padding:8px 0;
  border-bottom:1px solid var(--tint);
  font-size:12px; font-weight:500; line-height:1.4;
  color:var(--text-mute);
}
.card__specs li:first-child{ border-top:1px solid var(--tint); }
.card__specs img{ flex:none; width:22px; }

@media (max-width:1023px){
  /* must out-weigh the base rule, which is now scoped to .site-main > */
  .site-main > .product{ grid-template-columns:minmax(0, 1fr); gap:clamp(24px, 4vw, 40px); }
  /* one column: nothing to pin against and no neighbour to clear */
  .gallery{ position:static; padding-right:0; }
  .specs col.specs__col--name { width:46%; }
  .specs col.specs__col--value{ width:54%; }
  /* the gap has to follow the column edge it is aligned to */
  .specs{ --sp-a:40.8%; --sp-b:46%; }
  .related__strip > li{ flex-basis:calc((100% - clamp(20px, 3.2vw, 50px)) / 2); }

  /* the buttons keep their priority and give up width first, then the name
     truncates — the product is already named in the H1 just above */
  .subbar__product{ gap:16px; }
  .subbar__name{ font-size:14px; }
  .subbar__btn{ width:auto; min-width:0; flex:0 1 257px; }
}

@media (max-width:767px){
  .shots{ grid-template-columns:1fr; }
  .related__strip > li{ flex-basis:100%; }
  .cta{ flex-direction:column; align-items:stretch; }
  .cta__btn{ width:100%; }

  /* On a phone the bar is two thumbs' worth of screen, so it keeps only what
     it is for: the two calls, side by side and equal. The label wraps to a
     second line rather than being cut. */
  .subbar__product{ display:none; }
  .subbar__actions{ flex:1; gap:8px; }
  .subbar__btn{
    flex:1 1 0;
    font-size:10px; line-height:12px; letter-spacing:.03em;
    white-space:normal;
  }
  /* the spec table stacks: name over value, nothing truncated */
  .specs,
  .specs colgroup,
  .specs tbody,
  .specs tr,
  .specs th,
  .specs td{ display:block; width:auto; }
  .specs tr{ padding:10px 0; border-bottom:1px solid var(--tint); background-image:none; }
  .specs tbody tr:last-child{ border-bottom:0; }
  .specs th,
  .specs td{ padding:0; }
  .specs td{ margin-top:4px; padding-left:47px; }
  /* the row keeps its shape on a phone: icon, name, download. The name wraps
     inside its own cell instead of pushing the download onto its own line. */
  .cert{ gap:12px; }
  .cert__name{ line-height:20px; }
  .cert__dl{ gap:8px; }
}

/* ---------- lightbox ----------
   A native <dialog>, so Esc, the focus trap and inertness of the page behind
   come from the platform instead of being re-implemented in script. */
.gallery__slide img{ cursor:zoom-in; }

.lightbox{
  width:min(96vw, 1400px);
  max-width:none; max-height:none;
  height:min(92vh, 1000px);
  padding:0; border:0;
  background:var(--n-000);
  color:var(--text);
}
.lightbox::backdrop{ background:rgb(0 28 56 / .88); }
.lightbox:not([open]){ display:none; }

.lightbox__stage{
  position:relative;
  width:100%; height:100%;
  display:grid; place-items:center;
  padding:clamp(16px, 4vw, 64px);
  background:var(--n-050);
  overflow:hidden;
}
.lightbox__slide{
  position:absolute; inset:clamp(16px, 4vw, 64px);
  display:none;
}
.lightbox__slide.is-active{ display:block; }
.lightbox__slide img,
.lightbox__slide video{
  width:100%; height:100%;
  object-fit:contain;
}
.lightbox__slide video{ background:var(--b-900); }

.lightbox__nav{
  position:absolute; top:50%; transform:translateY(-50%);
  z-index:2;
}
.lightbox__nav--prev{ left:clamp(8px, 1.4vw, 22px); }
.lightbox__nav--next{ right:clamp(8px, 1.4vw, 22px); }

.lightbox__close{
  position:absolute; right:clamp(8px, 1.4vw, 22px); top:clamp(8px, 1.4vw, 22px);
  z-index:2;
  display:grid; place-items:center;
  width:44px; height:44px;
  padding:0; border:0; border-radius:50%;
  background:var(--n-000);
  cursor:pointer;
  transition:background .18s ease;
}
.lightbox__close:hover{ background:var(--tint); }
/* the cross is drawn, so it inherits the token colour and costs no request */
.lightbox__close::before,
.lightbox__close::after{
  content:"";
  position:absolute;
  width:17px; height:1px;
  background:var(--text);
}
.lightbox__close::before{ transform:rotate(45deg); }
.lightbox__close::after { transform:rotate(-45deg); }

.lightbox__count{
  position:absolute; left:50%; bottom:clamp(8px, 1.4vw, 20px);
  transform:translateX(-50%);
  z-index:2;
  padding:5px 12px; border-radius:20px;
  background:var(--n-000);
  font-size:12px; font-weight:600;
  color:var(--text-mute);
}

@media (max-width:767px){
  .lightbox{ width:100vw; height:100vh; }
  .lightbox__nav{ top:auto; bottom:14px; transform:none; }
  .lightbox__count{ bottom:26px; }
}
/* =========================================================
   CATALOG
   Figma 1931-861 (base width 1728px). The page is the site grid taken one
   level further: a 300px filter rail, then four product columns, with a
   hairline down the middle of every gutter and across the top of every row.
   The card is the same .card component the product page uses; only the media
   plate is dropped, because here the mock puts the machines straight on white.
   ========================================================= */
:root{
  --filters-w: 300px;   /* the mock's rail: 25 → 325 */
  --cat-gap:    42px;   /* rail → grid, hairline down the middle */
  --prod-gap:   46px;   /* between product columns, hairline down the middle */
}
.catalog{ padding-bottom:clamp(30px, 3.4vw, 56px); }

/* ---------- active filter chips ----------
   They repeat what is ticked in the rail at the point the eye lands first,
   and they are the fastest way back out of a filter. */
.catalog__bar{
  display:flex; flex-wrap:wrap; align-items:flex-start; gap:8px;
  padding-top:clamp(18px, 1.7vw, 28px);
  min-height:36px;      /* the row keeps its height when the last chip goes */
}
.chips{ display:flex; flex-wrap:wrap; gap:8px; flex:1 1 auto; min-width:0; }

/* ---------- drawer trigger ----------
   Only exists where the rail has nowhere to stand. */
.filters__open{
  display:none;
  align-items:center; gap:10px; flex:none;
  height:36px; padding:0 14px;
  border-radius:2px;
  background:var(--brand);
  font-size:13px; font-weight:600;
  color:var(--text-inv);
  cursor:pointer;
  transition:background .18s ease;
}
.filters__open:hover{ background:var(--b-400); }
/* three shortening rules — the usual shorthand for a filter */
.filters__open-icon{
  position:relative;
  width:14px; height:10px; flex:none;
}
.filters__open-icon::before,
.filters__open-icon::after{
  content:"";
  position:absolute; left:0; right:0; height:1px;
  background:currentColor;
  box-shadow:0 4px 0 currentColor;
}
.filters__open-icon::before{ top:1px; }
.filters__open-icon::after{ top:9px; right:5px; box-shadow:none; }
.filters__open-count{
  min-width:18px; height:18px; padding:0 5px;
  border-radius:9px;
  background:var(--n-000);
  font-size:11px; font-weight:700; line-height:18px; text-align:center;
  color:var(--brand);
}
.filters__open-count:empty,
.filters__open-count[hidden]{ display:none; }
.chip{
  display:inline-flex; align-items:center; gap:10px;
  max-width:100%;       /* a long filter name shortens rather than sticking out */
  height:36px; padding:0 12px;
  border-radius:2px;
  background:var(--tint);
  font-size:14px; font-weight:500; line-height:1;
  color:var(--text);
  cursor:pointer;
  transition:background .18s ease;
}
.chip__label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.chip:hover{ background:var(--n-400); }
/* .chip is inline-flex, which would win over the hidden attribute */
.chip[hidden]{ display:none; }
/* the cross is drawn, like the lightbox close button, so it costs no request
   and takes the colour of the chip it sits in */
.chip__x{
  position:relative;
  width:21px; height:21px; flex:none;
  border-radius:50%;
  background:var(--n-000);
  transition:background .18s ease;
}
.chip__x::before,
.chip__x::after{
  content:"";
  position:absolute; left:50%; top:50%;
  width:11px; height:1px; margin:0 0 0 -5.5px;
  background:var(--text);
  transition:background .18s ease;
}
/* the whole chip removes the filter, but the cross is the part that says so:
   under the pointer it turns into the destructive control it is */
.chip__x:hover{ background:var(--a-red); }
.chip__x:hover::before,
.chip__x:hover::after{ background:var(--n-000); }
.chip__x::before{ transform:rotate(45deg); }
.chip__x::after { transform:rotate(-45deg); }

/* ---------- two-column body ---------- */
.catalog__body{
  display:grid;
  grid-template-columns:var(--filters-w) minmax(0, 1fr);
  column-gap:var(--cat-gap);
  margin-top:clamp(20px, 2vw, 32px);
}

/* =========================================================
   FILTER RAIL
   ========================================================= */
/* A <dialog> so the narrow-screen drawer gets Esc, the focus trap and an
   inert page for free. On a wide screen the UA's modal styling is undone and
   it is an ordinary column of the grid. */
.filters{
  display:block; position:static;
  width:auto; max-width:none; height:auto; max-height:none;
  min-width:0; margin:0; padding:0; border:0;
  background:none; color:inherit;
  overflow:visible;
}
.filters__head,
.filters__foot{ display:none; }
.filters__cats{
  padding-top:20px;
  border-top:1px solid var(--tint);
}
.filters__cats a{
  display:block;
  font-size:14px; font-weight:500; line-height:32px;
  color:var(--text);
  transition:color .18s ease;
}
.filters__cats a:hover{ color:var(--link); }
/* "you are here" in the palette's link colour, one weight up so it still
   reads as current when a sibling is hovered into the same colour */
.filters__cats a[aria-current="page"]{ color:var(--link); font-weight:600; }

.filters__form{ margin-top:clamp(24px, 2.4vw, 38px); }

.fgroup + .fgroup{ margin-top:clamp(22px, 2.2vw, 34px); }
.fgroup--last{ padding-bottom:clamp(22px, 2.2vw, 34px); border-bottom:1px solid var(--tint); }
/* inline-flex, not block: the whole line is the tooltip's hover target, and a
   block would stretch that target across the empty half of the rail */
.fgroup__title{
  display:inline-flex; align-items:center; gap:9px;
  font-size:15px; font-weight:600; line-height:32px;
  color:var(--text);
}
.fgroup__list{ margin-top:6px; }

/* ---------- filter checkbox ----------
   The mock marks a chosen filter with a white square inside a blue box rather
   than a tick — kept, because it reads as "this value", not "done". */
.fcheck{
  display:flex; align-items:center; gap:11px;
  line-height:32px;
  cursor:pointer;
}
.fcheck input{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden;
}
.fcheck__box{
  position:relative;
  width:20px; height:20px; flex:none;
  border-radius:2px;
  background:var(--tint);
  transition:background .18s ease;
}
.fcheck__box::before{
  content:"";
  position:absolute; inset:6px;
  border-radius:1px;
  background:var(--n-000);
  opacity:0; transition:opacity .15s ease;
}
.fcheck:hover .fcheck__box{ background:var(--n-400); }
.fcheck input:checked + .fcheck__box{ background:var(--brand); }
.fcheck input:checked + .fcheck__box::before{ opacity:1; }
.fcheck input:focus-visible + .fcheck__box{ outline:2px solid var(--brand); outline-offset:3px; }
.fcheck > span:last-child{
  font-size:14px; font-weight:500;
  color:var(--text);
}

/* ---------- switch ---------- */
.switch{
  display:flex; align-items:center; gap:12px;
  margin-top:10px;
  cursor:pointer;
}
.switch input{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden;
}
.switch__track{
  position:relative;
  width:40px; height:22px; flex:none;
  border-radius:99px;
  background:var(--n-400);
  transition:background .2s ease;
}
.switch__track::before{
  content:"";
  position:absolute; left:2px; top:2px;
  width:18px; height:18px;
  border-radius:50%;
  background:var(--n-000);
  transition:transform .2s ease;
}
.switch input:checked + .switch__track{ background:var(--brand); }
.switch input:checked + .switch__track::before{ transform:translateX(18px); }
.switch input:focus-visible + .switch__track{ outline:2px solid var(--brand); outline-offset:3px; }
.switch__text{ font-size:14px; font-weight:500; color:var(--text); }

/* ---------- term hint ----------
   A "?" in a ring beside the group name. The bubble is a description of the
   mark (aria-describedby), not a disclosure, so assistive tech reads it
   whatever the visual state is; showing it is presentation only.

   The bubble hangs off .fgroup, so it is always exactly as wide as the rail:
   anchored to the mark it would be a fixed-width box under a heading whose
   length runs from "Чипсет" to "В реестре Минпромторга", with nowhere to go
   inside a 275px drawer. The tail is the other way round — it belongs to the
   mark, so it points at it wherever the heading ends. */
.hint{
  position:relative;
  width:18px; height:18px; flex:none;
  border:1px solid var(--n-400); border-radius:50%;
  background:none;
  font-size:11px; font-weight:600; line-height:1;
  color:var(--text-mute);
  cursor:help;
  transition:border-color .18s ease, color .18s ease;
}

.fgroup{
  position:relative;
  --hint-gap: 6px;   /* heading to the foot of the bubble */
  --tail-h:   7px;
}
.hint__bubble{
  position:absolute; z-index:5;
  left:0; right:0; bottom:calc(100% + var(--hint-gap));
  padding:12px 14px;
  border-radius:4px;
  background:var(--n-000);
  box-shadow:0 4px 16px rgba(0,0,0,.14);
  font-size:11px; font-weight:500; line-height:1.55;
  color:var(--text-mute);
}
.hint__bubble[hidden]{ display:none; }

/* the tail: drawn with borders, so it needs no asset and no shape to keep in
   step with the bubble's fill. Its flat edge sits on the bubble's lower edge
   and it points down at the mark it grew out of. */
.hint::after{
  content:"";
  position:absolute; z-index:6;
  left:50%; margin-left:calc(var(--tail-h) * -1);
  /* measured from the mark's own box, not from a percentage of it: the gap
     above the heading, the mark's border and the tail's own height put its
     flat edge exactly on the foot of the bubble */
  top:calc(-1 * (var(--hint-gap) + 1px + var(--tail-h)));
  width:0; height:0;
  border-left:var(--tail-h) solid transparent;
  border-right:var(--tail-h) solid transparent;
  border-top:var(--tail-h) solid var(--n-000);
  display:none;
}

/* the pointer over the heading line opens it; the keyboard does the same
   through the mark, and a tap is handled in script for touch, where there is
   no hover to work with — .is-hinted is how that third path reaches the tail,
   which no sibling selector can see from the bubble */
.fgroup__title:hover + .hint__bubble,
.fgroup__title:focus-within + .hint__bubble{ display:block; }
.fgroup__title:hover .hint::after,
.fgroup__title:focus-within .hint::after,
.fgroup.is-hinted .hint::after{ display:block; }
.fgroup__title:hover .hint,
.fgroup__title:focus-within .hint{ border-color:var(--text-mute); color:var(--text); }


/* =========================================================
   PRODUCT GRID
   ========================================================= */
.catalog__results{ min-width:0; }
.results .products{
  display:grid;
  /* the count is a literal on purpose: repeat() does not accept a var()
     as its first argument, and an invalid value collapses the grid */
  grid-template-columns:repeat(4, minmax(0, 1fr));
  column-gap:var(--prod-gap);
  row-gap:36px;
  /* the grid closes with a rule, like every row inside it */
  padding-bottom:36px;
  border-bottom:1px solid var(--tint);
}
.results .products > li{ position:relative; }
/* The column hairline is drawn by the card on its right, so it lands in the
   middle of the gutter. It stops short of the row rules at both ends, the way
   the mock breaks it, and the first one falls in the rail gutter. */
.results .products > li::after{
  content:"";
  position:absolute; z-index:0;
  left:calc(var(--prod-gap) / -2); top:7px; bottom:13px;
  width:1px;
  background:var(--tint);
}
/* Only the catalogue has a rail to its left, so only there does the first
   card in a row get a hairline — in the rail’s gutter, not the grid’s. */
.catalog__results .products > li:nth-child(4n+1)::after{ left:calc(var(--cat-gap) / -2); }

/* catalogue cards sit straight on the page: no plate under the machine, and
   none on hover either — here the whole cell lifts instead */
.results .products .card__media{
  background:none;
  padding:0;
  overflow:visible;
}
.results .products > li:hover .card__media,
.results .products > li:focus-within .card__media{ background:none; }
.results .products .card__media img{
  inset:13% 0;
  width:100%; height:74%;
}
.results .products .card__badge{ right:0; top:0; z-index:2; }

/* ---------- loading skeleton ----------
   Every shot is lazy now, so a card's picture arrives well after its text.
   The skeleton holds the media box while it does — the box is already sized
   by aspect-ratio, so nothing moves when the picture lands and the layout
   shift stays at zero. Script adds .is-loaded; a shot that fails to load
   counts as loaded too, or the box would shimmer for ever. */
.results .products .card__media::after{
  content:"";
  position:absolute; inset:0; z-index:1;
  background-color:var(--surface);
  background-image:linear-gradient(100deg,
    transparent 25%, rgba(255,255,255,.85) 50%, transparent 75%);
  background-repeat:no-repeat;
  background-size:220% 100%;
  animation:card-shimmer 1.4s linear infinite;
  transition:opacity .35s ease;
  pointer-events:none;
}
@keyframes card-shimmer{
  from{ background-position:-160% 0; }
  to  { background-position: 260% 0; }
}
.results .products > li.is-loaded .card__media::after{ opacity:0; animation:none; }
/* the mock leaves room between the picture and the name for the photo
   switcher; the rhythm is kept whether or not the control is there */
.results .products .card__title{ margin-top:56px; }

/* the card's own content has to ride above the hover plate */
.results .products > li > *{ position:relative; z-index:1; }

/* ---------- hover: the cell lifts onto a white plate ----------
   The plate runs hairline to hairline and reaches past the foot of the card,
   because that is where the "Подробнее" call comes out. */
.results .products > li{
  --more-h:   45px;   /* the call itself */
  --more-gap: 10px;   /* card foot to the call */
  --more-pad: 18px;   /* the call to the foot of the plate */
}
.results .products > li::before{
  content:"";
  position:absolute; z-index:0;
  /* the plate's lower edge is derived from the call it has to hold, so the
     two cannot drift apart when either number changes */
  top:7px;
  bottom:calc(-1 * (var(--more-gap) + var(--more-h) + var(--more-pad)));
  left:calc(var(--prod-gap) / -2); right:calc(var(--prod-gap) / -2);
  background:var(--n-000);
  box-shadow:0 4px 4px rgba(0,0,0,.09);
  opacity:0; transition:opacity .22s ease;
}
.catalog__results .products > li:nth-child(4n+1)::before{ left:calc(var(--cat-gap) / -2); }
.results .products > li:hover,
.results .products > li:focus-within{ z-index:2; }
.results .products > li:hover::before,
.results .products > li:focus-within::before{ opacity:1; }

/* scoped past `.products .card > *`, which would otherwise put it back in flow */
.results .products .card__more{
  position:absolute; z-index:1;
  left:-8px; right:-8px; top:100%;
  margin-top:var(--more-gap);
  opacity:0; visibility:hidden;
  transition:opacity .22s ease, visibility .22s;
}
.results .products > li:hover .card__more,
.results .products > li:focus-within .card__more{ opacity:1; visibility:visible; }
.card__more-btn{
  display:flex; align-items:center; justify-content:center; gap:12px;
  height:var(--more-h, 45px);
  background:var(--brand);
  font-size:12px; font-weight:700; letter-spacing:.02em; text-transform:uppercase;
  color:var(--text-inv);
  transition:background .18s ease;
}
.card__more-btn:hover{ background:var(--b-400); }
/* the arrow is drawn: a rule with a head, so it inherits the label colour */
.card__more-arrow{
  width:19px; height:13px; flex:none;
  background:currentColor;
  -webkit-mask:var(--arrow-mask) no-repeat center / contain;
          mask:var(--arrow-mask) no-repeat center / contain;
}

/* the pager hangs off the grid, not off the page's text column */
.catalog__results .pager{ margin-left:0; }

/* =========================================================
   CATEGORY COPY
   The same spine as the hero: a short lead in the left column, the heading and
   the running text to the right of the guide.
   ========================================================= */
.seo{
  position:relative;
  display:grid;
  grid-template-columns:var(--col-text) minmax(0, 1fr);
  padding:clamp(40px, 4.6vw, 78px) 0 clamp(20px, 2.4vw, 40px);
}
/* the same guide the hero draws, carried under the grid: --rule-gap left of
   the text column, so the copy never sits flush against it */
.seo::before{
  content:"";
  position:absolute;
  left:calc(var(--col-text) - var(--rule-gap));
  top:clamp(40px, 4.6vw, 78px); bottom:clamp(20px, 2.4vw, 40px);
  width:1px;
  background:var(--tint);
}
.seo__lead{
  margin-left:calc(var(--filters-w) + var(--cat-gap));
  max-width:216px;
  font-size:14px; font-weight:600; line-height:24px;
  color:var(--text-mute);
}
.seo__body{ min-width:0; }
.seo__title{
  max-width:608px;
  font-size:clamp(28px, 2.8vw, 48px);
  font-weight:500; line-height:1;
  letter-spacing:-.03em;
  color:var(--text);
}
.seo .prose{ max-width:824px; }

/* ---------- hero variant: the machine stands on the lower edge ----------
   Hung off --shell-x / --shell-w, the same pair the hero's own guides use, so
   the machine keeps its place in the grid at every width instead of drifting
   away from the rules behind it. */
/* No position:relative here. .hero is already sticky, which is both the
   containing block this needs and the pinning the white page rides over —
   relative would quietly cancel the pinning and the dim with it. overflow
   opens up so the machine can stand past the lower edge; every other layer in
   the hero is inset:0 and has nothing to leak. */
.hero--catalog{ overflow:visible; }
.hero__shot{
  --shot-sink: 26px;   /* how far its feet go under the white block below */
  position:absolute; z-index:1;
  bottom:calc(var(--shot-sink) * -1);
  left:calc(var(--shell-x) + 0.1055 * var(--shell-w));
  /* sized off the hero, not the shell: the mock gives it 78% of the block and
     that is what keeps its head below the breadcrumbs at every width */
  height:calc(78% + var(--shot-sink)); width:auto;
  pointer-events:none;
  /* rises into place on load. No fade: the white block below the hero already
     paints over the hero, so the machine's starting position is hidden behind
     it and it reads as coming up from under the page. */
  animation:hero-shot-rise .9s cubic-bezier(.22, .61, .36, 1) .12s both;
}
@keyframes hero-shot-rise{
  from{ transform:translateY(78px); }
  to  { transform:none; }
}


/* Four columns need roughly 1440 to keep a card near the mock's 300px. Below
   that the grid drops to three rather than letting the cards get thin. */
@media (max-width:1439px){
  :root{ --filters-w:260px; --cat-gap:32px; --prod-gap:34px; }
  .catalog__results .products{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
  /* with three columns the rail hairline moves to a different card */
  .catalog__results .products > li:nth-child(4n+1)::after{ left:calc(var(--prod-gap) / -2); }
  .catalog__results .products > li:nth-child(4n+1)::before{ left:calc(var(--prod-gap) / -2); }
  .catalog__results .products > li:nth-child(3n+1)::after,
  .catalog__results .products > li:nth-child(3n+1)::before{ left:calc(var(--cat-gap) / -2); }
  .results .products .card__title{ margin-top:40px; }
}

@media (max-width:1023px){
  /* ---------- the rail becomes a drawer ----------
     There is no room for a 300px column beside the grid, and laying the
     filters across the top costs a whole screen before the first product.
     So they slide in over the page and the grid keeps the full width. */
  .catalog__body{ grid-template-columns:minmax(0, 1fr); }
  .filters__open{ display:inline-flex; }

  .filters{
    position:fixed; inset:0 auto 0 0;
    z-index:70;                 /* over the pinned top bar */
    width:min(86vw, 360px); height:100%;
    padding:0 var(--pad) 96px;  /* room for the footer that floats over it */
    background:var(--n-000);
    overflow-y:auto; overscroll-behavior:contain;
    transform:translateX(-100%);
    transition:transform .3s ease;
  }
  .filters.is-open{ transform:none; }
  .filters::backdrop{ background:rgb(0 28 56 / .55); }
  .filters:not([open]){ display:none; }

  .filters__head{
    position:sticky; top:0; z-index:1;
    display:flex; align-items:center; justify-content:space-between;
    height:60px;
    background:var(--n-000);
    box-shadow:inset 0 -1px 0 var(--tint);
  }
  .filters__head-title{ font-size:16px; font-weight:600; color:var(--text); }
  .filters__close{
    position:relative;
    width:40px; height:40px; margin-right:-10px;
    background:none; cursor:pointer;
  }
  .filters__close::before,
  .filters__close::after{
    content:"";
    position:absolute; left:50%; top:50%;
    width:17px; height:1px; margin-left:-8.5px;
    background:var(--text);
  }
  .filters__close::before{ transform:rotate(45deg); }
  .filters__close::after { transform:rotate(-45deg); }

  .filters__foot{
    position:fixed; left:0; bottom:0;
    display:block;
    width:min(86vw, 360px);
    padding:14px var(--pad);
    background:var(--n-000);
    box-shadow:0 -4px 12px rgba(0,0,0,.08);
  }
  .filters__apply{
    width:100%; height:48px;
    background:var(--brand); color:var(--text-inv);
    font-size:12px;
  }
  .filters__apply:hover{ background:var(--b-400); }

  .filters__cats{ padding-top:18px; border-top:0; }
  .filters__form{ margin-top:22px; }
  .fgroup--last{ border-bottom:0; }
  .hint__bubble{ right:0; }
  .hint__bubble::before{ left:76px; }

  /* two columns, and the rail no longer sits beside them, so the leftmost
     card has nothing to be separated from */
  .catalog__results .products{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .results .products > li::after{ left:calc(var(--prod-gap) / -2); }
  .catalog__results .products > li:nth-child(2n+1)::after{ display:none; }
  .catalog__results .products > li:nth-child(3n+1)::before,
  .catalog__results .products > li:nth-child(4n+1)::before,
  .catalog__results .products > li:nth-child(2n+1)::before{ left:calc(var(--prod-gap) / -2); }

  .hero__shot{ display:none; }
  .seo{ grid-template-columns:minmax(0, 1fr); gap:clamp(14px, 2vw, 22px); }
  .seo::before{ display:none; }
  .seo__lead{ margin-left:0; max-width:none; }
}

@media (max-width:767px){
  :root{ --prod-gap:20px; }
  /* on a phone the trigger takes the whole content width: it is the way into
     the filters, not one control among several */
  .filters__open{ display:flex; width:100%; justify-content:center; height:44px; }
  .chips{ flex-basis:100%; }
  .results .products{ row-gap:26px; padding-bottom:26px; }
  .results .products > li::after{ display:none; }
  .results .products .card__title{ margin-top:22px; }
  /* no pointer, no hover: the plate and the extra call would never be seen */
  .results .products > li::before{ display:none; }
  .card__more{ display:none; }
  .chip{ font-size:13px; }
}

@media (max-width:479px){
  .catalog__results .products{ grid-template-columns:minmax(0, 1fr); }
  /* one card per row: a square picture would take the whole screen, so the
     media flattens and two cards stay in view */
  .results .products .card__media{ aspect-ratio:4 / 3; }
}
/* =========================================================
   SEARCH RESULTS
   Figma 1931-14683 (base width 1728px). The same results grid the catalogue
   uses, only wider: with no filter rail beside it the row holds five cards
   instead of four, so the page says so with --cols and changes nothing else.
   ========================================================= */
.search-page{
  --prod-gap: 42px;   /* the mock's gutters: 5 columns across the full width */
  padding-bottom:clamp(30px, 3.4vw, 56px);
}
.search-page .products{ grid-template-columns:repeat(5, minmax(0, 1fr)); }
/* nothing stands to the left of the first card here, so it carries no
   hairline — the catalogue is the exception, not this */
.search-page .products > li:nth-child(5n+1)::after{ display:none; }

/* ---------- the query field, in the hero ----------
   It replaces the lead and the call the other heroes end with, and sits on
   the same left edge as the headline above it. */
/* the other heroes end with a lead beside a call, so .hero__foot is a
   space-between row; here it carries one block and has to stop splitting it */
.hero__foot--search{ display:block; }
.hero__search{
  display:flex; align-items:center;
  width:min(643px, 100%); height:52px;
  background:var(--n-000);
}
/* The whole white box is the control, so the focus ring goes on the box.
   Left on the input it drew a brand-blue rectangle inside a white field over
   a blue hero, which read as a stray border rather than as focus. */
.hero__search:focus-within{ outline:2px solid var(--text-inv); outline-offset:2px; }
.hero__search input:focus,
.hero__search input:focus-visible,
.hero__search button:focus-visible{ outline:none; }
.hero__search input{
  flex:1; min-width:0;
  height:100%; padding:0 12px 0 20px;
  border:0; background:none;
  font-size:16px; font-weight:600; letter-spacing:-.03em;
  color:var(--text);
}
.hero__search input::placeholder{ color:var(--n-450); font-weight:500; }
/* the search field is white here, but the input is a search type — Chrome's
   own clear button would sit on top of ours */
.hero__search input::-webkit-search-decoration,
.hero__search input::-webkit-search-cancel-button{ -webkit-appearance:none; }
.hero__search button{
  display:grid; place-items:center;
  width:56px; height:100%; flex:none;
  background:none; cursor:pointer;
  transition:opacity .18s ease;
}
.hero__search button:hover{ opacity:.6; }
.hero__search button img{ width:22px; height:auto; }
.hero__hint{
  margin-top:6px;
  font-size:10px; font-weight:500; line-height:24px;
  color:var(--text-inv-dim);
}

/* ---------- result kinds ----------
   Not a filter and not a tab strip: three links to the same search under a
   different kind, so the one you are reading is the one printed in black. */
.kinds{
  display:flex; flex-wrap:wrap;
  gap:clamp(20px, 2.6vw, 44px);
  padding:clamp(30px, 5.1vw, 88px) 0 clamp(22px, 3.2vw, 56px);
}
.kinds__link{
  font-size:16px; font-weight:600; line-height:1; letter-spacing:-.03em;
  color:var(--link);
  transition:color .18s ease;
}
.kinds__link:hover{ color:var(--b-400); }
.kinds__link[aria-current="page"]{ color:var(--text); cursor:default; }
.kinds__count{
  margin-left:6px;
  color:var(--n-450);
  font-weight:600;
}

/* the count sits at the far right of the pager row, as on the catalogue */
.search-page .pager{ margin-left:0; }

@media (max-width:1599px){
  .search-page{ --prod-gap:38px; }
  .search-page .products{ grid-template-columns:repeat(4, minmax(0, 1fr)); }
  .search-page .products > li:nth-child(5n+1)::after{ display:block; }
  .search-page .products > li:nth-child(4n+1)::after{ display:none; }
}

@media (max-width:1279px){
  .search-page{ --prod-gap:34px; }
  .search-page .products{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
  .search-page .products > li:nth-child(4n+1)::after{ display:block; }
  .search-page .products > li:nth-child(3n+1)::after{ display:none; }
  .results .products .card__title{ margin-top:40px; }
}

/* below 768 the shared block already drops every hairline and the hover
   plate, so only the column count and the field are left to say */
@media (max-width:767px){
  .search-page{ --prod-gap:20px; }
  .search-page .products{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .hero__search{ height:48px; }
  .hero__search input{ font-size:15px; padding-left:16px; }
  .kinds{ gap:18px 24px; }
  .kinds__link{ font-size:15px; }
}

@media (max-width:479px){
  .search-page .products{ grid-template-columns:minmax(0, 1fr); }
}
/* =========================================================
   COOKIE NOTICE
   Figma 1931-1874. Sits on the lower edge of the viewport, not of the page,
   so it stays put through the whole scroll. Above the menu scrim (50) and
   below the top bar (60): it must not be dimmed while it is the one thing
   waiting on an answer, and the modal filter drawer opens in the top layer,
   which clears it anyway.
   ========================================================= */
:root{ --cookie-h: 57px; }

.cookie{
  position:fixed; left:0; right:0; bottom:0; z-index:55;
  background:var(--brand);
  transform:translateY(100%);
  transition:transform .32s ease;
}
.cookie.is-up{ transform:none; }
.cookie[hidden]{ display:none; }

.cookie__inner{
  display:flex; align-items:center;
  gap:clamp(16px, 2vw, 34px);
  min-height:var(--cookie-h);
  padding:10px 0;
}
.cookie__text{
  flex:1; min-width:0;
  max-width:863px;
  font-size:11px; font-weight:600; line-height:14px;
  /* the mock sets #a0bbff, which is 3.15:1 on the brand blue — under the 4.5:1
     an 11px legal notice has to clear. This is the same family, at 5.1:1. */
  color:var(--text-inv-key);
}
/* the notice is capped at the mock's 863px, so the answers have to be told
   to take the far edge rather than follow the text */
.cookie__actions{ display:flex; flex:none; gap:12px; margin-left:auto; }
.cookie__btn{
  width:189px; height:36px;
  font-size:11px; font-weight:700; letter-spacing:.02em; text-transform:uppercase;
  cursor:pointer;
  transition:background .18s ease, color .18s ease, border-color .18s ease;
}
/* the mock's #418fd5 is white at 28% over the brand blue: kept as the alpha,
   so the outline follows the bar if the bar ever changes colour */
.cookie__btn--ghost{
  border:1px solid rgb(255 255 255 / .28);
  background:none;
  color:var(--text-inv);
}
.cookie__btn--ghost:hover{ border-color:var(--text-inv); background:rgb(255 255 255 / .1); }
.cookie__btn--solid{
  border:1px solid var(--n-000);
  background:var(--n-000);
  color:var(--brand);
}
.cookie__btn--solid:hover{ background:var(--text-inv-key); border-color:var(--text-inv-key); }

/* the cross is drawn, like every other close on the site */
.cookie__close{
  position:relative;
  width:34px; height:34px; flex:none;
  margin-right:-9px;
  background:none; cursor:pointer;
}
.cookie__close::before,
.cookie__close::after{
  content:"";
  position:absolute; left:50%; top:50%;
  width:15px; height:1px; margin-left:-7.5px;
  background:var(--text-inv);
  transition:background .18s ease;
}
.cookie__close::before{ transform:rotate(45deg); }
.cookie__close::after { transform:rotate(-45deg); }
.cookie__close:hover::before,
.cookie__close:hover::after{ background:var(--text-inv-key); }
.cookie__close:focus-visible{ outline:2px solid var(--text-inv); outline-offset:-4px; }
.cookie__btn:focus-visible{ outline:2px solid var(--text-inv); outline-offset:3px; }

/* While the bar is up it covers the foot of the page. The footer is the last
   thing on every page and it is blue, so the reserve is invisible there. */
.has-cookie .site-foot{ padding-bottom:var(--cookie-h); }

@media (max-width:1023px){
  .cookie__text{ max-width:none; }
  .cookie__btn{ width:150px; }
}

@media (max-width:767px){
  /* stacked: the notice reads first, the two answers sit under it side by
     side, and the cross keeps its corner */
  .cookie__inner{
    display:grid;
    grid-template-columns:minmax(0, 1fr) auto;
    gap:12px 10px;
    padding:14px 0 16px;
  }
  .cookie__text{ grid-column:1; }
  .cookie__close{ grid-column:2; grid-row:1; align-self:start; margin:-6px -9px 0 0; }
  /* the row is a grid cell now: drop the auto margin that right-aligned it */
  .cookie__actions{ grid-column:1 / -1; margin-left:0; }
  .cookie__btn{ flex:1 1 0; width:auto; }
}
/* =========================================================
   SITE MAP
   Figma 1931-7877. One nested list of links; the connectors are drawn by the
   list, not placed as art, so the tree can never fall out of step with the
   markup it describes.
   ========================================================= */
.sitemap{ padding:clamp(20px, 2.4vw, 34px) 0 clamp(44px, 6vw, 104px); }

/* a page title on white — the blue heroes have .hero__title, this is its
   counterpart for the pages that start straight on the page */
.page-title{
  font-size:clamp(34px, 4.2vw, 64px);
  font-weight:600; line-height:1.05; letter-spacing:-.03em;
  color:var(--text);
}

.tree{
  /* --arm is the horizontal reach of an elbow, --gap the air between it and
     the label; the trunk sits at their sum to the left of the text, and the
     indent is what a child moves right by. All four move together. */
  --ind: 56px;
  --arm: 38px;
  --gap: 10px;
  --lift: calc(var(--arm) + var(--gap));
  margin-top:clamp(38px, 5vw, 81px);
}
.tree ul{ list-style:none; }
.tree__level{ padding-left:var(--ind); }

.tree li{
  position:relative;
  padding:8px 0;
  --elbow: 18px;   /* the middle of the first line of the label */
}
/* the trunk: it runs the whole item, so a branch with children keeps a line
   down its side, and stops at the elbow on the last child of a level */
.tree li::before{
  content:"";
  position:absolute; left:calc(var(--lift) * -1); top:0; bottom:0;
  width:1px;
  background:var(--rail);
}
.tree li:last-child::before{ bottom:auto; height:var(--elbow); }
.tree li::after{
  content:"";
  position:absolute; left:calc(var(--lift) * -1); top:var(--elbow);
  width:var(--arm); height:1px;
  background:var(--rail);
}
/* the root hangs from nothing */
.tree__root > li::before,
.tree__root > li::after{ display:none; }

.tree a{
  display:inline-block;
  font-size:15px; font-weight:500; line-height:20px;
  color:var(--text);
  transition:color .18s ease;
}
.tree a:hover{ color:var(--link); }

/* a level opens with more air than it keeps between siblings: 48px against
   36. It is padding on the first child, not on the list, so the child's own
   trunk still starts at the parent and the vertical line has no break. */
.tree__level > li:first-child{
  --open: 14px;
  padding-top:calc(8px + var(--open));
  --elbow: calc(18px + var(--open));
}
.tree__level--1 > li:first-child{ --elbow: calc(21px + var(--open)); }

/* the root reads as a section like the ones under it */
.tree a.tree__home{
  font-size:16px; font-weight:600; line-height:26px;
}
/* the first level are sections, not pages inside one */
.tree__level--1 > li{ --elbow:21px; }
.tree__level--1 > li > a{
  font-size:16px; font-weight:600; line-height:26px;
}

@media (max-width:767px){
  /* three levels of 56px would push the deepest labels off a phone */
  .tree{ --ind:30px; --arm:20px; --gap:8px; }
  .tree a{ font-size:14px; }
  .tree a.tree__home{ font-size:15px; line-height:22px; }
  .tree__level--1 > li > a{ font-size:15px; line-height:22px; }
  .tree__level--1 > li{ --elbow:19px; }
}
/* =========================================================
   PRESS CENTRE
   Figma 1804-112. A narrow rail of sections on the left, publications on the
   right in two columns. The grid keeps the same habits as the catalogue: a
   hairline over every row, another down the middle of the gutter.
   ========================================================= */
.press{ padding:clamp(20px, 2.4vw, 34px) 0 clamp(40px, 5vw, 90px); }
.press__body{
  /* the mock puts the publications on the 5th of twelve columns: 34.2% of the
     content box, rail and its air together */
  display:grid;
  grid-template-columns:34.2% minmax(0, 1fr);
  margin-top:clamp(34px, 4.4vw, 76px);
}

/* ---------- section rail ----------
   Nothing sits under it in the left column, so it travels with the reader
   instead of scrolling away. align-self:start is what makes sticky work in a
   grid — a stretched item fills the row and has no room to move. */
.press__rail{
  min-width:0;
  position:sticky;
  top:calc(var(--topbar-h) + 24px);
  align-self:start;
}
.press__rail a{
  display:block;
  max-width:227px;
  font-size:15px; font-weight:600; line-height:39px;
  color:var(--text-mute);
  transition:color .18s ease;
}
.press__rail a:hover{ color:var(--link); }
.press__rail a[aria-current="page"]{ color:var(--link); }

/* ---------- topic filter ---------- */
.filterbar{
  display:flex; flex-wrap:wrap; gap:9px;
  padding-bottom:clamp(28px, 3vw, 51px);
}
.filterbar__chip{
  min-width:66px; height:35px; padding:0 14px;
  border:1px solid var(--rail); border-radius:2px;
  background:none;
  font-size:13px; font-weight:600; letter-spacing:-.03em;
  color:var(--text-body);
  cursor:pointer;
  transition:background .18s ease, border-color .18s ease, color .18s ease;
}
.filterbar__chip:hover{ border-color:var(--brand); color:var(--brand); }
.filterbar__chip.is-active{
  border-color:var(--brand); background:var(--brand);
  color:var(--text-inv);
}

/* ---------- publications ---------- */
.posts{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  column-gap:52px;
  row-gap:46px;
  padding-bottom:46px;
  border-bottom:1px solid var(--tint);
}
.post{
  position:relative;
  display:flex; flex-direction:column;
  padding-top:27px;
  border-top:1px solid var(--tint);
}
/* the gutter hairline, drawn by the card on its right so it lands in the
   middle; it stops short of the row rules the way the mock breaks it */
.posts > .post:nth-child(2n)::before{
  content:"";
  position:absolute; left:-26px; top:0; bottom:-24px;
  width:1px;
  background:var(--tint);
}

.post__shot{
  display:block;
  aspect-ratio:527 / 330;
  background:var(--surface);
  overflow:hidden;
}
.post__shot img{
  width:100%; height:100%;
  object-fit:cover;
  transition:transform .4s ease;
}
.post:hover .post__shot img{ transform:scale(1.03); }

.post__date{
  margin-top:14px;
  font-size:14px; font-weight:500; line-height:32px; letter-spacing:-.03em;
  color:var(--text-mute);
}
.post__title{
  margin-top:8px;
  font-size:21px; font-weight:600; line-height:28px; letter-spacing:-.03em;
}
.post__title a{
  color:var(--text);
  transition:color .18s ease;
}
.post__title a:hover{ color:var(--link); }

.post__tags{
  display:flex; flex-wrap:wrap; gap:7px;
  margin-top:auto; padding-top:clamp(24px, 3vw, 52px);
}
.tag{
  display:inline-flex; align-items:center;
  height:23px; padding:0 9px;
  border:1px solid var(--n-400); border-radius:2px;
  font-size:13px; font-weight:600; line-height:1; letter-spacing:-.03em;
  color:var(--num);
  transition:background .18s ease, color .18s ease, border-color .18s ease;
}
.tag:hover,
.tag.is-on{ background:var(--n-400); border-color:var(--n-400); color:var(--text); }

.press .pager{ margin-left:0; }

@media (max-width:1279px){
  .press__body{ grid-template-columns:26% minmax(0, 1fr); }
  .posts{ column-gap:34px; }
  .posts > .post:nth-child(2n)::before{ left:-17px; }
  .post__title{ font-size:19px; line-height:26px; }
}

@media (max-width:1023px){
  /* the rail lays itself across the top: a 26% column leaves the pictures
     too narrow to be worth showing */
  .press__body{ grid-template-columns:minmax(0, 1fr); }
  /* laid across the top now: there is nothing beside it to stay level with */
  .press__rail{
    position:static;
    padding-bottom:clamp(20px, 3vw, 30px);
    border-bottom:1px solid var(--tint);
  }
  .press__rail ul{ display:flex; flex-wrap:wrap; gap:0 clamp(18px, 3vw, 34px); }
  .press__rail a{ max-width:none; line-height:32px; }
  .filterbar{ padding-top:clamp(20px, 3vw, 30px); }
}

@media (max-width:767px){
  .posts{ grid-template-columns:minmax(0, 1fr); row-gap:30px; padding-bottom:30px; }
  .posts > .post:nth-child(2n)::before{ display:none; }
  .post{ padding-top:20px; }
  .post__title{ font-size:17px; line-height:24px; }
  .post__tags{ padding-top:18px; }
  .filterbar__chip{ height:32px; min-width:0; padding:0 12px; font-size:12px; }
}
/* =========================================================
   HOME
   Figma 1931-15187 (base width 1728px). The page reuses the site's hero,
   card, post and pager components; what is new here is the photographic
   hero, the equipment strip, the solutions list and the advantages stage.
   ========================================================= */

/* ---------- hero: a photograph, not the blue gradient ---------- */
.hero--home{
  min-height:clamp(560px, 52vw, 900px);
  padding-bottom:clamp(48px, 5vw, 90px);
  background:var(--b-900);
}
.hero--home .hero__photo{
  position:absolute; inset:0; z-index:0;
  width:100%; height:100%;
  object-fit:cover;
  /* scale comes from the script, together with the veil — .hero clips it */
  transform-origin:center;
  will-change:transform;
}
/* the headline sits over the busiest part of the picture, so the picture has
   to give way: dark at the bottom-left where the copy is, clear top-right */
.hero__scrim{
  position:absolute; inset:0; z-index:0;
  background:
    linear-gradient(180deg, rgb(0 28 56 / .55) 0%, rgb(0 28 56 / 0) 34%),
    linear-gradient(75deg, rgb(0 28 56 / .82) 18%, rgb(0 28 56 / .28) 62%, rgb(0 28 56 / .1) 100%);
}
.hero--home > .shell{ position:relative; z-index:1; flex:1; display:flex; flex-direction:column; }
/* the base .hero__body is flex:1 and fills the block, which leaves
   margin-top:auto nothing to push against — here the copy sits on the lower
   half, as in the mock */
.hero--home .hero__body{ flex:none; margin-top:auto; padding-top:0; }
/* The plates finish the first screen, so the hero takes exactly what is left
   of it — they sat over the fold before, and the hero has come up to meet
   them. Only where there is room: on a short window the hero keeps its own
   height and the plates go back to following it. */
@media (min-width:1024px) and (min-height:700px){
  /* the gap is counted twice: once over the plates and once under them, so
     they sit on the fold with air on both sides rather than against its edge */
  .hero--home{
    min-height:calc(100vh - var(--usp-h) - var(--usp-gap) * 2);
    min-height:calc(100svh - var(--usp-h) - var(--usp-gap) * 2);
  }
}
.hero__title--home{
  max-width:960px;
  font-size:clamp(30px, 3.5vw, 60px);
  font-weight:600; line-height:1.07; letter-spacing:-.02em;
}
.hero__lead--home{
  max-width:622px; margin-top:clamp(18px, 2vw, 32px);
  font-size:clamp(14px, 1.05vw, 16px); font-weight:500; line-height:1.55;
  color:var(--text-inv-soft);
}
.hero__acts{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:clamp(18px, 2.4vw, 40px);
  margin-top:clamp(26px, 3vw, 50px);
}
.hero__more{
  display:inline-flex; align-items:center; gap:12px;
  font-size:14px; font-weight:500;
  color:var(--text-inv);
}
.hero__more-arrow{
  position:relative;
  width:6px; height:12px;
}
.hero__more-arrow::before{
  content:"";
  position:absolute; left:0; top:2px;
  width:7px; height:7px;
  border-top:1px solid currentColor; border-right:1px solid currentColor;
  transform:rotate(45deg);
}
.hero__more:hover{ color:var(--text-inv-key); }
.hero__mark{
  position:absolute; right:0; bottom:0;
  font-size:16px; font-weight:500;
  color:var(--text-inv);
  opacity:.8;
}
.hero__mark sup{ font-size:.6em; }

/* ---------- shared section heading ---------- */
.block-title{
  font-size:clamp(24px, 2.4vw, 40px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
  color:var(--text);
}

/* a bordered call with a rule-and-head arrow, used by three sections */
.btn-wide{
  display:inline-flex; align-items:center; justify-content:space-between; gap:22px;
  width:196px; height:45px; padding:0 16px;
  border:1px solid var(--rail);
  font-size:11px; font-weight:700; letter-spacing:.02em; text-transform:uppercase;
  color:var(--text);
  transition:border-color .18s ease, background-color .18s ease, color .18s ease;
}
/* The site's one rule for a bordered call on a light surface: an outline at
   rest, and on hover it fills with the brand and the label turns white. Any
   button of this shape follows it — see the UI kit. */
.btn-wide:hover,
.btn-wide:focus-visible{
  border-color:var(--brand);
  background:var(--brand);
  color:var(--text-inv);
}
.btn-wide__arrow{
  width:19px; height:13px; flex:none;
  background:currentColor;
  -webkit-mask:var(--arrow-mask) no-repeat center / contain;
          mask:var(--arrow-mask) no-repeat center / contain;
}

/* ---------- three plates ---------- */
.usp{ padding-top:var(--usp-gap); }
.usp__grid{
  display:grid;
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:clamp(14px, 1.6vw, 27px);
}
.usp__card{
  display:flex; align-items:center; gap:clamp(18px, 2vw, 34px);
  min-height:var(--usp-h); padding:clamp(20px, 2.2vw, 38px);
  background:var(--surface);
}
/* The mock's three marks: two are multi-colour drawings, so they stay files
   rather than single-colour masks. They are not one size in Figma either —
   100 / 125 / 147 wide — so one base carries the scale and each keeps its own
   share of it. */
.usp{ --usp-icon: clamp(84px, 7.8vw, 134px); }
.usp__icon{
  width:var(--usp-icon); height:auto; flex:none;
  object-fit:contain;
}
.usp__icon--dev { width:calc(var(--usp-icon) * .68); }
.usp__icon--make{ width:calc(var(--usp-icon) * .94); }
/* the cube edges are filled slivers, not strokes; a hairline stroke on the
   dark shapes alone gives them weight without touching the light faces */
.usp__cube path[fill="#030202"]{ stroke:#030202; stroke-width:.85; }
.usp__links path{ stroke:#030202; stroke-width:.5; }
/* The stack deals itself out under the pointer, like the mark beside it: the
   sheets pull back onto the top one and slide down to their places, a beat
   apart. At rest the mark is exactly as Figma draws it — the animation is
   only attached while hovered, so leaving and returning replays it. --from
   and --lag are read inside the rule, so one declaration serves all five. */
.usp__layer{ transform-box:view-box; transform-origin:50px 57px; }
/* --from is how far below its place a sheet starts: they all begin stacked on
   the bottom one, so the lowest travels nothing and the top one the whole
   height. --lag runs the other way, bottom sheet first. */
.usp__layer--1{ --from:55.25px; --lag:.40s; }
.usp__layer--2{ --from:39.52px; --lag:.30s; }
.usp__layer--3{ --from:25.00px; --lag:.20s; }
.usp__layer--4{ --from:12.90px; --lag:.10s; }
.usp__layer--5{ --from:0px;     --lag:0s;   }
.usp__card:hover .usp__layer{
  animation:usp-deal 2.4s cubic-bezier(.22, .61, .36, 1) var(--lag, 0s) infinite both;
}
/* the move takes the first 40% and the rest is a hold, so the loop reads as
   one gesture repeating rather than a constant churn */
@keyframes usp-deal{
  0%  { transform:translateY(var(--from, 0)); opacity:0; }
  40% { transform:none; opacity:1; }
  100%{ transform:none; opacity:1; }
}
/* the core only makes sense once the sheets are apart */
.usp__card:hover .usp__core{ animation:usp-settle 2.4s ease .6s infinite both; }
@keyframes usp-settle{
  0%  { opacity:0; }
  25% { opacity:1; }
  100%{ opacity:1; }
}

/* The cubes breathe under the pointer, each on its own clock: seven different
   periods and offsets, none a multiple of another, so the set never falls into
   step and reads as restless rather than as a pulse. transform-box:fill-box
   makes each group scale about its own centre; the links between them hold
   still, which is what keeps the network legible while it moves. */
.usp__cube{ transform-box:fill-box; transform-origin:center; }
.usp__cube--1{ --dur:1.7s;  --lag:0s;    --peak:1.18; }
.usp__cube--2{ --dur:2.3s;  --lag:.21s;  --peak:.82;  }
.usp__cube--3{ --dur:1.9s;  --lag:.47s;  --peak:1.22; }
.usp__cube--4{ --dur:2.7s;  --lag:.13s;  --peak:.78;  }
.usp__cube--5{ --dur:1.5s;  --lag:.62s;  --peak:1.15; }
.usp__cube--6{ --dur:2.1s;  --lag:.35s;  --peak:.85;  }
.usp__cube--7{ --dur:2.9s;  --lag:.08s;  --peak:1.25; }
.usp__card:hover .usp__cube{
  animation:usp-breathe var(--dur, 2s) ease-in-out var(--lag, 0s) infinite;
}
@keyframes usp-breathe{
  0%,  100%{ transform:scale(1); }
  50%      { transform:scale(var(--peak, 1.15)); }
}

/* the support mark is inline so its two rings can answer the pointer: the
   arrows turn one way, the dotted ring the other, and only while hovered */
.usp__icon--care{ height:auto; }
.usp__ring,
.usp__dots{
  transform-box:view-box; transform-origin:73.5px 73.5px;
  animation:usp-spin-cw 18s linear infinite paused;
}
.usp__dots{ animation-name:usp-spin-ccw; animation-duration:26s; }
.usp__card:hover .usp__ring,
.usp__card:hover .usp__dots{ animation-play-state:running; }
/* the arrows run with the clock, the dotted ring against it */
@keyframes usp-spin-cw { to{ transform:rotate(360deg);  } }
@keyframes usp-spin-ccw{ to{ transform:rotate(-360deg); } }
.usp__text{
  font-size:clamp(13px, 1.05vw, 16px); font-weight:500; line-height:1.5;
  color:var(--text);
}

/* ---------- equipment strip ----------
   The same five-column rhythm the catalogue uses, with a rule over and under
   the row and a hairline down the middle of every gutter. */
.cats{
  --cats-pad:clamp(34px, 4.4vw, 76px);
  position:relative;
  padding-top:var(--cats-pad);
}
.cats__row{
  display:grid;
  grid-template-columns:repeat(5, minmax(0, 1fr));
  column-gap:44px;
}
/* Figma cuts the rule at every gutter rather than running it across the row,
   so it belongs to the cell. The mock's segments are 298/298/303/304/304 wide
   against a 44px gap — the same construction as the partner grid. */
.cats__row > .cat{
  position:relative;
  border-top:1px solid var(--tint);
  border-bottom:1px solid var(--tint);
}
/* and the vertical stops short of both, so the crossings stay open: the mock
   runs it 1230→1591 inside a row ruled at 1221 and 1612 */
.cats__row > .cat + .cat::before{
  content:"";
  position:absolute; left:-22px; top:10px; bottom:21px;
  width:1px;
  background:var(--tint);
}
/* Each card arrives as it reaches the screen, one after the next. Only the
   contents move — the rules around the cell are the grid and stay put. The
   script adds .is-armed, so with it switched off nothing is ever hidden. */
.cats.is-armed .cat__link{
  opacity:0;
  transform:translateY(20px);
  transition:opacity .55s ease var(--in-lag, 0s),
             transform .55s cubic-bezier(.22, .61, .36, 1) var(--in-lag, 0s);
}
.cats.is-armed .cat.is-in .cat__link{ opacity:1; transform:none; }
.cat__link{
  display:flex; flex-direction:column;
  height:100%; padding:26px 0 30px;
}
.cat__shot{
  position:relative;
  display:block;
  aspect-ratio:1 / 1;
}
.cat__shot img{
  position:absolute; inset:13%;
  width:74%; height:74%;
  object-fit:contain;
  mix-blend-mode:multiply;
  transition:transform .3s ease;
}
.cat__link:hover .cat__shot img{ transform:translateY(-8px); }
.cat__name{
  margin-top:auto; padding-top:22px;
  font-size:clamp(13px, 1.05vw, 16px); font-weight:600; line-height:1.3;
  letter-spacing:-.03em;
  color:var(--text);
  transition:color .18s ease;
}
.cat__link:hover .cat__name{ color:var(--link); }
/* the controls belong to the slider, not to the space over it: they sit in
   its top right corner, level with the top of the last card's picture. Out of
   flow, so the row starts at the section's own padding. */
.cats__nav{
  position:absolute; right:0; top:calc(var(--cats-pad) + 26px);
  z-index:2;
  display:flex; gap:12px;
}

/* ---------- key solutions ---------- */
.solutions{
  display:grid;
  grid-template-columns:38.5% minmax(0, 1fr);
  column-gap:clamp(24px, 3vw, 52px);
  padding-top:clamp(40px, 5.4vw, 92px);
}
.solutions__intro{ display:flex; flex-direction:column; align-items:flex-start; }
/* narrow enough to put «компании» on its own line, as the mock sets it */
.solutions__intro .block-title{ max-width:560px; }
.solutions__lead{
  max-width:341px; margin-top:clamp(20px, 2.6vw, 46px);
  font-size:14px; font-weight:500; line-height:1.6;
  color:var(--text-body);
}
.solutions__intro .btn-wide{ margin-top:auto; }

.solutions__list{ min-width:0; }
.solution{
  display:grid;
  grid-template-columns:226px minmax(0, 1fr) 41px;
  align-items:start;
  gap:0 clamp(20px, 2.4vw, 42px);
  padding:clamp(16px, 1.8vw, 26px) 0 clamp(26px, 3vw, 44px);
  border-top:1px solid var(--tint);
}
.solution:last-child{ border-bottom:1px solid var(--tint); }
.solution__shot{
  display:block;
  aspect-ratio:226 / 138;
  overflow:hidden;
  background:var(--surface);
}
.solution__shot img{
  width:100%; height:100%;
  object-fit:cover;
  transition:transform .35s ease;
}
/* the whole row is one link, so it answers as one: the shot pushes past its
   own frame, which crops it — that is what .solution__shot's overflow is for */
.solution:hover .solution__shot img,
.solution:focus-within .solution__shot img{ transform:scale(1.06); }
.solution__num{
  grid-column:2; grid-row:1;
  font-size:14px; font-weight:500; line-height:1;
  color:var(--num);
}
.solution__body{ grid-column:2; grid-row:1; padding-top:22px; min-width:0; }
.solution__title{
  font-size:clamp(18px, 1.5vw, 26px); font-weight:600; line-height:1.2;
  letter-spacing:-.03em;
}
.solution__title a{
  color:var(--text);
  transition:color .18s ease;
}
.solution__title a:hover{ color:var(--link); }
.solution__note{
  max-width:443px; margin-top:14px;
  font-size:13px; font-weight:500; line-height:1.55;
  color:var(--text-mute);
}
/* the square blue call at the end of every row — a link to the same place as
   the title, kept out of the tab order so the row is one stop, not two */
.solution__go{
  grid-column:3; grid-row:1;
  position:relative;
  width:41px; height:40px;
  overflow:hidden;               /* the arrows leave and arrive through it */
  background:var(--brand);
  transition:background .18s ease;
}
.solution:hover .solution__go,
.solution:focus-within .solution__go{ background:var(--b-400); }
/* Two copies of the same glyph: the resting one leaves through the top right
   corner and the waiting one comes up from the bottom left. Because the pair
   is turned 45°, a plain translate along their own X axis is the diagonal. */
.solution__go-arrow{
  position:absolute; left:50%; top:50%;
  width:19px; height:13px; margin:-6.5px 0 0 -9.5px;
  background:var(--text-inv);
  transform:rotate(-45deg);
  transition:transform .34s cubic-bezier(.22, .61, .36, 1);
  -webkit-mask:var(--arrow-mask) no-repeat center / contain;
          mask:var(--arrow-mask) no-repeat center / contain;
}
.solution__go-arrow:last-child{ transform:rotate(-45deg) translateX(-190%); }
.solution:hover .solution__go-arrow:first-child,
.solution:focus-within .solution__go-arrow:first-child{
  transform:rotate(-45deg) translateX(190%);
}
.solution:hover .solution__go-arrow:last-child,
.solution:focus-within .solution__go-arrow:last-child{
  transform:rotate(-45deg) translateX(0);
}

/* ---------- industries ---------- */
.industry{
  position:relative;
  display:flex;
  min-height:clamp(460px, 55vw, 951px);
  margin-top:clamp(44px, 5.6vw, 96px);
  overflow:hidden;
  color:var(--text-inv);
}
.industry__media{ position:absolute; inset:0; z-index:0; }
/* the clips are stacked and cross-faded, so a slide change never shows a gap */
.industry__shot{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  opacity:0;
  transition:opacity .5s ease;
}
.industry__shot.is-on{ opacity:1; }
.industry__scrim{
  position:absolute; inset:0; z-index:0;
  background:linear-gradient(180deg, rgb(0 28 56 / .58) 0%, rgb(0 28 56 / .28) 42%, rgb(0 28 56 / .78) 100%);
}
.industry__inner{
  position:relative; z-index:1;
  display:flex; flex-direction:column;
  padding:clamp(34px, 3.6vw, 61px) 0 clamp(34px, 4vw, 66px);
}
.industry__eyebrow{
  font-size:clamp(18px, 1.6vw, 28px); font-weight:600; letter-spacing:-.03em;
}
/* copy on the left, the controls in the opposite corner: the arrows first and
   the progress under them, both flush with the right edge of the block */
.industry__foot{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:clamp(24px, 4vw, 70px);
  margin-top:auto;
}
/* the slides share one grid cell, so the block keeps the height of the tallest
   and nothing below it jumps as they change */
.industry__copy{ display:grid; max-width:478px; }
.industry__slide{
  grid-area:1 / 1;
  opacity:0; visibility:hidden;
  transform:translateY(14px);
  transition:opacity .45s ease, transform .45s ease, visibility .45s;
}
.industry__slide.is-on{ opacity:1; visibility:visible; transform:none; }
.industry__title{
  max-width:470px; margin-top:clamp(30px, 4vw, 70px);
  font-size:clamp(26px, 2.8vw, 48px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
}
.industry__lead{
  margin-top:clamp(16px, 1.8vw, 30px);
  font-size:14px; font-weight:500; line-height:1.55;
  color:var(--text-inv-soft);
}
.industry__side{
  display:flex; flex-direction:column; align-items:flex-end;
  gap:clamp(16px, 1.8vw, 30px);
  flex:none;
}
.industry__nav{ display:flex; gap:12px; }
.industry__bar{
  display:flex; gap:11px;
  width:clamp(240px, 29vw, 503px);
}
/* --fill comes from the clip's own playhead: slides already shown read 100%,
   the running one grows, the rest stay at 0 */
.industry__seg{
  flex:1; height:5px;
  background:linear-gradient(to right,
    var(--text-inv) 0 var(--fill, 0%),
    rgb(255 255 255 / .3) var(--fill, 0%) 100%);
}

/* ---------- about ---------- */
.about{ padding-top:clamp(40px, 5.4vw, 92px); }
.about{
  display:grid;
  grid-template-columns:38.5% minmax(0, 1fr);
  column-gap:clamp(24px, 3vw, 52px);
}
.about__title{ max-width:525px; }
.about__body{ min-width:0; }
.about__lead{
  font-size:15px; font-weight:500; line-height:1.6;
  color:var(--text-body);
}
.figures{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:clamp(24px, 3vw, 52px);
  margin-top:clamp(30px, 3.6vw, 62px);
}
/* a <dd> carries a 40px indent from the browser, which would step the rule,
   the caption and the note in from the number they belong to */
.figure dd{ margin-inline-start:0; }
.figure__num{
  /* the value counts up on the way in, and proportional digits would make the
     number twitch as it climbs */
  font-variant-numeric:tabular-nums;
  font-size:clamp(48px, 5.4vw, 92px);
  font-weight:600; line-height:.9; letter-spacing:-.03em;
  color:var(--text-body);
}
.figure__label{
  margin-top:18px; padding-top:16px;
  border-top:1px solid var(--tint);
  font-size:clamp(15px, 1.3vw, 20px); font-weight:600; line-height:1.3;
  letter-spacing:-.03em;
  color:var(--text);
}
.figure__note{
  margin-top:12px;
  font-size:13px; font-weight:500; line-height:1.55;
  color:var(--text-mute);
}
.about__shots{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:clamp(12px, 1.2vw, 20px);
  margin-top:clamp(24px, 3vw, 50px);
}
.about__shots img{
  width:100%; height:auto;
  aspect-ratio:500 / 317;
  object-fit:cover;
}

/* ---------- advantages ----------
   A scene, not a block. The section is --adv-run tall, its stage is pinned for
   the whole of it, and the scroll drives three things at once: the logo
   sequence behind, the four notes drifting past at their own speeds, and the
   veil that comes up as the white page rides over the top — the same move the
   hero makes, so the page opens and closes on the same gesture.

   Everything below is the resting state: an ordinary block with the notes
   under the heading. The scene is layered on top of it by .adv.is-scene, which
   the script adds only on a wide screen, with motion allowed. */
.adv{
  position:relative;
  /* the radial wash is painted past the box on the narrowest phones */
  overflow:hidden;
  margin-top:clamp(44px, 5.6vw, 96px);
  /* named once and inherited into .adv__stage below, so the resting block and
     the pinned scene can never drift into two different dark backgrounds */
  --adv-dark: linear-gradient(160deg, #1a1f2b 0%, #141824 46%, #10192e 100%);
  background:
    radial-gradient(120% 90% at 8% 104%, rgb(2 99 187 / .55) 0%, rgb(2 99 187 / 0) 62%),
    var(--adv-dark);
  color:var(--text-inv);
}
.adv__stage{
  position:relative;
  padding:clamp(44px, 5vw, 92px) 0 clamp(44px, 5vw, 86px);
}
/* the clip carries the background art, tile and all, so nothing is drawn twice */
.adv__seq{
  position:absolute; inset:0; z-index:0;
  width:100%; height:100%;
  object-fit:cover;
  pointer-events:none;
}
.adv__dim{
  position:absolute; inset:0; z-index:2;
  background:var(--veil);
  opacity:0;
  pointer-events:none;
  will-change:opacity;
}
.adv__inner{ position:relative; z-index:1; }
.adv__title{
  max-width:660px;
  font-size:clamp(24px, 2.5vw, 42px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
}
.adv__list{
  list-style:none;
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:clamp(26px, 3vw, 48px) clamp(24px, 4vw, 70px);
  margin-top:clamp(30px, 3.4vw, 56px);
}
.adv__item{
  padding-top:14px;
  border-top:1px solid rgb(255 255 255 / .35);
}
/* these four carry the section on their own — they are read across a whole
   screen in the scene, so they run a step larger than the body text */
.adv__num{
  display:block;
  font-size:clamp(15px, 1.15vw, 20px); font-weight:600; line-height:1;
  color:var(--text-inv);
}
.adv__item p{
  margin-top:14px;
  max-width:400px;
  font-size:clamp(16px, 1.25vw, 21px); font-weight:500; line-height:1.45;
  color:var(--text-inv-soft);
}
/* the layer that rides over the pinned stage — opaque, and above it */
.adv-after{ position:relative; z-index:1; background:var(--n-000); }
/* it starts one screen before the section ends, which is the overlap: the
   stage is still pinned while this slides up over it. The veil under .adv's
   own stacking context follows it up, so the stage darkens as it is covered —
   the hero's move, at the other end of the page. */
.adv.is-scene + .adv-after{ margin-top:-100vh; }

/* ---- the scene ---- */
.adv.is-scene{
  /* three screens of travel: two for the notes, one for the white to arrive */
  --adv-run:400vh;
  /* the height, in vh, at which a note is fully faded — it has to clear the
     heading, which is taller on a narrow screen. Read by the script. */
  --adv-floor:26;
  height:var(--adv-run);
  /* z-index:0 keeps the veil inside this box: without a stacking context here
     the veil's z-index:2 would paint over the white page that covers it */
  z-index:0;
  overflow:visible;              /* a clipping ancestor would break the pin */
  background:none;
}
.adv.is-scene .adv__stage{
  position:sticky; top:0;
  display:flex; align-items:center;
  height:100vh; padding:0;
  overflow:hidden;
  background:
    radial-gradient(120% 90% at 8% 104%, rgb(2 99 187 / .55) 0%, rgb(2 99 187 / 0) 62%),
    var(--adv-dark);
}
/* Full height, because the notes are positioned against this box and have to
   be able to cross the whole stage. Its width is left to .shell — that is what
   puts the heading and the notes on the site's content line, and setting
   width:100% here would take the block full-bleed on a wide screen. */
.adv.is-scene .adv__inner{ align-self:stretch; }
/* 0 is the edge of .shell, which is the content line every other section
   heading starts on — absolute positioning would otherwise lose it */
.adv.is-scene .adv__title{
  position:absolute; left:0; right:0; top:clamp(90px, 9vh, 130px);
  max-width:min(660px, 46vw);
  margin:0;
}
/* the notes leave the grid and ride the screen, each on its own column and at
   its own speed — --y and --o are written by the script every frame */
.adv.is-scene .adv__list{
  display:block;
  margin:0;
  position:absolute; inset:0;
}
.adv.is-scene .adv__item{
  position:absolute;
  width:min(30%, 420px);
  top:0;
  opacity:var(--o, 0);
  transform:translate3d(0, var(--y, 60vh), 0);
  will-change:transform, opacity;
}
.adv.is-scene .adv__item--1{ left:0; }
.adv.is-scene .adv__item--2{ left:22%; }
.adv.is-scene .adv__item--3{ left:57%; }
.adv.is-scene .adv__item--4{ right:0; }

/* ---------- news ---------- */
.news{ padding-top:clamp(40px, 5.4vw, 92px); }
.news__head{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:20px;
  padding-bottom:clamp(24px, 3vw, 50px);
}
.posts--3{ grid-template-columns:repeat(3, minmax(0, 1fr)); border-bottom:0; padding-bottom:0; }
/* a rule over and under each card, broken at every gutter, as in the mock */
.posts--3 > .post{ padding-bottom:26px; border-bottom:1px solid var(--tint); }
/* the two-column grid draws its hairline on every even card; over three
   columns it belongs to every card that does not open a row — the old rule
   read 2n and so swallowed the line between the first and the second */
.posts--3 > .post:not(:nth-child(3n+1))::before{
  content:"";
  position:absolute; left:-26px; top:14px; bottom:14px;
  width:1px;
  background:var(--tint);
}

/* Each card arrives as it reaches the screen, one after the next — same
   technique as the equipment strip. The rule around the card is the grid and
   stays put; only its contents fade and lift. Script adds .is-armed, so with
   it switched off nothing is ever hidden. */
.news.is-armed .post > *{
  opacity:0;
  transform:translateY(20px);
  transition:opacity .55s ease var(--in-lag, 0s),
             transform .55s cubic-bezier(.22, .61, .36, 1) var(--in-lag, 0s);
}
.news.is-armed .post.is-in > *{ opacity:1; transform:none; }

/* ---------- technology partners ---------- */
.techpart{ padding-top:clamp(40px, 5.4vw, 92px); }
.techpart__grid{
  display:grid;
  grid-template-columns:repeat(5, minmax(0, 1fr));
  column-gap:44px;
  margin-top:clamp(26px, 3vw, 52px);
}
/* the rule is cut per cell, so every gutter shows a gap — that is how the
   mock draws it, and it is why the border sits on the cell and not the grid */
.techpart__grid > li{
  position:relative;
  border-top:1px solid var(--tint);
}
.techpart__grid > li:nth-last-child(-n+5){ border-bottom:1px solid var(--tint); }
/* the vertical stops short of both rules, so the crossings stay open */
.techpart__grid > li:not(:nth-child(5n+1))::before{
  content:"";
  position:absolute; left:-22px; top:14px; bottom:14px;
  width:1px;
  background:var(--tint);
}
.techpart__grid a{
  display:grid; place-items:center;
  min-height:clamp(120px, 12vw, 210px);
  padding:24px 8px;
  transition:opacity .18s ease;
}
.techpart__grid a:hover{ opacity:.6; }
/* logos arrive the same way the cards above do: the grid rule sits on the
   cell and stays still, only the logo fades in — otherwise the lattice of
   hairlines would look like it was drawing itself in one gutter at a time */
.techpart.is-armed .techpart__grid > li > a{
  opacity:0;
  transform:translateY(20px);
  transition:opacity .55s ease var(--in-lag, 0s),
             transform .55s cubic-bezier(.22, .61, .36, 1) var(--in-lag, 0s);
}
.techpart.is-armed .techpart__grid > li.is-in > a{ opacity:1; transform:none; }
.techpart__grid img{
  max-width:min(100%, 186px); height:auto;
  object-fit:contain;
}

/* the same scene on a phone, with the runway shortened so the block is not an
   endless scroll, and the notes on the full column, alternating sides */
@media (max-width:1023px){
  .adv.is-scene{ --adv-run:320vh; --adv-floor:32; }
  .adv.is-scene .adv__title{ max-width:none; }
  .adv.is-scene .adv__item{ width:min(80%, 420px); }
  .adv.is-scene .adv__item--2,
  .adv.is-scene .adv__item--4{ left:auto; right:0; }
  .adv.is-scene .adv__item--3{ left:0; }
}

@media (max-width:1279px){
  .solutions,
  .about{ grid-template-columns:minmax(0, 1fr); row-gap:clamp(24px, 3vw, 40px); }
  .solutions__intro .btn-wide{ margin-top:clamp(20px, 3vw, 34px); }
  .solution{ grid-template-columns:180px minmax(0, 1fr) 41px; }
  .cats__row{ column-gap:30px; }
  .cats__row > .cat + .cat::before{ left:-15px; }
  .techpart__grid{ column-gap:30px; }
  .techpart__grid > li + li::before{ left:-15px; }
}

@media (max-width:1023px){
  .usp__grid{ grid-template-columns:minmax(0, 1fr); }
  .usp__card{ min-height:0; }
  /* one row still, but scrolled: two machines fit the screen and the third
     shows half, which is what says there is more to the right. The row bleeds
     to both edges so the peek reaches the screen, not the gutter. */
  .cats__row{
    --cat-slide-gap:20px;
    display:flex;
    column-gap:var(--cat-slide-gap);
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    scroll-behavior:smooth;
    scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
  }
  .cats__row::-webkit-scrollbar{ display:none; }
  .cats__row > .cat{
    /* 2 whole cards + half of the next + the two gaps between them */
    flex:0 0 calc((100% - 2 * var(--cat-slide-gap)) / 2.5);
    scroll-snap-align:start;
  }
  .cats__row > .cat + .cat::before{ left:calc(var(--cat-slide-gap) / -2); }
  /* back to two columns, so the base .posts hairline on every even card is
     the right one again */
  .posts--3{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .posts--3 > .post:not(:nth-child(3n+1))::before{ content:none; }
  .techpart__grid{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
  .techpart__grid > li + li::before{ display:none; }
  .figures{ gap:26px; }
}

@media (max-width:767px){
  .hero__mark{ display:none; }
  .industry__foot{ flex-direction:column; align-items:stretch; gap:24px; }
  .industry__side{ align-items:flex-start; }
  .industry__bar{ width:100%; }
  /* 45px round buttons crowd a phone; the glyph shrinks with the circle */
  .round{ width:36px; height:36px; }
  .round::before{ width:13px; height:7px; }
  .cats__nav{ gap:8px; top:calc(var(--cats-pad) + 18px); }
  /* stacked: the picture takes the width and the copy sits under it. Every
     part needs its row spelled out — the base rules pin them all to row 1,
     and the picture would otherwise be pushed below the copy with its gap
     stranded at the bottom of the row. */
  .solution{ grid-template-columns:minmax(0, 1fr) 41px; }
  .solution__shot{ grid-column:1 / -1; grid-row:1; margin-bottom:22px; }
  .solution__num,
  .solution__body{ grid-column:1; grid-row:2; }
  .solution__go{ grid-column:2; grid-row:2; }
  .posts--3{ grid-template-columns:minmax(0, 1fr); }
  /* two columns leave about 145px each on a phone, which is too narrow for
     the sentences these notes carry */
  .adv__list{ grid-template-columns:minmax(0, 1fr); }
  .figures{ grid-template-columns:minmax(0, 1fr); }
  .about__shots{ grid-template-columns:minmax(0, 1fr); }
  .techpart__grid{ grid-template-columns:repeat(2, minmax(0, 1fr)); }

  /* an <ol> brings a 40px indent of its own, which on a phone reads as the
     rows being pushed off the column everything else lines up on */
  .solutions__list,
  .adv__list{ padding-inline-start:0; }

  /* the second call in a block takes the column rather than sitting in it */
  .solutions__intro .btn-wide,
  .news__head .btn-wide{ width:100%; }

  /* the partner marks are drawn for five across; at two they have to come
     down or each one reads as a banner */
  .techpart__grid img{ max-width:min(50%, 93px); }
  .techpart__grid a{ min-height:clamp(84px, 22vw, 120px); padding:16px 8px; }
}
/* =========================================================
   SITE SEARCH
   Opens from the magnifier in the header and drops under it, over the page.
   Above the menu scrim so it is never dimmed while it holds the focus, and
   under the header itself, which it hangs from.
   ========================================================= */
.sitesearch{
  position:fixed; left:0; right:0; top:var(--topbar-h); z-index:55;
  background:var(--n-000);
  box-shadow:inset 0 1px 0 var(--tint), 0 12px 28px rgb(0 0 0 / .1);
  transform:translateY(-100%);
  opacity:0; visibility:hidden;
  transition:transform .3s ease, opacity .3s ease, visibility .3s;
}
:root.search-on .sitesearch{ transform:none; opacity:1; visibility:visible; }
.sitesearch[hidden]{ display:none; }

.sitesearch__inner{
  position:relative;
  padding:clamp(22px, 2.6vw, 44px) 0 clamp(18px, 2vw, 32px);
}
.sitesearch__form{
  display:flex; flex-wrap:wrap; gap:12px;
  padding-right:56px;   /* room for the close, which sits in the corner */
}
.sitesearch__field{
  flex:1 1 320px; min-width:0;
  height:52px; padding:0 18px;
  border:1px solid var(--tint); border-radius:2px;
  background:var(--surface);
  font-size:clamp(15px, 1.2vw, 18px); font-weight:500; letter-spacing:-.02em;
  color:var(--text);
  transition:border-color .18s ease, background .18s ease;
}
.sitesearch__field::placeholder{ color:var(--text-mute); font-weight:500; }
.sitesearch__field:focus{ outline:none; border-color:var(--brand); background:var(--n-000); }
/* the browser's own clear button would sit on top of ours */
.sitesearch__field::-webkit-search-decoration,
.sitesearch__field::-webkit-search-cancel-button{ -webkit-appearance:none; }
.sitesearch__go{
  flex:none;
  height:52px; padding:0 26px;
  background:var(--brand);
  font-size:11px; font-weight:700; letter-spacing:.02em; text-transform:uppercase;
  color:var(--text-inv);
  cursor:pointer;
  transition:background .18s ease;
}
.sitesearch__go:hover{ background:var(--b-400); }
.sitesearch__hint{
  margin-top:12px; padding-right:56px;
  font-size:12px; font-weight:500; line-height:1.5;
  color:var(--text-mute);
}
.sitesearch__close{
  position:absolute; right:0; top:clamp(22px, 2.6vw, 44px);
  width:44px; height:52px;
  background:none; cursor:pointer;
}
.sitesearch__close::before,
.sitesearch__close::after{
  content:"";
  position:absolute; left:50%; top:50%;
  width:17px; height:1px; margin-left:-8.5px;
  background:var(--text);
  transition:background .18s ease;
}
.sitesearch__close::before{ transform:rotate(45deg); }
.sitesearch__close::after { transform:rotate(-45deg); }
.sitesearch__close:hover::before,
.sitesearch__close:hover::after{ background:var(--brand); }

@media (max-width:767px){
  .sitesearch__form{ padding-right:0; }
  .sitesearch__go{ flex:1 1 100%; }
  .sitesearch__close{ top:8px; }
  .sitesearch__hint{ padding-right:0; }
}

/* =========================================================
   ABOUT PAGE  (Figma 1931-16548)
   Every section here is one the site already owns — the hero, the «о компании»
   block, the industries slider, the news grid, the equipment strip and the
   partner grid. Only the brand hero, the creed band and the FAQ are new.
   ========================================================= */

/* ---- hero: the wordmark over the descriptive line, the mark on the right ---- */
.hero--about{
  min-height:clamp(430px, 31vw, 577px);
  padding-bottom:clamp(28px, 2.7vw, 46px);
}
/* this hero puts its copy on the content line rather than in the offset
   column the section pages use */
.hero--about .hero__body{
  flex:none;
  margin-left:0; margin-top:clamp(16px, 1.6vw, 26px);
  padding-top:0;
}
.hero__word{
  font-size:clamp(56px, 6vw, 103px);
  font-weight:600; line-height:.94; letter-spacing:-.04em;
}
.hero__title--about{
  max-width:760px; margin-top:clamp(18px, 2.4vw, 40px);
  font-size:clamp(22px, 2.4vw, 40px);
  font-weight:600; line-height:1.15; letter-spacing:-.03em;
}
/* the mock stands the call at the far right of the hero, on its own line */
.hero__foot--about{
  display:flex; justify-content:flex-end;
  margin-top:clamp(20px, 2vw, 34px);
}
/* the mock hangs it off the right edge, cropped by the hero */
.hero__cube{
  position:absolute; z-index:0;
  left:49.3%; top:3%;                 /* the mock's 852 / 58 on a 1728 frame */
  width:clamp(280px, 42vw, 723px); height:auto;
  pointer-events:none;
}

/* ---- «о компании» on this page: a note in the rail, the claim as heading ---- */
.about--page{ padding-top:clamp(44px, 5.6vw, 96px); }
.about__note{
  max-width:300px;
  font-size:13px; font-weight:500; line-height:1.55;
  color:var(--text-mute);
}
.about__claim{ max-width:940px; }
.about--page .about__lead{ margin-top:clamp(22px, 2.6vw, 44px); }

/* ---- the creed band and the four things the company does ---- */
.creed{
  margin-top:clamp(44px, 5.6vw, 96px);
  padding:clamp(48px, 6vw, 100px) 0 clamp(48px, 6vw, 96px);
  background:var(--surface);
}
.creed__inner{ display:flex; flex-direction:column; align-items:center; }
/* the mark ships on white rather than with an alpha channel; multiply drops
   it onto the band instead of boxing it */
.creed__mark{
  width:clamp(120px, 11vw, 178px); height:auto;
  mix-blend-mode:multiply;
}
.creed__claim{
  max-width:978px; margin-top:clamp(24px, 3vw, 52px);
  font-size:clamp(20px, 2.1vw, 36px);
  font-weight:600; line-height:1.3; letter-spacing:-.03em;
  text-align:center;
}
.values{
  list-style:none;
  display:grid; grid-template-columns:repeat(4, minmax(0, 1fr));
  gap:clamp(14px, 1.2vw, 19px);
  width:100%; margin-top:clamp(34px, 4.4vw, 80px);
}
.value{
  display:flex; flex-direction:column;
  min-height:clamp(320px, 27vw, 464px);
  padding:clamp(20px, 2.4vw, 38px);
  background:var(--n-000);
}
/* a fixed slot rather than a fixed icon: the four drawings are not one size
   in Figma either, and the slot is what puts all four titles on one line */
.value__icon{
  display:block; flex:none;
  width:clamp(96px, 11vw, 189px);
  height:clamp(132px, 13.6vw, 225px);
  background:no-repeat left center / contain;
}
.value__icon--cube  { background-image:url("assets/about-make.svg"); }
.value__icon--import{ background-image:url("assets/about-import.svg"); }
.value__icon--layers{ background-image:url("assets/about-dev.svg"); }
.value__icon--links { background-image:url("assets/about-care.svg"); }
.value__title{
  margin-top:clamp(14px, 1.6vw, 26px);
  font-size:clamp(17px, 1.5vw, 24px);
  font-weight:600; line-height:1.25; letter-spacing:-.03em;
}
.value__note{
  margin-top:14px;
  font-size:13px; font-weight:500; line-height:1.55;
  color:var(--text-mute);
}

/* ---- FAQ: the question list is <details>, so the browser owns the state ---- */
.faq{
  display:grid; grid-template-columns:38.5% minmax(0, 1fr);
  column-gap:clamp(24px, 3vw, 52px);
  padding-top:clamp(44px, 5.6vw, 92px);
}
.faq__intro{ display:flex; flex-direction:column; align-items:flex-start; }
.faq__intro .block-title{ max-width:600px; }
.faq__ask{ margin-top:clamp(26px, 3.4vw, 56px); }
.faq__list{ min-width:0; }
.faq__item{ border-top:1px solid var(--tint); }
.faq__item:last-child{ border-bottom:1px solid var(--tint); }
.faq__q{
  position:relative;
  display:block;
  padding:clamp(22px, 2.4vw, 32px) 64px clamp(22px, 2.4vw, 32px) 0;
  font-size:clamp(15px, 1.3vw, 20px);
  font-weight:600; line-height:1.3; letter-spacing:-.03em;
  color:var(--text);
  cursor:pointer;
  transition:color .18s ease;
  list-style:none;                 /* the marker is drawn below instead */
}
.faq__q::-webkit-details-marker{ display:none; }
.faq__q:hover{ color:var(--brand); }
.faq__item[open] > .faq__q{ color:var(--text); }
/* a plus that loses its upright stroke when the row opens */
.faq__sign{
  position:absolute; right:0; top:50%;
  width:23px; height:23px; margin-top:-11.5px;
}
.faq__sign::before,
.faq__sign::after{
  content:"";
  position:absolute; left:50%; top:50%;
  background:var(--text);
  transition:transform .22s ease, opacity .22s ease, background .18s ease;
}
.faq__sign::before{ width:23px; height:2px; margin:-1px 0 0 -11.5px; }
.faq__sign::after { width:2px; height:23px; margin:-11.5px 0 0 -1px; }
.faq__item[open] .faq__sign::after{ transform:scaleY(0); opacity:0; }
.faq__q:hover .faq__sign::before,
.faq__q:hover .faq__sign::after{ background:var(--brand); }
.faq__a{
  padding:0 64px clamp(24px, 2.6vw, 34px) 0;
  font-size:14px; font-weight:500; line-height:1.6;
  color:var(--text-mute);
}
.faq__a p{ max-width:790px; }

/* the equipment strip carries a heading on this page, so its controls move
   down beside it rather than sitting on the row */
.cats__title{ max-width:790px; padding-right:130px; }
.about-page .cats__nav{ top:auto; }

@media (max-width:1279px){
  .faq{ grid-template-columns:minmax(0, 1fr); row-gap:clamp(22px, 3vw, 36px); }
  .values{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
}

@media (max-width:767px){
  .hero__cube{ opacity:.35; right:-40px; }
  .about__note{ max-width:none; margin-bottom:22px; }
  .values{ grid-template-columns:minmax(0, 1fr); }
  .value{ min-height:0; }
  .value__icon{ height:clamp(96px, 26vw, 132px); }
  .faq__ask{ width:100%; }
  .faq__q{ padding-right:44px; }
  .faq__a{ padding-right:0; }
  .cats__title{ padding-right:0; }
}

/* =========================================================
   ARTICLE  (Figma 1931-14148)
   A reading page: the copy runs in one column that starts at the same rail the
   rest of the site uses, and the contents list rides along on the right. The
   product strip, the gallery, the table and «смотрите так же» hang off that
   column rather than the shell, so the measure never changes mid-article.
   ========================================================= */
/* The only page with no hero under the fixed bar, so it owns the clearance.
   No padding at the foot: the consultation block and the footer are the last
   children of <main>, and padding there would show as a white strip under the
   footer rather than as space after the article. */
.article{ padding-top:var(--topbar-h); }
/* the trail on this page is .crumbs, the same component the other white
   pages use — nothing here to restyle */

/* one grid for the whole piece: copy | rail. --col-art is the mock's 361 on a
   1728 frame, i.e. the column the headline and every block below it start on */
.article__grid{
  --col-art:17.4%;
  /* the mock's 954: the gallery, the table and the related list all share it,
     while the running copy is allowed to run a little wider */
  --art-measure:954px;
  display:grid;
  grid-template-columns:var(--col-art) minmax(0, 1fr) 322px;
  column-gap:clamp(20px, 2.6vw, 44px);
  align-items:start;
  padding-top:clamp(30px, 4.4vw, 76px);
}
.article__head,
.author,
.article__body{ grid-column:2 / 4; min-width:0; }
/* the rail sits beside the body, so the body gives its track back */
.article__body{ grid-column:2 / 3; }

/* the mock stands a back control in the left rail, level with the headline */
.article__back{
  grid-column:1 / 2; grid-row:1;
  justify-self:start;
  width:50px; height:50px;
  margin-top:clamp(30px, 4vw, 68px);
}
.article__date{
  font-size:clamp(15px, 1.3vw, 20px); font-weight:500;
  color:var(--text-mute);
}
.article__title{
  max-width:1330px; margin-top:clamp(16px, 1.8vw, 30px);
  font-size:clamp(28px, 3.3vw, 56px);
  /* the mock sets three lines in 253px, which is a good deal looser than a
     headline usually runs — it is a reading page, not a cover */
  font-weight:600; line-height:1.45; letter-spacing:-.03em;
}
/* .post__tags pads itself down to the foot of a card; here it is inline in
   the header and the padding would double the gap */
.article__tags{ margin-top:clamp(24px, 3.4vw, 59px); padding-top:0; }
.article__lead{
  max-width:1184px; margin-top:clamp(24px, 3.1vw, 54px);
  font-size:clamp(14px, 1.15vw, 17px); font-weight:500; line-height:1.6;
  color:var(--text-body);
}
.article__lead a{ color:var(--link); text-decoration:underline; }
.article__lead a:hover{ color:var(--b-400); }

/* ---- the author card ---- */
.author{
  position:relative;
  display:flex; flex-direction:column; justify-content:flex-end;
  min-height:clamp(320px, 42vw, 721px);
  margin-top:clamp(34px, 6.5vw, 112px);
  padding:clamp(24px, 3vw, 52px);
  overflow:hidden;
  color:var(--text-inv);
  background:linear-gradient(196.7deg, #001353 28.464%, #0049a6 82.079%);
}
/* the mock scatters 63 brand-coloured squares over the gradient; they ship as
   one flat file rather than 63 elements */
.author__pixels{
  position:absolute; left:0; top:0; z-index:0;
  width:100%; height:100%;
  background:url("assets/art-pixels.svg") no-repeat left top / auto 100%;
  opacity:.85;
  pointer-events:none;
}
.author__logo{
  position:relative; z-index:1;
  align-self:flex-start;
  width:clamp(110px, 12vw, 208px); height:auto;
  margin-bottom:auto;
}
.author__body{ position:relative; z-index:1; max-width:560px; }
.author__name{
  font-size:clamp(28px, 3.2vw, 54px);
  font-weight:600; line-height:1.1; letter-spacing:-.03em;
}
.author__role{
  max-width:534px; margin-top:clamp(14px, 1.6vw, 26px);
  font-size:clamp(13px, 1.05vw, 15px); font-weight:500; line-height:1.55;
  color:var(--text-inv-soft);
}
.author__face{
  position:absolute; right:clamp(20px, 2.4vw, 42px); bottom:0; z-index:1;
  width:clamp(150px, 22vw, 305px); height:auto;
}

/* ---- the copy ---- */
.article__body{ margin-top:clamp(12px, 1vw, 16px); }
.article__kicker{
  margin-top:clamp(12px, 1vw, 16px);
  font-size:13px; font-weight:600; letter-spacing:-.02em;
  color:var(--text-mute);
}
.article__h2{
  margin-top:clamp(34px, 6vw, 104px);
  font-size:clamp(22px, 2.2vw, 36px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
}
.article__body p{
  margin-top:clamp(16px, 2vw, 35px);
  max-width:900px;
  font-size:14px; font-weight:500; line-height:1.65;
  color:var(--text-body);
}
.article__list{
  list-style:none;
  margin-top:clamp(18px, 2.3vw, 39px);
  max-width:1126px;
  font-size:14px; font-weight:500; line-height:1.75;
  color:var(--text-body);
}
.article__list li{ position:relative; padding-left:18px; }
.article__list li::before{
  content:"";
  position:absolute; left:0; top:.75em;
  width:5px; height:5px;
  background:var(--brand);
}
.article__list a{ color:var(--link); text-decoration:underline; }
.article__list a:hover{ color:var(--b-400); }

/* ---- contents, pinned while the piece scrolls past ---- */
.toc{
  position:sticky; top:calc(var(--stick-h) + 24px);
  align-self:start;                 /* a stretched grid item cannot travel */
  grid-column:3 / 4;
  margin-top:clamp(34px, 7.4vw, 127px);
}
.toc__list{ list-style:none; }
.toc__link{
  display:block;
  padding:5px 0;
  font-size:13px; font-weight:500; line-height:1.5;
  color:var(--text-mute);
  transition:color .18s ease;
}
.toc__link:hover{ color:var(--brand); }
.toc__link.is-here{ color:var(--text); font-weight:600; }

/* ---- the three products quoted in the piece ---- */
.products-strip{
  list-style:none;
  display:grid; grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:clamp(16px, 2vw, 34px);
  margin-top:clamp(22px, 3.5vw, 60px);
}
.product-card{ display:flex; flex-direction:column; min-width:0; }
.product-card__shot{
  position:relative;
  display:grid; place-items:center;
  aspect-ratio:317 / 290;
  padding:22px;
  background:var(--surface);
}
.product-card__shot img{
  max-width:70%; max-height:100%;
  object-fit:contain;
  mix-blend-mode:multiply;
}
.product-card__badge{
  position:absolute; right:10px; top:10px;
  padding:5px 10px;
  background:var(--b-950);
  font-size:10px; font-weight:600; letter-spacing:.02em;
  color:var(--text-inv);
}
.product-card__title{
  margin-top:18px;
  font-size:14px; font-weight:600; line-height:1.3; letter-spacing:-.02em;
}
.product-card__title a{ color:var(--text); transition:color .18s ease; }
.product-card__title a:hover{ color:var(--link); }
.product-card__note{
  margin-top:10px;
  font-size:12px; font-weight:500; line-height:1.45;
  color:var(--text-mute);
}
.product-card__spec{
  list-style:none;
  margin-top:14px; padding-top:12px;
  border-top:1px solid var(--tint);
  font-size:12px; font-weight:500; line-height:1.8;
  color:var(--text-mute);
}
.product-card__spec b{ font-weight:600; color:var(--text); }

/* ---- the gallery: two across, one of the tiles is a clip ---- */
.shots{
  list-style:none;
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:10px;
  max-width:var(--art-measure, 954px);
  margin-top:clamp(22px, 4vw, 69px);
}
.shots__item{ position:relative; }
.shots__item img{
  display:block;
  width:100%; aspect-ratio:472 / 361;
  object-fit:cover;
}
.shots__play{
  position:absolute; left:50%; top:50%;
  width:71px; height:71px; margin:-35.5px 0 0 -35.5px;
  background:var(--n-000);
  clip-path:polygon(0 0, 100% 50%, 0 100%);
  opacity:.9;
  pointer-events:none;
}

/* ---- the register table ----
   Not a boxed grid: every cell carries its own rule and the gutters break it,
   which is how the mock draws it and how the rest of the site rules its rows.
   Column widths are the mock's 449 / 335 / 170 of the 954 measure. */
.article__table{
  max-width:var(--art-measure, 954px);
  margin-top:clamp(22px, 3.5vw, 60px);
  overflow-x:auto;
}
.reg-table{
  width:100%; min-width:620px;
  border-collapse:separate; border-spacing:11px 0;
  margin-inline:-11px;                 /* the spacing must not inset the block */
  table-layout:fixed;
  text-align:left;
}
.reg-table th,
.reg-table td{
  padding:12px 0 20px;
  border-bottom:1px solid var(--tint);
  vertical-align:top;
}
.reg-table thead th{
  padding-top:0;
  font-size:11px; font-weight:500; letter-spacing:.04em; text-transform:uppercase;
  color:var(--text-mute);
}
.reg-table tbody th,
.reg-table tbody td{
  font-size:14px; font-weight:500; line-height:1.4;
  color:var(--text);
}
.reg-table tbody th{ font-weight:500; }
.reg-table col:first-child{ width:47.1%; }
.reg-table th:nth-child(2),
.reg-table td:nth-child(2){ width:35.1%; }
.reg-table th:nth-child(3),
.reg-table td:nth-child(3){ width:17.8%; }

/* ---- «смотрите так же» ----
   On the article's own measure rather than the shell's, image beside the copy,
   and a rule over every card the way the mock rules them. */
.article__also{
  padding-top:clamp(36px, 6.6vw, 114px);
  padding-bottom:clamp(40px, 6.5vw, 112px);   /* the space the mock leaves before the band */
  align-items:start;
}
.also{ grid-column:2 / 3; max-width:950px; min-width:0; }
.also__title{
  font-size:clamp(22px, 2.2vw, 36px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
}
.also__list{ list-style:none; margin-top:clamp(18px, 1.8vw, 31px); }
.also__item{
  display:grid; grid-template-columns:minmax(0, 438px) minmax(0, 1fr);
  column-gap:clamp(20px, 2.6vw, 42px);
  align-items:start;
  padding:clamp(18px, 2vw, 26px) 0 clamp(22px, 2.6vw, 38px);
  border-top:1px solid var(--tint);
}
.also__item:last-child{ border-bottom:1px solid var(--tint); }
.also__item .post__shot{ aspect-ratio:438 / 275; }
.also__item .post__body{ min-width:0; }
.also__item .post__date{ margin-top:0; }

@media (max-width:1279px){
  .article__grid{ grid-template-columns:minmax(0, 1fr); }
  .article__head,
  .author,
  .article__body,
  .also{ grid-column:1 / -1; }
  /* no rail to sit in, so the control goes back above the headline */
  .article__back{ grid-column:1 / -1; grid-row:auto; margin-top:0; }
  /* nothing to ride alongside, so the contents become a plain list up top */
  .toc{
    position:static;
    grid-column:1 / -1; grid-row:3;
    margin-top:clamp(24px, 3vw, 38px);
    padding:18px 0;
    border-top:1px solid var(--tint); border-bottom:1px solid var(--tint);
  }
  .toc__list{ display:flex; flex-wrap:wrap; gap:6px 22px; }
}

@media (max-width:767px){
  .author{ min-height:0; padding-bottom:clamp(140px, 42vw, 220px); }
  .author__face{ right:0; width:clamp(130px, 38vw, 200px); }
  .author__body{ max-width:none; }
  .products-strip{ grid-template-columns:minmax(0, 1fr); }
  .shots{ grid-template-columns:minmax(0, 1fr); }
  .also__item{ grid-template-columns:minmax(0, 1fr); row-gap:16px; }
}
