/* ============================================================
   BLACK DUCK — страницы из компилятора figma/gen_flow.py (общие для ВСЕХ
   страниц классы guillotine-разметки, gf-*), + settings ленты-компонента
   (сама .marq уже есть в main.css). Страничные особые случаи — классы
   .s-<frameId> (см. PAGES[<L>]["css_class"] в gen_flow.py); дублировать
   общие правила в них не нужно.
   ============================================================ */
.gf-body{background:#0b0b0b}
.gf-text{white-space:normal}
.gf-text em{display:inline}
.gf-img{max-width:none}
.gf-node{box-sizing:border-box}
.gf-overlay{box-sizing:border-box}
/* Контракт высоты (PHASE2-ARCH, уточнение 10.09): на эталоне 1440 — точная
   высота из Figma (height); ниже эталона (переходный режим 1024-1440) —
   обёртка растёт по контенту (min-height), чтобы текст не резался/не наезжал. */
.gf-t,.gf-node{height:var(--h)}
@container (max-width:1439.98px){.gf-t,.gf-node{height:auto;min-height:var(--h)}}
/* Надёжный переключатель режима высот: класс на <html> ставит js/main.js по
   window.innerWidth. Контейнерный запрос выше остаётся запасным вариантом на
   случай выключенного JS, но при зуме он врал (Chrome на 1512/1536/1600 включал
   min-height при кадре ровно 1440), поэтому классы его перебивают. */
html.is-wide .gf-t,html.is-wide .gf-node{height:var(--h);min-height:0}
html.is-narrow .gf-t,html.is-narrow .gf-node{height:auto;min-height:var(--h)}
.gf-hit{position:absolute;display:block;z-index:3;cursor:pointer}
.gf-hero .player,.gf-brands .player{background-color:#1E1E1E}
.gf-brands .marq{overflow:visible}

/* ---------- страница B (pricing-new.html) ---------- */
/* 22.09: правило «.s-b-plans .marq--x{mask-image:none}» УДАЛЕНО вместе со
   своим предметом. Оно снимало фейд у плиток внутри карточки «One strategic
   partner…» (build_pill_rows), а та карточка ушла из макета при пересборке
   страницы на новую колонку фреймов. В .s-b-plans теперь только лента
   логотипов «TRUSTED BY», и ей нужен тот же фейд по краям, что и на
   остальных 12 страницах, — иначе логотипы обрубались бы краем кадра. */
/* На застывшем кадре (?qa=1) animation-play-state:paused (main.css) не
   обнуляет позицию — фиксирует ту, что успела натечь за миллисекунды
   между покраской ленты и applyQaFreeze() в main.js (обычно доли px,
   но у .s-b-plans/.s-b-testi это первая страница, где содержимое ленты
   само несёт data-node — предыдущие build_brands_marq/build_hero_marq
   рисуют детей без data-node, поэтому дрейф раньше был невидим сверке).
   Жёстко фиксируем "from"-кадр — он же единственно верный по Figma. */
.qa-freeze .s-b-plans .marq__track,.qa-freeze .s-b-testi .marq__track{transform:translate3d(0,0,0) !important}
/* FAQ-аккордеон (build_faq, 6735:8334): нативный <details>/<summary>,
   свой чек-маркер браузера убираем — в макете вместо него шеврон-картинка. */
.faq-item{list-style:none}
.faq-item summary{list-style:none;cursor:pointer;outline:none}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary::marker{content:''}
/* display:flow-root — блокирует схлопывание отрицательного margin-top
   вложенного .gf-text (cap-trim) с родителем: без этого он утягивал
   верхнюю границу .faq-item__q вверх на ту же величину, а шеврон-иконка
   (position:absolute;top:0 от .faq-item__q) уезжала вместе с ней. */
.faq-item__q{position:relative;display:flow-root;height:20px}
.faq-item__qtext{position:relative;display:flow-root}
.faq-item__qtext .gf-text{padding-right:44px}
.faq-item__chevron{flex:0 0 auto;transition:transform .2s ease}
/* открытая строка — «минус» (js/mobile.js меняет картинку), не повёрнутый плюс (25.09) */
/* Ответ раскрывается на свою высоту (23.09: тексты появились из мобильного
   кадра; раньше коробка была пустой и держала 48px). Анимация — по
   grid-template-rows: max-height на неизвестную высоту не настроить, а
   жёсткий потолок обрезал бы длинные ответы (до 813 знаков). */
/* 1px макета = 1 экранный px при любом масштабе: на окнах шире 1440 корень
   увеличен (zoom 1.28 на 1848), и в Safari линия выходила в 3 точки экрана
   вместо 2 — «толстые линии» (заказчица 25.09) */
.faq-item--line::after{content:"";position:absolute;left:0;right:0;bottom:0;height:calc(1px / var(--zk, 1));background:#D1D1D1;pointer-events:none}
.faq-item{transition:transform .28s ease}
.faq-item__a{display:grid;grid-template-rows:0fr;overflow:hidden;
  transition:grid-template-rows .28s ease}
.faq-item[open] .faq-item__a{grid-template-rows:1fr}
.faq-item__a>p{min-height:0;margin:0;overflow:hidden;
  font-family:var(--f-sans);font-weight:400;color:rgba(13,30,29,.72);
  font-size:calc(1.0417 * var(--cq));line-height:1.55;
  padding:10px 44px 14px 0}
.m-only .faq-item__a>p,.is-mob .faq-item__a>p{font-size:calc(3.8168 * var(--cq));padding-right:24px}

/* Лента карточек «Concept creation services» (H, build_cards_strip): едет сама,
   как герой-лента (.marq--x), под курсором замирает. */
.cstrip{overflow:hidden;user-select:none;-webkit-user-select:none}
.cstrip img{-webkit-user-drag:none;pointer-events:none}
.cstrip:hover .marq__track{animation-play-state:paused}   /* запасной вариант на CSS-анимации (?лента=1, reduced-motion) */
.cstrip[data-swipe]{cursor:grab}
.cstrip[data-swipe]:active{cursor:grabbing}   /* ленту тянут мышью (заказчица 07.10: «ручной скролл») */
/* панель карточки: в покое только название, при наведении — до высоты макета с описанием (как superside.com/ai-creative) */
.cpanel{height:var(--rest);transition:height .3s ease-in-out}
.cstrip__card:hover .cpanel{height:var(--full)}
.cdesc{opacity:0;transition:opacity .3s ease-in-out}
.cstrip__card:hover .cdesc{opacity:1}
/* область картинки: как у superside окно картинки сжимается, содержимое уезжает
   вверх на половину прироста панели и слегка увеличивается */
.cstrip__card>div:not(.cpanel){transition:transform .3s ease-in-out;transform-origin:50% 50%}
.cstrip__card:hover>div:not(.cpanel){transform:translateY(calc((var(--rest) - var(--full)) / 2)) scale(1.04)}
/* ---------- мобильная вёрстка (23.09) ----------
   Кадр мобильного макета — 393px, единица кадра ровно его сотая доля.
   Через --frame-max это не сделать: html.is-wide (main.css) считает --cq от
   переменной КОРНЯ, а корень остаётся десктопным. */
.is-mob{min-width:0}
/* 24.09: единица кадра — настоящая контейнерная (1% ширины кадра), а кадр
   тянется на всю ширину окна. Вместе с переводом вертикали в те же доли
   (см. в_доли_кадра) это делает мобильную вёрстку полностью текучей:
   масштабировать корень больше не нужно, текст остаётся резким. */
.is-mob .gf-frame,.m-only .gf-frame{--cq:1cqw;max-width:none}
/* Слои фона секции (bleed-картинки первого экрана и т.п.) лежат СНАРУЖИ .gf-frame,
   где --cq не задан: подхватывалось десктопное 14.4px, и фон шапки на телефоне
   раздувало до 2854px высоты — мутное пятно вместо картинки на всех 14 страницах
   (жалоба 24.09). Секция — тоже контейнер, --cq = 1% её ширины. */
.m-only .gf-section{container-type:inline-size;--cq:1cqw}
/* Зоны нажатия на телефоне (заказчица 24.09: «работает, только если на буквах
   нажимаешь»). Прозрачные ссылки gf-hit были ровно по тексту — 96×12 px у
   пунктов меню, 23×11 у бургера. Расширяем невидимым ::before, вёрстка на месте:
   пункт меню — вся строка между разделителями (шаг строк в макете 15.776 cq),
   бургер и крестик — 48×48 px вокруг значка. */
.mmenu .gf-hit[href="#mservices"]::before,.mmenu .gf-hit[href="our-work.html"]::before,.mmenu .gf-hit[href="pricing.html"]::before{content:"";position:absolute;left:calc(-3.8168 * var(--cq));width:calc(100 * var(--cq));top:calc(-6.3613 * var(--cq));height:calc(15.776 * var(--cq))}
.m-only .gf-hit[href="#menu"]::before,.m-only .gf-hit[href="#mclose"]::before{content:"";position:absolute;left:50%;top:50%;width:48px;height:48px;transform:translate(-50%,-50%)}
/* выезжающая шапка телефона (js/mobile.js): копия шапки макета, выезжает сверху,
   когда исходная ушла за край при прокрутке; под меню (оверлей z-index 60) */
.mbar{position:fixed;left:0;right:0;top:0;z-index:50;background:#000;transform:translateY(-100%);transition:transform .3s ease;will-change:transform}
.mbar.is-on{transform:none}
.mbar img{display:block;max-width:none}
.mbar__menu::before{content:"";position:absolute;left:50%;top:50%;width:48px;height:48px;transform:translate(-50%,-50%)}
/* лента со свайпом (js/main.js data-swipe): без выделения, «лупы» и системного
   перетаскивания картинки по долгому касанию на iPhone */
.marq[data-swipe]{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
/* мобильные ленты обрезает край экрана (.gf-frame), а не собственная граница:
   лента услуг главной стоит с отступом 15px, и карточки пропадали, не дойдя до
   края, — белая полоса слева (заказчица 25.09) */
.m-only .marq--x{overflow:visible}
/* серая подсветка нажатия iPhone (rgba(0,0,0,.4) на весь увеличенный ::before)
   мигала на строках меню и футера — убираем на всех ссылках и кнопках (25.09) */
html,.m-only a,.m-only button,.m-only summary,.m-only details,.m-only [role="button"],.mbar a,.faq-item summary{-webkit-tap-highlight-color:transparent}
/* свойство наследуется: на html — значит на ВСЁМ нажимаемом (вопросы FAQ —
   <summary>, их прошлое правило не покрывало; блик на «плюсиках», 25.09) */
/* футер телефона (js/mobile.js): ссылки пунктов и кнопка-раскрывашка на всю
   строку «Services» / «Navigation» (прозрачные, поверх текста) */
.mfoot__lnk{position:absolute;left:0;right:-24px;top:-5px;bottom:-5px;z-index:4}
.mfoot__acc{position:absolute;left:0;top:-10px;bottom:-10px;width:calc(100 * var(--cq) - 2 * 3.8168 * var(--cq));min-width:100%;z-index:4;background:none;border:0;padding:0;margin:0;cursor:pointer;-webkit-tap-highlight-color:transparent}
.mfoot [data-node="7011:5495"],.mfoot [data-node="7011:5496"]{transition:transform .25s ease}
.marq[data-swipe] img{-webkit-user-drag:none;user-drag:none}
/* логотип → главная: картинка всего 17px в высоту, зона нажатия 44px */
.m-only a[aria-label="BLACK DUCK — home"]::before{content:"";position:absolute;left:-8px;right:-8px;top:50%;height:44px;transform:translateY(-50%)}
/* Высоты боксов — макетные, как в обычном (не qa) режиме десктопа
   (html.is-wide .gf-t). Без этого бокс текста в потоке чуть выше макетного
   (обрезка leading не совпадает с высотой кадра до десятых), и внутри
   карточки ошибка копится: 1.0 → 1.7 → 2.4px на четырёх элементах (23.09). */
/* 24.09: было height:var(--h) — бокс держал макетную высоту, и текст,
   которому в браузере нужно больше строк, печатался ПОВЕРХ соседа (снимки
   с телефона: «Increase social volume», рельс шагов, карточки лент).
   min-height оставляет макетную высоту там, где текст влезает, и даёт
   блоку вырасти там, где не влезает: соседи сдвигаются, а не перекрываются.
   Накопление в 1-2px внутри карточек (п.34) — меньшее зло, чем наезд. */
/* 24.09, итог: высота снова МАКЕТНАЯ. Наезд текста был не от неё, а от
   лишней пустой строки на стыке ранов («

» в Figma = один перевод) —
   это исправлено в render_text_leaf. Теперь строки совпадают с макетом,
   текст влезает в свой бокс, и жёсткая высота возвращает точность. */
.is-mob .gf-t,.is-mob .gf-node,.m-only .gf-t,.m-only .gf-node{height:var(--h);min-height:0}
.m-only{display:none}
/* оверлей мобильного меню: поверх страницы, во всю высоту окна */
.mmenu-ovl{position:fixed;inset:0;z-index:60;overflow-y:auto;background:#fff;display:none}
.mmenu-ovl[hidden]{display:none}
body.mmenu-open{overflow:hidden}
@media (max-width:699px){
  .mmenu-ovl:not([hidden]){display:block}
}
@media (max-width:699px){
  body{min-width:0}
  .d-only{display:none}
  /* колонка ровно макетной ширины и по центру: выше потолка масштаба
     (js/mobile.js) окно шире макета, и поля уходят по краям */
  .m-only{display:block}
}
/* Шары отзыва (страница B, build_vcircles): колонка стоит по макету, шаг
   делают стрелки (js/pages.js). Слот 2 — центральный: 180px, непрозрачный.
   Переход top/width/opacity даёт проворот: шар едет в соседний слот и по
   дороге меняет размер и прозрачность на «слотовые». */
.vball{position:absolute;left:50%;transform:translate(-50%,-50%);border-radius:50%;
background:#BCB118;width:calc(11.3889 * var(--cq));aspect-ratio:1;opacity:.2;
transition:top .5s cubic-bezier(.4,0,.2,1),width .5s cubic-bezier(.4,0,.2,1),opacity .5s ease}
.vball[data-slot="-1"]{top:calc(284px + (-127.2265 * var(--cq)) + (-30px))}
.vball[data-slot="0"]{top:calc(284px + (-85.4962 * var(--cq)) + (-20px))}
.vball[data-slot="1"]{top:calc(284px + (-43.7659 * var(--cq)) + (-10px));opacity:.4}
.vball[data-slot="2"]{top:284px;width:calc(45.8015 * var(--cq));opacity:1}
.vball[data-slot="3"]{top:calc(284px + (43.7659 * var(--cq)) + (10px));opacity:.4}
.vball[data-slot="4"]{top:calc(284px + (85.4962 * var(--cq)) + (20px))}
.vball[data-slot="5"]{top:calc(284px + (127.2265 * var(--cq)) + (30px))}
.hball{position:absolute;top:0;transform:translate(-50%,-50%);border-radius:50%;aspect-ratio:1;
transition:left .5s cubic-bezier(.4,0,.2,1),width .5s cubic-bezier(.4,0,.2,1),background-color .5s ease}
.hball[data-slot="-3"]{left:calc(-20.9924 * var(--cq));width:calc(18.0662 * var(--cq));background:#EEEDCE}
.hball[data-slot="-2"]{left:calc(-0.3817 * var(--cq));width:calc(18.0662 * var(--cq));background:#EEEDCE}
.hball[data-slot="-1"]{left:calc(22.5191 * var(--cq));width:calc(22.6463 * var(--cq));background:#E2DEA1}
.hball[data-slot="0"]{left:calc(50.0000 * var(--cq));width:calc(27.2265 * var(--cq));background:#BCB118}
.hball[data-slot="1"]{left:calc(77.4809 * var(--cq));width:calc(22.6463 * var(--cq));background:#E2DEA1}
.hball[data-slot="2"]{left:calc(100.3817 * var(--cq));width:calc(18.0662 * var(--cq));background:#EEEDCE}
.hball[data-slot="3"]{left:calc(120.9924 * var(--cq));width:calc(18.0662 * var(--cq));background:#EEEDCE}
.hball.is-jump{transition:none}
.vball.is-jump{transition:none}   /* перескок по кругу за кадром — без анимации */
@media (prefers-reduced-motion: reduce){.vball{transition:none}}
/* Зум картинок работ при наведении (как .project__media на главной) */
.gf-zoom>img{transition:transform .4s ease}
.gf-zoom.is-hover>img{transform:scale(1.03)}
/* счётчик шире бокса макета (числа заменены на реальные 06.10: 800+ → 3500+):
   у центрированной цифры переполнение — поровну в обе стороны, центр на месте.
   Шрифт и кегль — из макета, не трогаем */
.gf-text[style*="text-align:center"] [data-count]{margin-inline:-60px}
