/* =========================================================
   БАЙТ — Технологическое партнерство
   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;
  --n-950: #0d0d0d;   /* the presence plate: neutral, not navy */

  /* 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 */
  --a-warm:   #fff8ee;   /* плашка ответа справочника в форме партнёрства */

  /* ===== 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 */
  --text-inv-cap:   var(--n-400);   /* captions over the hero and photography */

  /* 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);
  --surface-dark:   var(--n-950);  /* dark counterpart to --surface */
  --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");
  --upload-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 60'%3E%3Cpath d='M49.8125 28.0117C49.7165 28.0117 49.6202 28.0357 49.5242 28.0357C49.5722 27.5788 49.5962 27.1221 49.5962 26.6652C49.5962 18.8278 43.3673 12.4615 35.5385 12.4615C28.3818 12.4615 22.3634 17.7939 21.4267 24.6942C20.466 24.3817 19.4815 24.1895 18.4488 24.1895C13.0696 24.1895 8.69885 28.5648 8.69885 33.9503C8.69885 33.9983 8.72285 34.0463 8.72285 34.0705C8.29038 33.9985 7.83415 33.9503 7.37792 33.9503C3.53538 33.9501 0.461538 37.0516 0.461538 40.8501C0.461538 44.6485 3.33554 47.5385 7.15385 47.5385H31.3846V37.3846H25.3846L33.7068 26.2908L42 37.3846H36V47.5385H49.6154C54.9948 47.5385 59.5385 43.158 59.5385 37.7728C59.5625 32.3873 55.1917 28.0117 49.8125 28.0117Z' fill='%23000'/%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; }
/* textarea and select do not inherit the family on their own — left out, a
   message field renders in the UA's default face beside Montserrat fields */
input, textarea, select{ 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(26px, 3.6vw, 62px);
  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 !important;   /* перебивает любой сторонний img-ресет (плагины) */
}
/* 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); }

/* --------------------------------------------------------------
   .round--line is the same control drawn as an outline: a white
   disc on a hairline with a dark chevron. It belongs to standalone
   navigation — the «назад» control on a reading page — where a
   filled disc would read as a slider arrow. Hover follows the same
   rule as .round--soft, so all three skins behave alike.
   -------------------------------------------------------------- */
.round--line{
  background:var(--n-000);
  /* --rail, the same outline .btn-wide draws: a control boundary reads darker
     than a hairline divider, and the two must not disagree */
  box-shadow:inset 0 0 0 1px var(--rail);
  transition:background .18s ease, box-shadow .18s ease;
}
.round--line::before{
  background:var(--text);
  transition:background .18s ease;
}
.round--line:hover{ background:var(--brand); box-shadow:inset 0 0 0 1px var(--brand); }
.round--line:hover::before{ background:var(--n-000); }

/* ---------- 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; }
.specs__note{
  margin-top:18px;
  font-size:13px; font-weight:500; line-height:21px;
  color:var(--text-mute);
}

/* ---------- 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{
  position:relative;   /* anchors the autocomplete panel */
  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;
}
/* the article's «смотрите так же» is the same card in a wider frame, so it
   answers to the hover the same way */
.post:hover .post__shot img,
.also__item: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);
}
/* one step up, for a heading that opens a page rather than a section */
.block-title--lg{ font-size:clamp(28px, 3.13vw, 54px); }

/* 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;
  /* under the picture, which is centred in its cell, so the name is too —
     a left-aligned label reads as belonging to the gutter, not to the machine */
  text-align:center;
  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{
  position:relative;   /* anchors the autocomplete panel */
  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){
  /* the submit wraps to its own line here, so the corner is cleared by the
     field alone — that keeps the × level with it instead of above it */
  .sitesearch__form{ padding-right:0; }
  .sitesearch__field{ flex:0 1 calc(100% - 52px); }   /* growing would eat the corner back */
  .sitesearch__go{ flex:1 1 100%; }
  .sitesearch__hint{ padding-right:0; }
}

/* =========================================================
   SEARCH AUTOCOMPLETE
   Script appends one .ac panel to whichever search form it enhances — the
   header magnifier's and, on the results page, the hero's. Same component,
   same dataset, wherever a search field already exists on the page.
   ========================================================= */
.ac{
  position:absolute; top:calc(100% + 8px); left:0; right:0; z-index:60;
  display:flex; flex-direction:column;
  background:var(--n-000);
  border-radius:4px;
  box-shadow:0 18px 40px rgba(0,32,66,.18);
  max-height:min(70vh, 520px);
  opacity:0; visibility:hidden; transform:translateY(8px);
  transition:opacity .18s ease, transform .18s ease, visibility .18s;
}
/* "Показать все результаты" is a flex sibling of the scrolling area, not
   part of it — a long result list scrolls under it, but the call to action
   itself always stays put at the very bottom of the panel */
.ac__skeleton,
.ac__body,
.ac__empty{ flex:1 1 auto; min-height:0; overflow-y:auto; }
.ac.is-open{ opacity:1; visibility:visible; transform:translateY(0); }
.ac[hidden]{ display:none; }

/* .sitesearch is already a white panel with its own drop shadow — floating a
   second white card with a shadow of its own on top of it read as a card
   sitting on a card. Inside .sitesearch the results render as part of that
   same panel instead: a plain flex child that wraps onto its own row
   (.sitesearch__form already has flex-wrap for exactly this), no card chrome
   of its own. .hero__search has no such panel behind it — sitting on the
   hero photo, it still needs to be its own white card, so it keeps the base
   .ac styling above untouched. */
.ac--inline{
  position:static; flex:1 1 100%;
  border-radius:0; box-shadow:none; background:none;
  max-height:min(50vh, 420px);
  opacity:1; visibility:visible; transform:none; transition:none;
  /* .sitesearch__inner still reserves its own bottom padding below this —
     that gap was sized for one line of hint text, not a list of results, and
     it is what kept leaving air under "Показать все результаты". Pulling
     the exact same amount back with a negative margin lands .ac__all flush
     on the panel's real edge instead of floating above it. */
  margin-bottom:calc(-1 * clamp(18px, 2vw, 32px));
}

/* ---------- skeleton ----------
   Stands in for the moment a real lookup would still be in flight — there is
   no backend here, so script holds the actual render behind a short timeout
   just so this has something honest to fill. */
.ac__sk-row{ padding:11px 20px; }
.ac__sk-row span{
  display:block; height:10px; border-radius:2px;
  background:linear-gradient(90deg, var(--tint) 25%, var(--n-050) 37%, var(--tint) 63%);
  background-size:400% 100%;
  animation:ac-shimmer 1.4s ease-in-out infinite;
}
.ac__sk-row span + span{ margin-top:8px; width:60%; }
@keyframes ac-shimmer{ 0%{ background-position:100% 50%; } 100%{ background-position:0 50%; } }
@media (prefers-reduced-motion:reduce){
  .ac__sk-row span{ animation:none; }
}

/* ---------- results ---------- */
.ac__group + .ac__group{ border-top:1px solid var(--tint); }
.ac__group-title{
  padding:14px 20px 4px;
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  color:var(--text-mute);
}
.ac__list{ padding-bottom:6px; }
.ac__item{
  display:block;
  padding:9px 20px;
  font-size:14px; font-weight:500; line-height:1.4;
  color:var(--text);
  transition:background .15s ease;
}
.ac__item:hover,
.ac__item:focus-visible{ background:var(--surface); }
.ac__item mark{
  background:none; color:var(--brand); font-weight:700;
}

/* catalog rows only — a small plate, same recipe as .card__media, just at
   thumbnail size: a light square, the studio shot's white multiplied out
   rather than boxed in */
.ac__item--shot{ display:flex; align-items:center; gap:12px; }
.ac__item-img{
  flex:none;
  width:40px; height:40px; padding:5px;
  background:var(--n-050);
  object-fit:contain;
  mix-blend-mode:multiply;
}
.ac__item-title{ min-width:0; }

.ac__empty{
  padding:26px 20px;
  font-size:13px; text-align:center;
  color:var(--text-mute);
}
.ac__empty[hidden],
.ac__body:empty,
.ac__skeleton[hidden]{ display:none; }

.ac__all{
  flex:none;
  display:flex; align-items:center; justify-content:center; gap:8px;
  height:48px; border-top:1px solid var(--tint);
  font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.02em;
  color:var(--brand);
  transition:background .15s ease;
}
.ac__all:hover,
.ac__all:focus-visible{ background:var(--surface); }
.ac__all[hidden]{ display:none; }
.ac__all-count{ font-weight:600; text-transform:none; letter-spacing:0; color:var(--text-mute); }

/* =========================================================
   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.
   It then rides down with the reader, so its grid area has to be the whole
   rail rather than the headline's row — a sticky element can only travel
   inside the area it was placed in. Rows 1..3 are the header, the author card
   and the copy; the rail owns all three. */
.article__back{
  grid-column:1 / 2; grid-row:1 / 4;
  position:sticky; top:calc(var(--stick-h) + 24px);
  justify-self:start; align-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 same 1.2 every other heading on the site is set on, so a three-line
     headline reads as one block instead of three stacked lines */
  font-weight:600; line-height:1.2; 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; }
/* the mock rules the lead off above and below, across the whole column, and
   sets it in italic — it is a standfirst, not the first paragraph of the copy */
.article__note{
  margin-top:clamp(16px, 1.45vw, 25px);
  padding:clamp(20px, 2vw, 34px) 0;
  border-top:1px solid var(--tint);
  border-bottom:1px solid var(--tint);
}
.article__lead{
  max-width:1184px;
  font-size:clamp(15px, 1.16vw, 20px);
  font-weight:600; font-style:italic; line-height:1.6;
  color:var(--text);
}
.article__lead a{ color:var(--link); text-decoration:underline; }
.article__lead a:hover{ color:var(--b-400); }

/* ---- the author card ---- */
.author{
  /* one number for the portrait: the tile reads it for its width and the copy
     reads it to know how much room is left, so the two can never collide */
  --face-w:clamp(150px, 17.6vw, 304px);
  position:relative;
  display:flex; flex-direction:column; justify-content:flex-end;
  min-height:clamp(320px, 42vw, 721px);
  margin-top:clamp(32px, 4vw, 69px);
  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:min(560px, 100% - var(--face-w) - 24px);
}
.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:clamp(20px, 2.6vw, 44px);
  z-index:1;
  width:var(--face-w); height:auto;
  aspect-ratio:304 / 416;             /* the source is square; the mock crops it */
  object-fit:cover;
}

/* ---- the copy ---- */
.article__body{ margin-top:clamp(12px, 0.9vw, 15px); }
/* The standfirst over each part. It has to out-weigh `.article__body p`, which
   would otherwise set it at the running copy's 14/500. */
.article__body .article__kicker{
  margin-top:clamp(12px, 0.9vw, 15px);
  font-size:12px; font-weight:500; line-height:1.4; letter-spacing:-.02em;
  color:var(--text-mute);
}
/* the first one follows the author card, and the card already carries the gap */
.article__body > .article__kicker:first-child{ margin-top:0; }
.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;
}
/* Direct children only. The copy is authored as children of this block, while
   the components dropped into it — the product cards, the gallery — bring
   paragraphs of their own; as a descendant rule this one was re-typesetting
   them and, worse, pushing the absolutely positioned «Минпромторг» chip down
   by its margin. */
.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);
}
/* The mock runs a rail down the left of the list and marks the section being
   read with a short brand segment on it. The rail starts level with the first
   line rather than with the list box, which sits half a leading higher. */
.toc__list{
  list-style:none;
  position:relative;
  padding-left:31px;
}
.toc__list::before{
  content:"";
  position:absolute; left:1px; top:9px; bottom:0;
  width:1px;
  background:var(--tint);
}
.toc__link{
  position:relative;
  display:block;
  font-size:13px; font-weight:600; line-height:2.8;
  color:var(--text-mute);
  transition:color .18s ease;
}
/* the marker is always there and only fades in, so the row never reflows */
.toc__link::before{
  content:"";
  position:absolute; left:-31px; top:50%;
  width:2px; height:18px; margin-top:-9px;
  background:var(--brand);
  opacity:0;
  transition:opacity .18s ease;
}
.toc__link:hover{ color:var(--brand); }
.toc__link.is-here{ color:var(--brand); }
.toc__link.is-here::before{ opacity:1; }

/* ---- the three products quoted in the piece ----
   The site already has a product card — the one «похожие товары» puts on the
   product page — so the article borrows it whole rather than growing a second
   one. Only the strip's own measure is the article's. */
.article__products{ max-width:var(--art-measure, 954px); }

/* ---- 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(14px, 1.4vw, 21px);
}
.shots__item{ position:relative; }
/* every tile opens the popup, and a real control makes it reachable from the
   keyboard as well as the mouse */
.shots__open{
  display:block;
  width:100%; padding:0;
  border:0; background:none;
  cursor:zoom-in;
}
.shots__open:focus-visible{ outline:2px solid var(--brand); outline-offset:3px; }
.shots__item img,
.shots__item video{
  display:block;
  width:100%; height:auto; aspect-ratio:472 / 361;
  object-fit:cover;
  background:var(--surface);
}
.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 and stops
     travelling — pinned, it would sit on top of the copy */
  .article__back{
    position:static;
    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; padding-left:0; }
  .toc__list::before{ content:none; }
  .toc__link{ line-height:1.6; }
  .toc__link::before{ content:none; }
}

@media (max-width:767px){
  .author{
    --face-w:min(38vw, 200px);
    min-height:0;
    padding-bottom:calc(var(--face-w) * 1.368 + 40px);   /* tile + its clearance */
  }
  .author__face{ right:clamp(16px, 4vw, 24px); bottom:20px; }
  /* the card is content-height here, so the logo's auto margin has nothing to
     push against and the name would sit right under it */
  .author__body{ max-width:none; margin-top:clamp(20px, 6vw, 34px); }
  .shots{ grid-template-columns:minmax(0, 1fr); }
  .also__item{ grid-template-columns:minmax(0, 1fr); row-gap:16px; }
}

/* =========================================================
   NO ZOOM ON FOCUS
   Safari on iOS zooms the page the moment focus lands in a control set under
   16px, and it never zooms back out. Every field on the site is therefore held
   at 16 on the phone; this block has to sit last, because the rules it answers
   are as specific as it is.
   ========================================================= */
@media (max-width:767px){
  .field input,
  .sitesearch__field,
  .hero__search input,
  .city__input{ font-size:16px; }
}

/* =========================================================
   SOLUTIONS  (Figma 1931-6419)
   Five plates, one per direction, on the same gradient the hero is built from
   — so the page reads as one surface the white shell is cut out of. Inside a
   plate everything sits on its foot: the title on the left, the note in the
   right column, both on one baseline.
   ========================================================= */
.solpage{ padding:clamp(24px, 2vw, 32px) 0 clamp(40px, 4.6vw, 80px); }
.solbands{
  list-style:none;
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:clamp(14px, 1.5vw, 25px);
}

.solband__link{
  position:relative;
  display:grid; grid-template-columns:minmax(0, 1fr);
  align-content:end;   /* align-items:end was a no-op here (rows are auto-sized to content,
                           so there's nothing to align inside a track); align-content is what
                           actually pins the whole title+note block to the plate's bottom edge */
  row-gap:calc(clamp(4px, 0.5vw, 8px) + 30px);   /* note stays pinned to the bottom edge
     (align-content:end); this gap sets the title's height above it — was +40px, -10px on request */
  column-gap:clamp(20px, 2.6vw, 44px);
  /* a fixed height, not a floor: every plate matches every other one
     regardless of which title happens to wrap onto a second line. Well past
     the mock's own half-width proportion by now, by request — three bumps
     on the original 190/14.7vw/254: +slightly, then +40%, then +20%
     (210/15.5vw/270 → 294/21.7vw/378 → 353/26vw/454). */
  height:clamp(353px, 26vw, 454px);
  padding:clamp(28px, 3.4vw, 60px) clamp(24px, 4vw, 70px)
          clamp(28px, 3.4vw, 60px) clamp(24px, 3vw, 52px);
  overflow:hidden;
  color:var(--text-inv);
  background:linear-gradient(189.6deg, var(--hero-a) 28.464%, var(--hero-b) 82.079%);
}
/* The mock lays a photograph over the gradient in soft-light; it is a blend
   layer rather than an exported asset, so the same stand-in the mega cards use
   plays it — and it doubles as the hover, fading in under the copy. */
.solband__link::after{
  content:"";
  position:absolute; inset:0;
  opacity:0;
  background:
    radial-gradient(90% 130% at 86% 12%, rgba(255,255,255,.14) 0%, rgba(255,255,255,0) 58%),
    radial-gradient(70% 110% at 18% 112%, rgba(23,199,178,.28) 0%, rgba(23,199,178,0) 62%);
  transition:opacity .3s ease;
  pointer-events:none;
}
.solband__link:hover::after,
.solband__link:focus-visible::after{ opacity:1; }
.solband__link:focus-visible{ outline:2px solid var(--n-000); outline-offset:-6px; }

.solband__title,
.solband__note{ position:relative; z-index:1; }
.solband__title{
  max-width:520px;
  font-size:clamp(22px, 2.32vw, 40px);
  font-weight:500; line-height:1.2; letter-spacing:-.02em;
  transition:transform .3s cubic-bezier(.22, .61, .36, 1);
}
.solband__link:hover .solband__title,
.solband__link:focus-visible .solband__title{ transform:translateY(-6px); }
.solband__note{
  max-width:501px;
  font-size:clamp(14px, 1.05vw, 18px);
  font-weight:600; line-height:1.55;
  color:var(--b-100);
}

@media (max-width:767px){
  /* one to a row */
  .solbands{ grid-template-columns:minmax(0, 1fr); }
}

@media (prefers-reduced-motion:reduce){
  .solband__title{ transition:none; }
  .solband__link:hover .solband__title,
  .solband__link:focus-visible .solband__title{ transform:none; }
}

/* =========================================================
   DRAWER  (Figma 1931-11172)
   A panel that comes in from the right over a darkened page. A <dialog>, like
   the filter rail and the lightbox, so Esc, the focus trap and page inertness
   come from showModal() and only the slide and the scroll lock are ours.
   The component is empty of content on purpose — .drawer is the shell, and
   what it carries is the caller's business.
   ========================================================= */
.drawer{
  /* The sheet's width in one place: the close control sits beside it and has
     to know where its edge is. The 92px the sheet gives up is that control's
     room — without it a 1024 screen would push the cross off the left. */
  --sheet-w:min(100% - 92px, 1036px);
  position:fixed; inset:0;
  width:100%; max-width:none; height:100%; max-height:none;
  margin:0; padding:0; border:0;
  background:none;
  overflow:hidden;
}
.drawer:not([open]){ display:none; }
.drawer::backdrop{
  background:rgb(10 11 26 / .86);
  opacity:0;
  transition:opacity .32s ease;
}
.drawer.is-open::backdrop{ opacity:1; }

.drawer__sheet{
  position:absolute; right:0; top:0;
  display:flex; flex-direction:column;
  width:var(--sheet-w); height:100%;
  overflow-y:auto;
  overscroll-behavior:contain;
  background:var(--n-000);
  color:var(--text);
  transform:translateX(100%);
  transition:transform .32s cubic-bezier(.22, .61, .36, 1);
  /* the mock draws a 3px rail rather than the platform scrollbar */
  scrollbar-width:thin;
  scrollbar-color:var(--n-400) transparent;
}
.drawer.is-open .drawer__sheet{ transform:none; }
.drawer__sheet::-webkit-scrollbar{ width:4px; }
.drawer__sheet::-webkit-scrollbar-thumb{ background:var(--n-400); border-radius:2px; }

/* the mock's 604 of copy centred in the 1036 sheet */
.drawer__body{
  width:min(100% - 40px, 604px);
  margin-inline:auto;
  padding:clamp(28px, 3.6vw, 56px) 0 clamp(36px, 4vw, 64px);
}

/* Out on the scrim, level with the top of the sheet. It is drawn rather than
   an asset, the way every other cross on the site is. */
.drawer__close{
  position:absolute; top:21px; right:calc(var(--sheet-w) + 24px);
  z-index:1;
  width:44px; height:44px;
  background:none; border:0;
  cursor:pointer;
}
.drawer__close::before,
.drawer__close::after{
  content:"";
  position:absolute; left:50%; top:50%;
  width:22px; height:2px; margin:-1px 0 0 -11px;
  background:var(--n-000);
  transition:background .18s ease;
}
.drawer__close::before{ transform:rotate(45deg); }
.drawer__close::after { transform:rotate(-45deg); }
.drawer__close:hover::before,
.drawer__close:hover::after{ background:var(--b-200); }

.drawer__title{
  font-size:clamp(24px, 2.08vw, 36px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
  color:var(--text-body);
}
.drawer__title sup{ font-size:.645em; top:-.1em; }
/* a line under the title on the panels that need to say what the form is for */
.drawer__lead{
  /* the widest the mock sets one: a two-line standfirst either way */
  max-width:587px;
  margin-top:clamp(18px, 1.9vw, 33px);
  font-size:clamp(13px, 0.81vw, 14px); font-weight:600; line-height:1.4;
  letter-spacing:-.03em;
  color:var(--text-mute);
}
/* the lead already separates the title from the fields */
.drawer__lead + .pform{ margin-top:clamp(28px, 3.5vw, 61px); }

/* ---- what the panel shows once the form has gone ----
   The same panel, emptied: the confirmation stands in the middle of the sheet
   rather than at its top, because there is no longer a column of fields to
   head. The card is 635 wide in the mock, a little over the form's measure. */
.drawer__done[hidden]{ display:none; }
.drawer.is-done .drawer__body{
  width:min(100% - 40px, 635px);
  margin-block:auto;
}
.drawer__done .drawer__lead{ max-width:420px; }

.specialist{
  display:grid; grid-template-columns:auto minmax(0, 1fr);
  align-items:center;
  column-gap:clamp(16px, 1.7vw, 29px);
  margin-top:clamp(28px, 3.4vw, 59px);
  padding:clamp(12px, 1vw, 17px) clamp(12px, 0.9vw, 15px);
  background:var(--n-050);
}
.specialist__face{
  width:clamp(52px, 3.7vw, 64px); height:auto;
  border-radius:50%;
}
.specialist__name{
  font-size:clamp(16px, 1.05vw, 18px); font-weight:600; line-height:26px;
  color:var(--text-body);
}
.specialist__role{
  font-size:clamp(13px, 0.81vw, 14px); font-weight:500; line-height:18px;
  color:var(--text-mute);
}
.specialist__phone{
  margin-top:9px;
  font-size:clamp(15px, 0.93vw, 16px); font-weight:600; line-height:18px;
  color:var(--text);
}
.specialist__phone a{ transition:color .18s ease; }
.specialist__phone a:hover{ color:var(--link); }
/* the call spans the card, inside its own padding */
.specialist__close{
  grid-column:1 / -1;
  margin-top:clamp(16px, 1.6vw, 28px);
  background:var(--brand); color:var(--text-inv);
}
.specialist__close:hover{ background:var(--b-400); }

@media (prefers-reduced-motion:reduce){
  .drawer__sheet{ transition:none; }
  .drawer::backdrop{ transition:none; }
}

/* the sheet fills the screen, so the cross comes inside it and turns dark */
@media (max-width:1023px){
  .drawer{ --sheet-w:100%; }
  .drawer__close{ top:8px; right:8px; }
  .drawer__close::before,
  .drawer__close::after{ background:var(--text); }
  .drawer__close:hover::before,
  .drawer__close:hover::after{ background:var(--brand); }
  .drawer__body{ padding-top:clamp(46px, 8vw, 64px); }
}

/* =========================================================
   PARTNERSHIP FORM
   The form the drawer carries. Fields are rules rather than boxes: the same
   construction the consultation form uses on the blue, in its light skin.
   ========================================================= */
.pform{ margin-top:clamp(30px, 3.9vw, 67px); }

/* The rhythm is the form's, and only its own children keep it: two fields
   sharing a .pform__row are columns of one line, not two lines. */
.pform > * + *{ margin-top:clamp(20px, 2vw, 33px); }
.pform > input[type="hidden"] + *{ margin-top:0; }
/* the row below the pair carries the service chip above its line and needs the
   clearance for it */
.pform > .pform__row + .pfield{ margin-top:clamp(26px, 2.3vw, 40px); }
.pform > .pform__hint{ margin-top:13px; }
.pform > .orgcard{ margin-top:clamp(22px, 2.1vw, 36px); }
.pform > .orgcard + *{ margin-top:clamp(28px, 2.9vw, 50px); }
.pform > .pgroup{ margin-top:clamp(30px, 3.1vw, 53px); }
.pform > .pgroup + .pgroup{ margin-top:clamp(24px, 2.3vw, 39px); }
.pform > .pform__go{ margin-top:clamp(32px, 2.9vw, 49px); }
/* the attach plate already carries its own air inside the dashes */
.pform > .pform__attach + .pform__go{ margin-top:clamp(20px, 1.7vw, 29px); }
.pform > .check{ margin-top:19px; }

.pfield{ position:relative; }
.pfield input{
  width:100%;
  height:33px; padding:0 0 12px;
  border:0; border-bottom:2px solid var(--rail);
  background:none;
  font-size:clamp(14px, 0.93vw, 16px); font-weight:500; letter-spacing:-.03em;
  color:var(--text);
  transition:border-color .18s ease;
}
/* The name of the field sits on the rule while it is empty and rises above it
   once there is something to read — the mock draws both states. The label
   follows the control in the markup so the sibling selectors below can reach
   it, and the control keeps a blank placeholder so :placeholder-shown is what
   "empty" means. It floats into the gap above rather than reserving a row, so
   nothing on the form moves. */
.pfield > label{
  position:absolute; left:0; top:0;
  font-size:clamp(14px, 0.93vw, 16px); font-weight:500; line-height:21px;
  letter-spacing:-.03em;
  color:var(--text-mute);
  pointer-events:none;
  transition:transform .18s ease, font-size .18s ease, color .18s ease;
}
/* Two ways of saying the same thing on purpose. The sibling rules work on this
   static markup; :focus-within and .is-filled (set by script) keep working
   after Contact Form 7 wraps every control in its own
   <span class="wpcf7-form-control-wrap">, which breaks the sibling chain. */
.pfield input:focus ~ label,
.pfield input:not(:placeholder-shown) ~ label,
.pfield__area:focus ~ label,
.pfield__area:not(:placeholder-shown) ~ label,
.pfield select:focus ~ label,
.pfield select:valid ~ label,
.pfield:focus-within > label,
.pfield.is-filled > label{
  transform:translateY(-21px);
  font-size:12px; font-weight:600;
  color:var(--n-500);
}
.pfield input::placeholder,
.pfield__area::placeholder{ color:transparent; }
.pfield input:hover{ border-bottom-color:var(--n-450); }
.pfield input:focus{ outline:none; border-bottom-color:var(--brand); }
.pfield.has-error input{ border-bottom-color:var(--a-danger); }
.pfield__error{
  position:absolute; left:0; top:100%;
  margin-top:4px;
  font-size:12px; color:var(--a-danger);
  opacity:0; transition:opacity .18s ease;
}
.pfield.has-error .pfield__error{ opacity:1; }

.pform__row{
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:clamp(14px, 1.2vw, 16px);
}

/* the field that talks to the suggestions service says so on its own right */
.pfield--tagged input{ padding-right:78px; }
.pfield__tag{
  position:absolute; right:0; top:-5px;
  padding:5px 9px;
  border-radius:2px;
  background:var(--n-100);
  font-size:clamp(12px, 0.81vw, 14px); font-weight:500; letter-spacing:-.03em;
  color:var(--text-mute);
  pointer-events:none;
}
.pfield--icon input{ padding-right:32px; }
.pfield__icon{
  position:absolute; right:0; top:0;
  width:20px; height:20px;
  background:url("assets/icon-planet.svg") no-repeat center / contain;
  pointer-events:none;
}
.pform__hint{
  font-size:12px; font-weight:500; line-height:1.35; letter-spacing:-.03em;
  color:var(--text-mute);
}

/* The suggestions the ИНН field drops are the search field's own .ac panel —
   one dropdown on this site, not two that merely look alike. Only the rows
   differ: they pick a value rather than navigate, so each carries the record
   under its name. */
.ac--sugg{ top:calc(100% + 6px); max-height:min(52vh, 340px); }
.ac--sugg .ac__list{ flex:1 1 auto; min-height:0; overflow-y:auto; padding:6px 0; }
.ac__item--org{ width:100%; text-align:left; }
.ac__item--org .ac__item-title{ display:block; font-weight:600; }
.ac__item-note{
  display:block; margin-top:2px;
  font-size:12px; font-weight:500; line-height:1.35;
  color:var(--text-mute);
}

/* what the lookup came back with */
.orgcard{
  padding:clamp(12px, 0.81vw, 14px) clamp(16px, 1.45vw, 25px) clamp(14px, 1.04vw, 18px);
  border-radius:2px;
  background:var(--a-warm);
}
.orgcard[hidden]{ display:none; }
.orgcard__row + .orgcard__row{ margin-top:clamp(10px, 0.7vw, 12px); }
.orgcard__label{
  display:block;
  font-size:12px; font-weight:500; line-height:19px; letter-spacing:-.03em;
  color:var(--text-mute);
}
.orgcard__value{
  display:block; margin-top:3px;
  font-size:14px; font-weight:600; line-height:19px; letter-spacing:-.03em;
  color:var(--text-body);
}

/* a message runs to more than one line; it starts as one and grows with what
   is typed rather than showing a resize grip on a ruled field */
.pfield__area{
  display:block;
  width:100%; height:33px; padding:0 0 12px;
  border:0; border-bottom:2px solid var(--rail);
  background:none;
  overflow:hidden; resize:none;
  font-size:clamp(14px, 0.93vw, 16px); font-weight:500; line-height:21px;
  letter-spacing:-.03em;
  color:var(--text);
  transition:border-color .18s ease;
}
/* ---- a ruled select ----
   Same rule as the fields; the caret is the site's own, and while nothing is
   chosen the control shows no text of its own so the label reads through. */
.pfield select{
  width:100%;
  height:33px; padding:0 26px 12px 0;
  border:0; border-bottom:2px solid var(--rail);
  background:none;
  -webkit-appearance:none; appearance:none;
  font-size:clamp(14px, 0.93vw, 16px); font-weight:500; letter-spacing:-.03em;
  color:var(--text);
  cursor:pointer;
  transition:border-color .18s ease;
}
.pfield select:invalid{ color:transparent; }
.pfield select:hover{ border-bottom-color:var(--n-450); }
.pfield select:focus{ outline:none; border-bottom-color:var(--brand); }
.pfield__caret{
  position:absolute; right:0; top:6px;
  width:12px; height:7px;
  background:var(--text-mute);
  -webkit-mask:var(--caret-mask) no-repeat center / contain;
          mask:var(--caret-mask) no-repeat center / contain;
  pointer-events:none;
}
.pfield__area:hover{ border-bottom-color:var(--n-450); }
.pfield__area:focus{ outline:none; border-bottom-color:var(--brand); }

/* ---- the attach control ----
   One dashed plate that is itself the label of a hidden file input, so a click
   anywhere on it — and a file dropped onto it — reaches the same control. */
.drop{
  position:relative;
  display:flex; align-items:center; justify-content:center;
  gap:clamp(12px, 1.1vw, 19px);
  min-height:clamp(96px, 7.1vw, 123px);
  padding:18px clamp(16px, 1.4vw, 24px);
  border:2px dashed var(--n-400);
  border-radius:9px;
  cursor:pointer;
  transition:border-color .2s ease, background .2s ease;
}
.drop:hover,
.drop.is-over{ border-color:var(--brand); background:var(--surface); }
.drop input{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden;
}
.drop input:focus-visible + .drop__body{ outline:2px solid var(--brand); outline-offset:6px; }
.drop__body{ display:flex; align-items:center; gap:clamp(12px, 1.1vw, 19px); }
/* a mask rather than an <img>: the drawing then takes the plate's colour and
   can answer the hover, the way every other drawn icon on the site does */
.drop__icon{
  flex:none;
  width:clamp(40px, 3.5vw, 60px); height:clamp(40px, 3.5vw, 60px);
  background:var(--n-400);
  -webkit-mask:var(--upload-mask) no-repeat center / contain;
          mask:var(--upload-mask) no-repeat center / contain;
  transition:background .2s ease;
}
.drop:hover .drop__icon,
.drop.is-over .drop__icon{ background:var(--brand); }
.drop__title{
  display:block;
  font-size:clamp(14px, 0.93vw, 16px); font-weight:600; letter-spacing:-.03em;
  color:var(--text-body);
}
.drop__note{
  display:block;
  margin-top:6px;
  font-size:12px; font-weight:500; line-height:1.35; letter-spacing:-.03em;
  color:var(--text-mute);
}
/* what was picked, so the control answers back */
.drop__list{
  margin-top:12px;
  font-size:12px; font-weight:500; line-height:1.6;
  color:var(--text-mute);
}
.drop__list[hidden]{ display:none; }
.drop__list li{ display:flex; gap:8px; }
.drop__list b{ font-weight:600; color:var(--text-body); }

/* ---- the plate checkboxes ----
   The filter rail's box — a white square inside a brand one — standing on a
   plate that answers with it, so the whole plate is the target. */
.pgroup{ margin:0; padding:0; border:0; min-width:0; }
.pgroup__title{
  display:block; padding:0;
  font-size:clamp(14px, 0.93vw, 16px); font-weight:600; letter-spacing:-.03em;
  color:var(--text-body);
}
.pgroup__grid{
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:8px 16px;
  margin-top:clamp(12px, 1.04vw, 18px);
}
.pcheck{ position:relative; cursor:pointer; }
.pcheck input{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden;
}
.pcheck__plate{
  display:flex; align-items:center; gap:16px;
  min-height:57px; padding:12px 16px;
  border-radius:2px;
  background:var(--surface);
  font-size:clamp(13px, 0.93vw, 16px); font-weight:600; letter-spacing:-.03em;
  color:var(--text-body);
  transition:background .18s ease;
}
.pcheck__box{
  position:relative;
  flex:none; width:22px; height:22px;
  border-radius:2px;
  background:var(--n-000);
  transition:background .18s ease;
}
.pcheck__box::before{
  content:"";
  position:absolute; inset:6px;
  border-radius:1px;
  background:var(--n-000);
  opacity:0; transition:opacity .15s ease;
}
.pcheck:hover .pcheck__plate{ background:var(--tint); }
.pcheck input:checked + .pcheck__plate{ background:var(--tint); }
.pcheck input:checked + .pcheck__plate .pcheck__box{ background:var(--brand); }
.pcheck input:checked + .pcheck__plate .pcheck__box::before{ opacity:1; }
.pcheck input:focus-visible + .pcheck__plate{ outline:2px solid var(--brand); outline-offset:2px; }

/* .btn--submit is the white call the consultation form puts on the blue; here
   the surface is white, so the call is the brand one */
.pform__go{ background:var(--brand); color:var(--text-inv); }
.pform__go:hover{ background:var(--b-400); }

/* .check is written for the blue surfaces; on white the box and the copy have
   to come back down to the page's own colours */
.check--light .check__box{ border-color:var(--rail); }
.check--light .check__box img{ filter:invert(1); }
.check--light input:checked + .check__box{ background:var(--brand); border-color:var(--brand); }
.check--light input:checked + .check__box img{ filter:none; }
.check--light input:focus-visible + .check__box{ outline-color:var(--brand); }
.check--light .check__text{ color:rgb(0 0 0 / .39); }
.check--light .check__text a{ color:inherit; }
.check--light .check__text a:hover{ color:var(--link); }

@media (max-width:599px){
  .pform__row{ grid-template-columns:minmax(0, 1fr); }
  .pgroup__grid{ grid-template-columns:minmax(0, 1fr); }
}

/* =========================================================
   PAGE INDEX  (review aid — delete before the theme ships)
   A round control in the bottom-left corner opens a strip listing every page
   that has been built, so the layout can be walked through without going back
   to a menu. It is not part of the design: everything here is namespaced under
   .pagenav and the markup sits in one commented block at the foot of each page.
   ========================================================= */
.pagenav{
  position:fixed; left:clamp(14px, 1.4vw, 24px); bottom:clamp(14px, 1.4vw, 24px);
  z-index:70;
  display:grid; place-items:center;
  width:48px; height:48px;
  border-radius:50%;
  background:var(--b-950);
  box-shadow:0 8px 24px rgb(0 20 46 / .28);
  cursor:pointer;
  transition:background .2s ease, transform .2s ease;
}
.pagenav:hover{ background:var(--brand); transform:translateY(-2px); }
/* three rules, drawn: the control costs no request and takes the button's
   own colour */
.pagenav__icon,
.pagenav__icon::before,
.pagenav__icon::after{
  display:block;
  width:18px; height:2px;
  border-radius:1px;
  background:var(--n-000);
}
.pagenav__icon{ position:relative; }
.pagenav__icon::before,
.pagenav__icon::after{
  content:"";
  position:absolute; left:0;
}
.pagenav__icon::before{ top:-6px; }
.pagenav__icon::after { top:6px; }

/* the cookie bar sits along the same edge; on a phone they would overlap */
:root.has-cookie .pagenav{ bottom:calc(clamp(14px, 1.4vw, 24px) + 62px); }

/* ---- the strip ----
   .drawer, mirrored: same panel, same behaviour, entering from the other side.
   Narrower, because a list of names does not need the form's measure. */
.drawer--left{ --sheet-w:min(100% - 92px, 380px); }
.drawer--left .drawer__sheet{
  right:auto; left:0;
  transform:translateX(-100%);
}
.drawer--left.is-open .drawer__sheet{ transform:none; }
.drawer--left .drawer__close{
  right:auto; left:calc(var(--sheet-w) + 24px);
}
.drawer--left .drawer__body{
  width:min(100% - 40px, 300px);
  padding-top:clamp(24px, 2.6vw, 40px);
}

.pagelist{ list-style:none; margin-top:clamp(20px, 2.2vw, 34px); }
.pagelist li + li{ margin-top:2px; }
.pagelist a{
  display:block;
  padding:11px 14px;
  border-radius:2px;
  font-size:14px; font-weight:500; line-height:1.35; letter-spacing:-.02em;
  color:var(--text-body);
  transition:background .15s ease, color .15s ease;
}
.pagelist a:hover{ background:var(--surface); color:var(--link); }
.pagelist a[aria-current="page"]{
  background:var(--tint);
  font-weight:600; color:var(--text);
}
.pagelist__file{
  display:block; margin-top:2px;
  font-size:11px; font-weight:500; letter-spacing:0;
  color:var(--text-mute);
}
.pagenav__note{
  margin-top:clamp(20px, 2.2vw, 32px);
  padding-top:16px;
  border-top:1px solid var(--tint);
  font-size:12px; font-weight:500; line-height:1.45;
  color:var(--text-mute);
}

@media (max-width:1023px){
  .drawer--left{ --sheet-w:min(100%, 320px); }
  .drawer--left .drawer__close{ left:auto; right:8px; }
}

/* =========================================================
   WORDPRESS INTEGRATION
   Nothing here changes how the static pages look. It is the seam: the classes
   the plugins will emit, mapped onto the components already built above, so
   the markup keeps its shape once the forms and the catalog come from
   WordPress. See INTEGRATION.md for what becomes what.
   ========================================================= */

/* ---- Contact Form 7 ----
   CF7 wraps every control in a span of its own and prints its own validation
   copy. The wrapper must not become a layout box, and its messages must land
   where .pfield__error already does. */
.pfield .wpcf7-form-control-wrap,
.form .wpcf7-form-control-wrap{ display:block; }
.pform .wpcf7-spinner{ display:none; }

.pfield .wpcf7-not-valid-tip{
  position:absolute; left:0; top:100%;
  margin-top:4px;
  font-size:12px; color:var(--a-danger);
}
.pfield:has(.wpcf7-not-valid) input,
.pfield:has(.wpcf7-not-valid) select,
.pfield .wpcf7-not-valid{ border-bottom-color:var(--a-danger); }

/* the form's own answer, in place of .form__status */
.pform .wpcf7-response-output,
.form .wpcf7-response-output{
  margin:14px 0 0; padding:0; border:0;
  font-size:13px; font-weight:500;
}
.pform form.invalid .wpcf7-response-output,
.form form.invalid .wpcf7-response-output{ color:var(--a-danger); }

/* [acceptance] renders the consent box inside three spans of its own */
.check .wpcf7-list-item{ margin:0; }
.check .wpcf7-list-item-label{
  font-size:13px; font-weight:500; line-height:1.23; letter-spacing:-.03em;
}

/* [file] keeps the plate: the wrapper is not allowed to break the label */
.drop .wpcf7-form-control-wrap{ position:static; }

/* ---- geotargeting ----
   Every node the geo plugin rewrites is marked with data-geo; the styling
   stays on the component, so a swapped city, phone or address changes the
   text and nothing else. */
[data-geo]{ transition:opacity .18s ease; }
:root.geo-loading [data-geo]{ opacity:.45; }

/* ---- Filter Everything ----
   Разметка виджета проверена по фактическому рендеру (не по документации
   плагина — она разошлась с реальной версией). Своей обёртки-квадрата вокруг
   чекбокса плагин не рисует — стилизуем сам <input> через appearance:none,
   тем же приёмом, что .fcheck__box в остальной вёрстке. Контейнер, который
   плагин перерисовывает по AJAX — .catalog__results, пагинацию — .pager__nav
   (настроено в самом Filter Set, тут не трогать). */

/* свою кнопку-открывашку и крестик-закрытие не показываем — есть свои,
   .filters__open в .catalog__bar и .filters__close в диалоге */
.wpc-filters-open-button-container,
.wpc-widget-close-container,
.wpc-spinner{ display:none; }

.wpc-filters-main-wrap,
.wpc-filters-widget-content,
.wpc-filters-widget-containers-wrapper,
.wpc-filters-scroll-container{ display:block; }

.wpc-filters-widget-wrapper{ margin:0; padding:0; border:0; }
.wpc-filters-section + .wpc-filters-section{ margin-top:clamp(22px, 2.2vw, 34px); }

/* свои чипы виджета скрыты — активные фильтры выводятся отдельным
   [fe_chips] в самом верху .catalog__bar, как в макете (см. archive-product.php) */
.wpc-filters-widget-top-container{ display:none; }
.wpc-filters-widget-top-container{ margin-bottom:clamp(18px, 1.7vw, 28px); }

.wpc-filter-header{ margin:0; }
.wpc-filter-title,
.wpc-filters-widget-wrapper .widget-title{
  display:inline-flex; align-items:center; gap:9px;
  margin:0;
  font-size:15px; font-weight:600; line-height:32px;
  color:var(--text);
}

.wpc-filter-content{ margin-top:6px; }
.wpc-filters-ul-list{ list-style:none; margin:0; padding:0; }
.wpc-term-item-content-wrapper{
  position:relative;
  display:flex; align-items:center; gap:11px;
  line-height:32px;
}
/* сам чекбокс прячем (как .fcheck input) и рисуем квадрат на <label> через
   ::before/::after — Firefox не поддерживает generated content на <input>,
   поэтому первая версия (квадрат прямо на инпуте) не показывала иконку и
   хвостом тянула неверный ховер. На <label> псевдоэлементы работают везде. */
.wpc-term-item-content-wrapper input[type="checkbox"]{
  position:absolute; width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden;
}
.wpc-term-item-content-wrapper label{
  position:relative;
  padding-left:31px;   /* 20px квадрат + 11px зазор, как gap у .fcheck */
}
.wpc-term-item-content-wrapper label::before{
  content:"";
  position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:20px; height:20px;
  border-radius:2px;
  background:var(--tint);
  transition:background .18s ease;
}
.wpc-term-item-content-wrapper label::after{
  content:"";
  position:absolute; left:6px; top:50%; transform:translate(0, -50%);
  width:8px; height:8px;
  border-radius:1px;
  background:var(--n-000);
  opacity:0; transition:opacity .15s ease;
}
.wpc-term-item-content-wrapper:hover label::before{ background:var(--n-400); }
.wpc-term-item-content-wrapper input[type="checkbox"]:checked ~ label::before{ background:var(--brand); }
.wpc-term-item-content-wrapper input[type="checkbox"]:checked ~ label::after{ opacity:1; }
.wpc-term-item-content-wrapper input[type="checkbox"]:focus-visible ~ label::before{ outline:2px solid var(--brand); outline-offset:3px; }

.wpc-term-item-content-wrapper label{
  display:flex; align-items:center; gap:6px;
  flex:1; min-width:0;
  cursor:pointer;
}
.wpc-filter-link{
  font-size:14px; font-weight:500;
  color:var(--text);
  text-decoration:none;
}
.wpc-term-count{ font-size:13px; color:var(--text-mute); }
.wpc-term-count-brackets-open,
.wpc-term-count-brackets-close{ display:none; }   /* счётчик без скобок */

/* на широком экране рельс — обычная колонка сетки без «подвала»
   (.filters__foot тоже display:none) — фильтрация идёт сразу по клику на
   чекбокс, отдельная кнопка «Показать» не нужна */
.wpc-filters-widget-controls-container{ display:none; }

/* «active filters» — свои чипы поверх сетки, тот же .chip, что и в мокете */
.wpc-filter-chips-list{ display:flex; flex-wrap:wrap; gap:8px; list-style:none; margin:0; padding:0; }
.wpc-filter-chips-list.wpc-empty-chips-container{ display:none; }
.wpc-chip-content{
  display:inline-flex; align-items:center; gap:10px;
  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;
}
.wpc-chip-content:hover{ background:var(--n-400); }
/* в макете рельс сбрасывается только крестиком на каждом чипе — общей
   плашки "Reset all" нет, плагин добавляет её сам первым чипом */
.wpc-chip-reset-all{ display:none; }

/* кружок-подсказка «?» у заголовка каждой группы — как .hint/.hint__bubble
   у остальных фильтров сайта. Плагин своей html-разметки для этого не даёт,
   поэтому текст подсказки идёт через content, по data-fid каждой секции. */
/* ::before тултипа позиционируется от .wpc-filters-section (вся ширина
   группы), а не от самого .wpc-filter-title — тот узкий, по ширине текста
   заголовка, и растянутый на 100% его ширины тултип получался бы крошечным */
.wpc-filters-section{ position:relative; }
.wpc-filter-title::after{
  content:"?";
  display:inline-flex; align-items:center; justify-content:center;
  width:18px; height:18px; flex:none;
  border:1px solid var(--n-400); border-radius:50%;
  font-size:11px; font-weight:600; line-height:1;
  color:var(--text-mute);
  cursor:help;
}
.wpc-filter-title::before{
  content:attr(data-hint);
  position:absolute; z-index:5;
  left:0; right:0; bottom:calc(100% + 6px);
  box-sizing:border-box;
  display:none;
  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);
  white-space:normal;
  word-wrap:break-word; overflow-wrap:break-word;
}
.wpc-filter-title:hover::before{ display:block; }
.wpc-filters-section[data-fid="47"] .wpc-filter-title::before{ content:"Основной вычислительный узел компьютера — от его модели зависят скорость работы и энергопотребление"; }
.wpc-filters-section[data-fid="48"] .wpc-filter-title::before{ content:"Энергозависимая память, в которой система держит данные запущенных программ. Поколение задаёт частоту и пропускную способность"; }
.wpc-filters-section[data-fid="49"] .wpc-filter-title::before{ content:"Набор микросхем системной платы, который связывает процессор с памятью, накопителями и портами"; }
.wpc-filters-section[data-fid="50"] .wpc-filter-title::before{ content:"Стандартизированный набор физических размеров, формы и других технических параметров устройства или его компонента"; }

/* =========================================================
   PARTNER DIRECTORY  (Figma 1931-13076)
   .pdir, not .partners — that name already belongs to the technology-partner
   grid on partnership.html, and a page-level block must not borrow it.
   The one page with no hero: a directory and a map side by side, both running
   the full width of the window rather than the shell. The directory scrolls
   inside itself, so the map stays put while the list is read.
   ========================================================= */
/* the bar is fixed, so the page has to leave its height at the top */
.pdir{ padding-top:var(--topbar-h); }

/* The block owns the first screen: it starts under the fixed bar and runs to
   the bottom edge, and the video band begins where it ends. */
.pdir__screen{
  display:flex; flex-direction:column;
  /* a definite height, not a floor: the list inside has to know what is left
     for it, otherwise it stops scrolling and pushes the screen open */
  height:calc(100svh - var(--topbar-h));
}
/* flex gives the grid a definite height; the row has to pass it on, or an
   auto row would just grow to fit the list and overshoot the screen */
.pdir__grid{ flex:1; min-height:0; grid-template-rows:minmax(0, 1fr); }
.pdir__head{ padding:clamp(10px, 0.9vw, 15px) 0 clamp(10px, 0.9vw, 16px); }
.pdir__title{
  font-size:clamp(20px, 1.4vw, 24px);
  font-weight:700; line-height:26px; letter-spacing:-.02em;
  color:var(--text);
}
.pdir__title sup{ font-size:.6em; top:-.45em; }

.pdir__grid{
  display:grid; grid-template-columns:40.1% minmax(0, 1fr);
  align-items:stretch;
}

/* ---- the directory ---- */
.pdir__panel{
  display:grid; grid-template-columns:146px minmax(0, 1fr);
  column-gap:clamp(20px, 2.7vw, 47px);
  height:100%;
  /* no left padding: the block sits in the shell, and the shell's own gutter
     already puts the rail of cities on the page's left line */
  padding:clamp(14px, 1.2vw, 20px) clamp(8px, 0.6vw, 10px) clamp(16px, 1.8vw, 30px) 0;
  border-top:1px solid var(--tint);
  border-right:1px solid var(--tint);
}
/* a grid item will not shrink under its content unless told to, and without
   this the list cannot scroll — it just makes the panel taller than its box */
.pdir__panel > *{ min-height:0; }

.citylist__label{
  font-size:10px; font-weight:700; line-height:26px; letter-spacing:.02em;
  color:var(--n-500);
}
.citylist ul{ list-style:none; margin-top:clamp(20px, 2.1vw, 36px); }
.citylist__item{
  display:block; width:100%;
  text-align:left;
  font-size:13px; font-weight:600; line-height:2.2; letter-spacing:-.02em;
  color:var(--n-500);
  transition:color .18s ease;
}
.citylist__item:hover{ color:var(--brand); }
.citylist__item.is-current{ color:var(--text); }

.pdir__col{ display:flex; flex-direction:column; min-width:0; }

/* One ring, not two. The mock outlines this field in teal — a colour the site
   uses nowhere else for a border, and on focus the browser's own ring landed
   outside it, so the field wore two. It now carries the site's control
   boundary and answers focus by colouring it. */
.psearch{
  position:relative;
  display:flex; align-items:center;
  max-width:448px; height:46px;
  border:1px solid var(--rail); border-radius:9px;
  transition:border-color .18s ease;
}
.psearch:hover{ border-color:var(--n-450); }
.psearch__field{
  flex:1; min-width:0;
  height:100%; padding:0 8px 0 19px;
  border:0; background:none;
  font-size:15px; font-weight:600; letter-spacing:-.02em;
  color:var(--text);
}
.psearch__field::placeholder{ color:var(--text); font-weight:600; }
.psearch__field::-webkit-search-decoration,
.psearch__field::-webkit-search-cancel-button{ -webkit-appearance:none; }
.psearch:focus-within{ border-color:var(--brand); }
.psearch__field:focus{ outline:none; }
.psearch__go{
  display:grid; place-items:center;
  width:46px; height:100%; flex:none;
  background:none; cursor:pointer;
}
.psearch__go img{ width:16px; }
.psearch__hint{
  max-width:448px; margin-top:5px;
  font-size:11px; font-weight:600; line-height:1.8; letter-spacing:-.02em;
  color:var(--text-mute);
}

/* ---- the cards ----
   The list is what scrolls, not the page: the map beside it must not run out
   from under the reader. */
.pcards{
  list-style:none;
  flex:1; min-height:0;
  margin-top:clamp(18px, 1.7vw, 29px);
  /* the cards keep the mock's 448; the gutter is where its scrollbar runs */
  padding-right:clamp(12px, 1.2vw, 21px);
  overflow-y:auto;
  overscroll-behavior:contain;
  scrollbar-width:thin;
  scrollbar-color:var(--n-400) transparent;
}
.pcards::-webkit-scrollbar{ width:3px; }
.pcards::-webkit-scrollbar-thumb{ background:var(--n-400); border-radius:2px; }
.pcards > li + li{ margin-top:clamp(8px, 0.8vw, 13px); }

.pcard{
  display:grid; grid-template-columns:119px minmax(0, 1fr);
  align-items:center;
  column-gap:clamp(12px, 1.1vw, 19px);
  min-height:148px;
  padding:clamp(10px, 0.8vw, 14px) clamp(10px, 0.9vw, 15px) clamp(9px, 0.7vw, 12px);
  border:1px solid var(--tint); border-radius:9px;
  transition:border-color .18s ease, box-shadow .18s ease;
}
.pcard{ cursor:pointer; }
.pcard:hover{ border-color:var(--rail); box-shadow:0 6px 18px rgb(0 32 66 / .06); }
.pcard:focus-visible{ outline:2px solid var(--brand); outline-offset:2px; }
/* the one the map is showing */
.pcard.is-active{ border-color:var(--brand); background:var(--n-050); }
.pcard__logo{
  display:grid; place-items:center;
  width:119px; height:119px;
  background:var(--n-050); border-radius:6px;
}
.pcard__logo img{ max-width:78%; max-height:60%; object-fit:contain; }
.pcard__body{ min-width:0; }
.pcard__name{
  font-size:15px; font-weight:700; line-height:26px; letter-spacing:-.02em;
  color:var(--text);
}
.pcard__addr{
  font-size:13px; font-weight:600; line-height:1.8; letter-spacing:-.02em;
  color:var(--n-500);
}
.pcard__phones{
  margin-top:2px;
  font-size:14px; font-weight:600; line-height:1.8; letter-spacing:-.02em;
  color:var(--text-body);
}
.pcard__phones a{ transition:color .18s ease; }
.pcard__mail{
  font-size:13px; font-weight:600; line-height:1.8; letter-spacing:-.02em;
  color:var(--text-body);
}
.pcard__site{
  display:flex; align-items:center; gap:8px;
  margin-top:5px;
  font-size:13px; font-weight:600; line-height:1.2; letter-spacing:-.02em;
  color:var(--text-body);
}
.pcard__phones a:hover,
.pcard__mail a:hover,
.pcard__site a:hover{ color:var(--link); }
.pcard__globe{
  flex:none; width:12px; height:12px;
  background:url("assets/icon-planet.svg") no-repeat center / contain;
}

/* ---- the map ----
   A live Yandex widget. It carries its own controls and pins, so the box only
   has to give it a size and keep it from spilling. */
.pdir__map{
  position:relative;
  border-top:1px solid var(--tint);
  background:var(--n-050);
  overflow:hidden;
}
.pdir__frame{
  display:block;
  width:100%; height:100%;
  border:0;
}

/* 1555 is where the card would drop under 400 with the rail still beside it:
   0.401·W − 224. Below that the rail becomes a row and the panel widens. */
@media (max-width:1555px){
  .pdir__grid{ grid-template-columns:48% minmax(0, 1fr); }
  .pdir__panel{
    grid-template-columns:minmax(0, 1fr);
    row-gap:clamp(14px, 1.8vw, 22px);
  }
  .citylist ul{
    display:flex; flex-wrap:wrap; gap:4px 18px;
    margin-top:8px;
  }
  .citylist__item{ width:auto; line-height:1.9; }
  .psearch,
  .psearch__hint{ max-width:none; }
}

@media (max-width:1023px){
  /* stacked, the two panes are taller than a screen between them */
  .pdir__screen{ height:auto; }
  .pdir__grid{ grid-template-columns:minmax(0, 1fr); }
  .pdir__panel{
    height:auto;
    border-right:0;
    padding-inline:0;
  }
  .pcards{ overflow:visible; padding-right:0; }
  .pdir__map{ height:clamp(320px, 52vw, 520px); border-top:1px solid var(--tint); }
}

@media (max-width:767px){
  .pcard{ grid-template-columns:minmax(0, 1fr); row-gap:14px; }
  .pcard__logo{ width:100%; height:96px; }
}

/* ---- the pin the mock draws ----
   A light round chip with the partner's mark in it and a short stem under it.
   The widget in the markup can only place Yandex's own dots; this is what the
   JS API draws once a key is set on [data-map-key]. */
.pmark{
  position:relative;
  display:grid; place-items:center;
  width:53px; height:53px;
  border-radius:50%;
  background:#eef4f8;
  box-shadow:0 9px 4px rgb(0 0 0 / .1);
  cursor:pointer;
  transition:transform .18s ease;
}
.pmark::after{
  content:"";
  position:absolute; left:50%; top:100%;
  width:2px; height:11px; margin-left:-1px;
  background:#eef4f8;
}
.pmark:hover,
.pmark.is-lit,
.pmark.is-active{ transform:translateY(-3px); }
.pmark.is-active{ box-shadow:0 9px 4px rgb(0 0 0 / .1), 0 0 0 3px var(--brand); }
.pmark img{ max-width:64%; max-height:52%; object-fit:contain; }

.pcards__empty{
  padding:26px 0;
  font-size:13px; font-weight:500;
  color:var(--text-mute);
}
.pcards__empty[hidden]{ display:none; }
.pcard[hidden]{ display:none; }

/* =========================================================
   CONTACTS  (Figma 1931-8102)
   A rail of address kinds on the left and the addresses themselves on the
   right, each ruled off from the one above. Every block is one line: the
   number, the address to write to, and the call that opens the contact panel.
   ========================================================= */
.contacts{ padding-top:var(--topbar-h); }
.contacts__head{ padding:clamp(14px, 1.6vw, 28px) 0 clamp(48px, 7.9vw, 137px); }
.contacts__title{
  font-size:clamp(32px, 3.7vw, 64px);
  font-weight:600; line-height:1; letter-spacing:-.03em;
  color:var(--text-body);
}

.contacts__grid{
  display:grid; grid-template-columns:minmax(0, 19.1%) minmax(0, 1fr);
  align-items:start;
  padding-bottom:clamp(40px, 5vw, 86px);
}

/* ---- the rail ---- */
.ctabs{ display:flex; flex-direction:column; align-items:flex-start; }
.ctabs__tab{
  font-size:15px; font-weight:600; line-height:2.6; letter-spacing:-.02em;
  color:var(--n-600);
  transition:color .18s ease;
}
.ctabs__tab:hover{ color:var(--brand); }
.ctabs__tab.is-current{ color:var(--brand); }

/* ---- one address ---- */
.cblock{
  padding:clamp(10px, 0.7vw, 12px) 0 clamp(20px, 2.2vw, 38px);
  border-top:1px solid var(--tint);
}
.cblock__label{
  font-size:15px; font-weight:600; line-height:26px; letter-spacing:-.02em;
  color:var(--n-600);
}
/* the number leads, the address to write to sits beside it and the call keeps
   to the right edge — one line, three jobs */
.cblock__row{
  display:grid;
  grid-template-columns:minmax(0, 1fr) auto auto;
  align-items:center;
  column-gap:clamp(20px, 2.8vw, 48px);
  margin-top:clamp(6px, 0.7vw, 12px);
}
.cblock__phone{
  font-size:clamp(26px, 2.3vw, 40px);
  font-weight:600; line-height:1.25; letter-spacing:-.03em;
  color:var(--text-body);
}
.cblock__phone a{ transition:color .18s ease; }
.cblock__phone a:hover{ color:var(--link); }
.cblock__mail{
  font-size:15px; font-weight:600; line-height:26px; letter-spacing:-.02em;
  color:var(--link);
}
.cblock__mail a:hover{ color:var(--b-400); }
/* The mock fills this one with the brand rather than the light plate, and the
   icon is an envelope, not the plus the hero calls wear. Hover follows the
   site's rule for a brand-filled call: one step lighter. */
.cblock__go{
  flex:none;
  width:174px; height:40px; gap:12px;
  padding:0 14px;
  justify-content:flex-start;
  background:var(--brand); color:var(--text-inv);
  transition:background .18s ease;
}
.cblock__go:hover{ background:var(--b-400); }
.cblock__go img{ width:22px; flex:none; }
.cblock__addr{
  margin-top:clamp(8px, 0.9vw, 14px);
  font-size:15px; font-weight:600; line-height:21px; letter-spacing:-.02em;
  color:var(--n-600);
}
.cblock__soon{
  margin-top:14px;
  font-size:15px; font-weight:500; line-height:1.5;
  color:var(--text-mute);
}

/* ---- the office on the map ---- */
.cblock__map{
  margin-top:clamp(20px, 2.4vw, 40px);
  aspect-ratio:1361 / 499;
  overflow:hidden;
  background:var(--n-050);
}
.cblock__frame{
  display:block;
  width:100%; height:100%;
  border:0;
}

@media (max-width:1023px){
  /* the rail has no column of its own left: it becomes a row over the list */
  .contacts__grid{ grid-template-columns:minmax(0, 1fr); row-gap:clamp(14px, 2vw, 22px); }
  .ctabs{ flex-direction:row; gap:24px; }
  .cblock__map{ aspect-ratio:16 / 10; }
}

@media (max-width:767px){
  /* stacked: the number, then the address to write to, then the call */
  .cblock__row{
    grid-template-columns:minmax(0, 1fr);
    row-gap:12px;
    justify-items:stretch;
  }
  /* the call spans the screen here — it is the only thing to press */
  .cblock__go{ width:100%; justify-content:center; }
}

/* =========================================================
   WARRANTY  (Figma 1931-10020)
   Three bands: the standard warranty on white, the service pack over a
   photograph, and the map of where the service reaches. The first band keeps
   the site's two-column reading measure — heading and lead on the left rail,
   everything that can be looked up on the right.
   ========================================================= */

/* the mock gives this hero a little more height and a shallower foot than
   the section pages, so the hotline clears the bottom edge by 36px */
.hero--warranty{ min-height:clamp(438px, 40.6vw, 577px); padding-bottom:36px; }
.hero--warranty .hero__body{ padding-top:clamp(20px, 2vw, 35px); }

/* the small hero heading, on the mock's own leading and measure */
.hero__title--warranty{ max-width:951px; line-height:1.2; }

/* Here the foot takes the whole content width — the hotline on the page
   gutter, the two calls at the right edge — so it hangs off the shell rather
   than off the indented copy column. */
.hero__foot--warranty{
  display:grid; grid-template-columns:minmax(0, 1fr) auto;
  align-items:center;
  gap:clamp(20px, 2.4vw, 40px);
}
.hotline{ display:flex; align-items:center; gap:clamp(14px, 1.4vw, 19px); }
.hotline__face{
  flex:none;
  width:clamp(46px, 3.4vw, 59px); height:auto;
  border-radius:50%;
}
.hotline__label{
  font-size:clamp(13px, 1vw, 14px); font-weight:600; line-height:24px;
  color:var(--text-inv-cap);
}
.hotline__row{
  display:flex; flex-wrap:wrap; gap:6px clamp(14px, 2vw, 35px);
  margin-top:6px;
  font-size:clamp(13px, 1.05vw, 16px); font-weight:600;
  color:var(--text-inv);
}
.hotline__row a{ transition:color .18s ease; }
.hotline__row a:hover{ color:var(--b-100); }

.hero__calls{ display:flex; flex-wrap:wrap; gap:8px; }
.hero__centres{ width:202px; }
.hero__claim{ width:344px; }

/* ---------- standard warranty ---------- */
.warranty{ background:var(--n-000); }
/* the same spine as the hero copy: heading and lead in the rail, everything
   that can be looked up in the column that starts at --col-text */
.wstd{
  display:grid; grid-template-columns:var(--col-text) minmax(0, 1fr);
  padding:clamp(44px, 6vw, 102px) 0 clamp(40px, 5vw, 86px);
}
.wstd__intro{
  position:sticky;
  /* clears whatever is pinned at the top, plus the same air the back control
     on the reading page leaves */
  top:calc(var(--stick-h) + clamp(20px, 2.4vw, 40px));
  align-self:start;      /* a stretched grid item has no room to travel */
  padding-right:clamp(20px, 2.4vw, 40px);
}
.wstd__intro .block-title{ max-width:400px; }
.wstd__lead{
  max-width:486px; margin-top:clamp(20px, 2.4vw, 42px);
  font-size:clamp(14px, 1.05vw, 16px); font-weight:600; line-height:1.63;
  color:var(--text-mute);
}
.wstd__col{ min-width:0; }
.wstd__sub{
  max-width:690px;
  font-size:clamp(21px, 1.85vw, 32px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
  color:var(--text);
}
.wstd__sub--rules{ margin-top:clamp(40px, 5.5vw, 94px); }
.wstd__note{
  margin-top:clamp(18px, 2vw, 34px);
  font-size:15px; font-weight:600; line-height:26px;
  color:var(--text-mute);
}
.wstd__note--after{ max-width:660px; }

/* the four kinds of machine and how long each is covered */
.wcards{
  list-style:none;
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:clamp(10px, 1vw, 15px);
  margin-top:clamp(20px, 2.4vw, 42px);
}
.wcard{
  position:relative;
  display:flex;
  aspect-ratio:493/268;
  background:var(--tint);
  overflow:hidden;
}
/* The plate is one link to the category. It carries the padding rather than
   the card, so the whole surface — machine included — is the target, and it
   stays unpositioned so the two pictures keep hanging off the card itself. */
.wcard__link{
  display:flex; flex-direction:column; align-items:flex-start;
  width:100%; height:100%;
  padding:clamp(18px, 1.7vw, 28px);
}
.wcard__link:focus-visible{ outline:2px solid var(--brand); outline-offset:-4px; }
/* the faint white lattice the mock lays over the right of every plate */
.wcard__grid{
  position:absolute; left:23.5%; top:0; z-index:0;
  width:76.9%; height:85.8%;
  pointer-events:none;
}
/* Each machine is framed differently in the mock, so the plate carries its
   own four numbers and one rule places them all. Percentages of the plate,
   so the framing survives the card being resized. The shots ship on white,
   which multiply drops onto the plate. */
.wcard__shot{
  position:absolute; z-index:0;
  right:var(--shot-r); bottom:var(--shot-b);
  width:var(--shot-w); height:var(--shot-h);
  object-fit:contain;
  mix-blend-mode:multiply;
  transition:transform .3s ease;
}
/* the two rack-mount machines are wider than their frame and run off the
   plate, so they are anchored by their left edge and cropped on the right */
.wcard--silex .wcard__shot,
.wcard--rack .wcard__shot{ object-fit:cover; object-position:left center; }
.wcard__link:hover .wcard__shot{ transform:translateY(-6px); }
.wcard--pc{    --shot-w:22.7%; --shot-h:76.9%; --shot-r:21.9%; --shot-b:0%; }
.wcard--silex{ --shot-w:55.2%; --shot-h:42.9%; --shot-r:0%;    --shot-b:26.1%; }
.wcard--ws{    --shot-w:43.0%; --shot-h:64.2%; --shot-r:11.8%; --shot-b:0%; }
.wcard--rack{  --shot-w:55.8%; --shot-h:32.8%; --shot-r:0%;    --shot-b:33.2%; }
.wcard__name{
  position:relative; z-index:1;
  max-width:46%;
  font-size:clamp(17px, 1.4vw, 24px);
  font-weight:600; line-height:1.2; letter-spacing:-.03em;
  color:var(--text);
  transition:color .18s ease;
}
.wcard__link:hover .wcard__name{ color:var(--link); }
.wcard__term{
  position:relative; z-index:1;
  margin-top:clamp(14px, 1.4vw, 24px);
  padding:4px 11px;
  border-radius:4px;
  background:var(--a-check);
  font-size:clamp(13px, 1.05vw, 16px); font-weight:600; line-height:26px;
  color:var(--text-inv);
}

/* ---- what the warranty covers: a ruled, numbered list ---- */
.wrules{
  list-style:none; padding:0;
  margin-top:clamp(18px, 2.2vw, 38px);
  border-top:1px solid var(--tint);
}
.wrule{
  display:grid; grid-template-columns:64px minmax(0, 1fr);
  align-items:start;
  padding:clamp(14px, 1.5vw, 26px) 0;
  border-bottom:1px solid var(--tint);
}
.wrule__num{
  font-size:15px; font-weight:600; line-height:26px;
  color:var(--text-mute);
}
.wrule__text{
  max-width:626px;
  font-size:16px; font-weight:600; line-height:26px;
  color:var(--text-body);
}
.wrule__text a{ color:var(--link); }
.wrule__text a:hover{ color:var(--b-400); }

/* ---------- ARBYTE Service Pack ---------- */
/* The tiles cross the seam into the black plate below, so this band carries
   no bottom padding and the row is pulled down past its own edge instead. */
.asp{
  position:relative;
  display:flow-root;
  padding:clamp(34px, 3.7vw, 64px) 0 0;
  color:var(--text-inv);
  background:var(--surface-dark);
}
/* The band keeps its overflow visible — the tiles have to hang past its
   bottom edge — so the picture gets its own clipping layer instead. */
.asp__frame{
  position:absolute; inset:0; z-index:0;
  overflow:hidden;
  pointer-events:none;
}
.asp__photo{
  position:absolute; left:0;
  /* taller than the frame, hung 13% above it: that spare height is what the
     script slides the picture through as the band crosses the screen */
  top:-13%; width:100%; height:126%;
  object-fit:cover;
  will-change:transform;
}
.asp__veil{
  position:absolute; inset:0; z-index:1;
  background:rgb(0 0 0 / .43);
  pointer-events:none;
}
/* both dark bands hold their copy one step inside the content box, the way
   the mock insets them from the plate edge */
.asp__inner,
.wpres__inner{ padding-inline:clamp(0px, 2.4vw, 41px); }
.asp__inner{ position:relative; z-index:2; }
.asp.is-armed .asp__kicker,
.asp.is-armed .asp__title,
.asp.is-armed .asp__lead{
  opacity:0;
  transform:translateY(24px);
  transition:opacity .6s ease var(--in-lag, 0s),
             transform .6s cubic-bezier(.22, .61, .36, 1) var(--in-lag, 0s);
}
.asp.is-armed .asp__kicker.is-in,
.asp.is-armed .asp__title.is-in,
.asp.is-armed .asp__lead.is-in{ opacity:1; transform:none; }

.asp__kicker{
  font-size:clamp(14px, 1vw, 16px); font-weight:500; line-height:1.4;
  color:var(--text-inv-dim);
}
.asp__title{
  max-width:489px; margin-top:clamp(10px, 1vw, 18px);
  font-size:clamp(34px, 3.7vw, 64px);
  font-weight:500; line-height:1.1;
  color:var(--a-check);
}
.asp__lead{
  max-width:459px; margin-top:clamp(20px, 3.2vw, 55px);
  font-size:clamp(14px, 1.05vw, 18px); font-weight:500; line-height:1.6;
  color:var(--text-inv);
}
.asp__tiles{
  /* the overhang onto the plate below: 121 of the 349-tall tile at 1728 */
  --asp-drop:clamp(48px, 7vw, 121px);
  position:relative; z-index:3;
  list-style:none;
  display:grid; grid-template-columns:repeat(4, minmax(0, 1fr));
  gap:9px;
  margin-top:clamp(40px, 15vw, 258px);
  margin-bottom:calc(-1 * var(--asp-drop));
}
.asp__tile{
  display:flex; flex-direction:column; justify-content:space-between;
  gap:clamp(24px, 3vw, 52px);
  aspect-ratio:392/349;
  padding:clamp(18px, 1.9vw, 32px) clamp(18px, 1.9vw, 32px) clamp(20px, 2vw, 35px);
  background:rgb(39 39 39 / .49);
  /* frosted, so the photograph reads through the plate without competing
     with the copy on it. Where the tiles hang over the black plate below the
     band there is nothing to blur, and browsers without it keep the plain
     translucent fill. */
  -webkit-backdrop-filter:blur(10px);
          backdrop-filter:blur(10px);
}
.asp__icon{ display:block; }
.asp__icon svg{ display:block; width:clamp(64px, 6vw, 104px); height:auto; }
/* the first tile's mark is drawn larger than the other three */
.asp__icon--lg svg{ width:clamp(86px, 8.1vw, 140px); }

/* ---------- the four marks ----------
   Inline, so each mark is a set of named parts the stylesheet can move. They
   are still at rest until the tile is hovered.

   Only the parts that actually move get a centred origin: several groups
   inside the first mark are already turned by a transform attribute, which is
   the same CSS property, so re-basing their origin would move them. */
.wi__spin,
.wi__rays,
.wi__ray,
.wi__arc,
.wi__corner,
.wi__bar,
.wi--turn .wi__ring,
.wi--lock .wi__ring{ transform-box:view-box; transform-origin:50% 50%; }
.wi__ring{ stroke:var(--n-000); stroke-width:1.5; fill:none; }
.wi__dot{ fill:var(--a-check); }

/* 1 — обслуживание на территории: the sweeps turn the way their heads point,
   anticlockwise; the dashed ring drifts back the other way */
.asp__tile:hover .wi--turn .wi__spin{ animation:wi-turn 5s linear infinite reverse; }
/* the teal sweep leads: at 5s against 2.4s it reads as a different speed,
   which 3.2s did not */
.asp__tile:hover .wi--turn .wi__spin--lead{ animation-duration:2.4s; }
.asp__tile:hover .wi--turn .wi__ring{ animation:wi-turn 9s linear infinite; }

/* 2 — выезд специалиста: the three arcs go out one after another, while
   the pointer they come from holds still */
.asp__tile:hover .wi--send .wi__arc{ animation:wi-ping 1.9s ease-out infinite; }
.asp__tile:hover .wi--send .wi__arc:nth-child(3){ animation-delay:.19s; }
.asp__tile:hover .wi--send .wi__arc:nth-child(4){ animation-delay:.38s; }

/* 3 — диагностика: the fan turns and the rays light in sequence */
.asp__tile:hover .wi--scan .wi__rays{ animation:wi-turn 14s linear infinite; }
.asp__tile:hover .wi--scan .wi__ray{ animation:wi-flick 1.8s ease-in-out infinite; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(2){  animation-delay:.15s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(3){  animation-delay:.30s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(4){  animation-delay:.45s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(5){  animation-delay:.60s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(6){  animation-delay:.75s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(7){  animation-delay:.90s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(8){  animation-delay:1.05s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(9){  animation-delay:1.20s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(10){ animation-delay:1.35s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(11){ animation-delay:1.50s; }
.asp__tile:hover .wi--scan .wi__ray:nth-child(12){ animation-delay:1.65s; }

/* 4 — пакет обслуживания: the rings lock on, the brackets breathe */
.asp__tile:hover .wi--lock .wi__ring{ animation:wi-lock 2.1s ease-out infinite; }
.asp__tile:hover .wi--lock .wi__ring:nth-of-type(2){ animation-delay:.16s; }
.asp__tile:hover .wi--lock .wi__ring:nth-of-type(3){ animation-delay:.32s; }
.asp__tile:hover .wi--lock .wi__corner{ animation:wi-breathe 2.1s ease-in-out infinite; }
.asp__tile:hover .wi--lock .wi__bar{ animation:wi-breathe 2.1s ease-in-out infinite .2s; }

@keyframes wi-turn{ to{ transform:rotate(360deg); } }
@keyframes wi-ping{
  0%   { transform:scale(.86); opacity:.25; }
  45%  { opacity:1; }
  100% { transform:scale(1.06); opacity:0; }
}
@keyframes wi-flick{
  0%, 100% { opacity:.35; }
  50%      { opacity:1; }
}
@keyframes wi-lock{
  0%   { transform:scale(.72); opacity:0; }
  35%  { opacity:1; }
  100% { transform:scale(1.08); opacity:0; }
}
@keyframes wi-breathe{
  0%, 100% { transform:scale(1); }
  50%      { transform:scale(1.05); }
}

@media (prefers-reduced-motion:reduce){
  /* The hover rules above are more specific than any blanket reset, and the
     sheet-wide reduced-motion rule only shortens durations — which for a
     looping fade would flicker rather than stop. So this one has to shout. */
  .wi *{ animation:none !important; }
}
.asp__text{
  font-size:clamp(13px, 1.05vw, 18px); font-weight:500; line-height:1.6;
  color:var(--text-inv);
}

/* ---------- where the service reaches ---------- */
/* the top padding has to clear the tiles hanging over from the band above */
.wpres{
  position:relative;
  padding:clamp(120px, 15.7vw, 271px) 0 clamp(60px, 10.7vw, 185px);
  color:var(--text-inv);
  background:var(--surface-dark);
}
/* the copy sits over the empty western end of the map rather than beside it */
.wpres__copy{ position:relative; z-index:1; }
.wpres__title{
  max-width:340px;
  font-size:clamp(26px, 2.4vw, 40px);
  font-weight:500; line-height:1.2;
  color:var(--text-inv);
}
.wpres__go{
  display:inline-flex; align-items:center; gap:10px;
  margin-top:clamp(14px, 1.6vw, 28px);
  font-size:clamp(13px, 1vw, 16px); font-weight:500; line-height:1.6;
  color:var(--text-inv);
}
.wpres__caret{
  display:grid; place-items:center;
  width:23px; height:23px; flex:none;
  border:1px solid rgb(255 255 255 / .35); border-radius:50%;
  transition:background .18s ease, border-color .18s ease;
}
.wpres__caret::before{
  content:"";
  width:10px; height:5px;
  background:var(--text-inv);
  -webkit-mask:var(--caret-mask) no-repeat center / contain;
          mask:var(--caret-mask) no-repeat center / contain;
  transform:rotate(-90deg);
  transition:background .18s ease;
}
.wpres__go:hover .wpres__caret{ border-color:var(--a-check); background:var(--a-check); }
/* ---------- the map itself ----------
   One inline SVG: a path per region, then a pin per city. The drawing scales
   with the column, so two custom properties re-inflate the parts that must not
   shrink with it — the pin and its label. Hairlines hold their width through
   the vector-effect attribute on the shapes themselves. */
.smap{
  --pin:1;            /* pin scale */
  --tip:1;            /* label scale */
  /* the map's own four tones; each region picks a pair through --fill/--line,
     which is also what lets one arrival animation serve both kinds */
  --map-fill:#161616;
  --map-line:#2e2e2e;
  --map-fill-on:#1f2a2a;
  --map-line-on:#3b4a4a;
  display:block;
  width:100%; max-width:1299px; height:auto;
  /* pulled back up so the heading overlaps its blank western edge */
  margin:clamp(-111px, -6.4vw, 0px) auto 0;
  overflow:visible;   /* labels may stand above the top edge */
}

/* --- the map arriving ---
   Script adds .is-armed and the per-shape --in-lag that runs the light west to
   east, then takes .is-armed off once the sweep is over — so none of this is
   left filled-forwards over the resting colours or the hover. */
.smap.is-armed .smap__reg{ opacity:0; }
.smap.is-armed .smap__reg.is-in{
  animation:smap-in .75s ease var(--in-lag, 0s) both;
}
@keyframes smap-in{
  from{ opacity:0; stroke:var(--a-check); stroke-width:1.6; }
  50% { opacity:1; stroke:var(--a-check); stroke-width:1.6; }
  to  { opacity:1; stroke:var(--line);    stroke-width:1; }
}

.smap.is-armed .smap__pin{
  opacity:0;
  transform:scale(.35);
  transform-box:fill-box; transform-origin:center;
  transition:opacity .35s ease var(--in-lag, 0s),
             transform .5s cubic-bezier(.2, .9, .3, 1.35) var(--in-lag, 0s);
}
.smap.is-armed .smap__pin.is-in{ opacity:1; transform:none; }

/* --- regions --- */
.smap__reg{
  --fill:var(--map-fill);
  --line:var(--map-line);
  fill:var(--fill);
  stroke:var(--line); stroke-width:1;
  transition:fill .18s ease, stroke .18s ease;
}
/* the ones that already have a service centre carry a standing tint */
.smap__reg--on{ --fill:var(--map-fill-on); --line:var(--map-line-on); }
.smap__reg:hover{ fill:#283636; stroke:var(--a-check); }
.smap__reg--on:hover{ fill:#2f4442; }

/* --- pins --- */
.smap__pin{ cursor:pointer; }
.smap__pin:focus{ outline:none; }
.smap__mark{
  transform:scale(var(--pin));
  transform-box:fill-box; transform-origin:center;
}
.smap__hit{ fill:transparent; stroke:none; }
.smap__ring{
  fill:none;
  stroke:var(--a-check); stroke-width:1.5;
  transition:stroke .18s ease;
}
.smap__dot{ fill:var(--a-check); }
/* the ring that keeps going out and fading */
.smap__wave{
  fill:none;
  stroke:var(--a-check); stroke-width:1.5;
  transform-box:fill-box; transform-origin:center;
  animation:smap-wave 2.8s ease-out infinite;
}
/* three groups, so the pins do not all breathe on the same beat */
.smap__pin:nth-child(3n+2) .smap__wave{ animation-delay:.9s; }
.smap__pin:nth-child(3n+3) .smap__wave{ animation-delay:1.8s; }
@keyframes smap-wave{
  0%   { transform:scale(1);   opacity:.55; }
  70%  { transform:scale(3.2); opacity:0; }
  100% { transform:scale(3.2); opacity:0; }
}
.smap__pin:hover .smap__ring,
.smap__pin:focus-visible .smap__ring{ stroke:var(--n-000); }
.smap__pin:focus-visible .smap__hit{ stroke:var(--n-000); stroke-width:1.5; }

/* --- the label over a pin --- */
.smap__tipbox{
  transform:scale(var(--tip));
  transform-box:fill-box; transform-origin:bottom center;
  opacity:0;
  transition:opacity .16s ease;
  pointer-events:none;
}
.smap__tipbox rect{ fill:#3d3d3d; }
.smap__tipbox text{
  fill:var(--text-inv);
  font-family:var(--font); font-size:13px; font-weight:600;
  text-anchor:middle;
}
.smap__pin:hover .smap__tipbox,
.smap__pin:focus-visible .smap__tipbox{ opacity:1; }

@media (prefers-reduced-motion:reduce){
  .smap__wave{ animation:none; opacity:.28; }
}

@media (max-width:1023px){
  .hero__foot--warranty{ grid-template-columns:minmax(0, 1fr); align-items:start; }
  .wstd{ grid-template-columns:minmax(0, 1fr); row-gap:clamp(26px, 4vw, 44px); }
  /* one column now: pinning the heading would park it on top of the cards */
  .wstd__intro{ position:static; padding-right:0; }
  .asp__tiles{ grid-template-columns:repeat(2, minmax(0, 1fr)); }
  .asp__tile{ aspect-ratio:auto; min-height:230px; }
  /* the drawing has shrunk, so the pins and their labels are drawn larger
     inside it to hold their size on screen */
  .smap{
    --pin:1.5; --tip:1.6;
    margin-top:clamp(16px, 2vw, 30px);
  }
}

@media (max-width:767px){
  .hero__foot--warranty{ margin-left:0; }
  .hero__centres,
  .hero__claim{ width:100%; }
  .wcards{ grid-template-columns:minmax(0, 1fr); }
  .wcard__name{ max-width:64%; }
  .asp__tiles{ grid-template-columns:minmax(0, 1fr); }
  .asp__tile{ min-height:0; gap:20px; }
  .wrule{ grid-template-columns:44px minmax(0, 1fr); }
  .wrule__text{ font-size:15px; line-height:24px; }
  .wpres__title{ max-width:none; }
  .smap{ --pin:2.9; --tip:3.2; }
}
