/* три набори кольорів, по одному на розділ: світлий для фото й дизайну,
   зелений для головної, нічний для відео. Вибирає їх не гість і не його
   система, а сама сторінка — data-theme стоїть у <html> ще до першого
   байта стилів. Доти набір залежав ще й від prefers-color-scheme, і той,
   хто колись натиснув «світлу», носив її за собою по всьому сайту */
:root[data-theme="light"]{color-scheme:light}
:root[data-theme="green"]{
  color-scheme:dark;
  /* та сама охра, світліша й тепліша. Доти тут стояло #e6bb7c, і в
     найсвітлішому куті плити воно давало 3,84:1 — нижче за поріг, хоч
     коментар обіцяв 5:1. Піднято на пів тону: тепер 4,53:1 угорі,
     7,56:1 посередині, 11:1 унизу, тобто поріг тримається на всій плиті.
     Не яскравіше: це підкреслення, а не заклик */
  --pencil:#f0cd96; --active:#f0cd96;
  --bg:#2b3e2d; --surface:#3a5340; --ink:#eaf1e7;
  /* верх плити: до нього примикає скляна шапка й обвід браузера */
  --plate-top:#42563f;
  /* Той самий виміряний тон, що й у бургер-меню Photo, Video та Design. */
  --menu-plate:#47564b;
  /* Кінці ті самі, що були з самого початку, але пройдені рівним кроком
     по OKLCH і дев'ятьма стопами: три стопи давали злам на середньому,
     і око читало злам смугою */
  --plate-base:linear-gradient(154deg,#4f5f49 0%,#4b5b47 8.3%,#445542 16.7%,#3b4d3d 25%,#344738 33.3%,#2f4234 41.7%,#2b3e31 50%,#283a2e 58.3%,#24352a 66.7%,#1f2f25 75%,#1a2a21 83.3%,#15241d 91.7%,#13211a 100%);
  --grain:.18;
  --divider:color-mix(in srgb, #eaf1e7 34%, transparent);
  --mute:color-mix(in srgb, #eaf1e7  80%, transparent);
}
body{
  margin:0; background:transparent; color:var(--ink);
  font-family:var(--font); font-stretch:var(--text-stretch);
  font-size:var(--fs-text); line-height:1.55; font-weight:400;
  /* clip, а не hidden: hidden робить із body контейнер прокрутки, і саме
     на ньому спотикалась інвалідація шарів — сліди від смуг ховера
     лишались там, де вони були до гортання. clip ріже так само, але
     контейнера прокрутки не заводить */
  overflow-x:hidden; overflow-x:clip;
}
h1,h2,h3{margin:0; font-stretch:var(--display-stretch); font-weight:700; letter-spacing:-.02em; line-height:1}
.meta + .rule{margin-bottom:2px}

/* ── marginalia bar ───────────────────────────────────────── */
.meta{
  display:grid; grid-template-columns:1fr auto; gap:var(--pad) 24px;
  /* у ряду тепер живе ім'я, тож ряд дихає, а не тулиться до лінійки */
  padding-block:var(--meta-pad); align-items:center;
}
.meta .cols{display:flex; gap:clamp(16px,4vw,64px); flex-wrap:wrap; align-items:center}
@media (min-width:761px){
.meta .cols > .tiny:first-child{padding-left:var(--chrome-pad)}
}
.home-meta .contact-link{font-size:var(--fs-label)}
#clock{font-variant-numeric:tabular-nums; font-feature-settings:"tnum" 1}
.meta .tiny{white-space:nowrap}
.meta .local-time{display:inline}
.tiny b{font-weight:700; color:var(--ink); letter-spacing:var(--ls-tiny)}
.tgl{display:flex; gap:0; align-items:center}
/* тільки перша група в ряду тулиться до краю — далі проміжок тримає .switches */
.switches > .tgl:first-child button:first-child{padding-left:0}
:root[data-theme="green"] .tgl button[aria-pressed="true"],
:root[data-theme="night"] .tgl button[aria-pressed="true"]{font-weight:700;font-variation-settings:"wght" 700}
.switches .contact-link{white-space:nowrap}
/* широко шапка стає на ту саму 12-колонкову сітку, що й сторінка:
   перемикачі починаються з 11-ї колонки, а не просто тиснуться до
   правого краю. space-between лишає мову на правій межі верстки, тож
   група займає рівно дві останні колонки.
   Нижче 1000px колонка 11 завузька для двох груп поспіль — там шапка
   лишається на старій сітці «зліва інформація, справа перемикачі» */
@media (min-width:1000px){
  .meta{grid-template-columns:1fr auto; column-gap:clamp(24px,3vw,48px)}
  .meta > .cols:first-child{grid-column:auto}
  .meta .switches{grid-column:auto; justify-content:flex-end; flex-wrap:nowrap}
}
@media (max-width:560px){
  .meta{grid-template-columns:minmax(0,1fr) auto; column-gap:12px; row-gap:0}
  .meta .cols{gap:14px}
  /* Terms лишається праворуч від міста й часу; мова нижче 640px
     переноситься у футер, тому перший рядок не перевантажується. */
  .meta .switches{grid-column:2;grid-row:1;justify-content:flex-end}
}
@media (max-width:760px){
  .meta{padding-bottom:var(--meta-pad)}
}
/* Той самий контракт рядка, що й у розділів: у цьому вузькому діапазоні
   кнопки мають 44px тач-поле, але видимий рядок шапки — рівно 24px.
   Винесене від’ємними полями тач-поле не може вплинути на лінійку. */
@media (min-width:641px) and (max-width:760px){
  .meta .switches{height:var(--mobile-meta-row);padding-bottom:0}
}
@media (max-width:640px){
  /* На головній усі елементи .switches лишаються в шапці й читаються
     зліва направо в тому самому порядку, що й на десктопі:
     «Умови співпраці», «Контакти», EN/UA. */
  /* Мобільна шапка має один спільний вертикальний контракт із розділами:
     24px на видимий рядок і 8px оптичного поля до лінійки. Поле належить
     самій .meta, тому висоту більше не визначає випадково найвища кнопка. */
  .meta{
    --mobile-meta-row:24px;
    grid-template-columns:1fr;
    padding-bottom:calc(var(--meta-pad) + 8px)
  }
  .meta .cols{display:none}
  .meta .switches > .tgl{display:flex}
  .meta .switches > .mobile-contact-link{display:inline-block}
  .meta .switches{
    grid-column:1;grid-row:1;justify-content:flex-end;
    height:var(--mobile-meta-row);padding:0 var(--chrome-pad) 0 0
  }
  .language-slot{display:flex;align-items:center;gap:clamp(12px,1.8vw,26px)}
  .language-slot .mobile-contact-link{display:inline-block;margin-right:clamp(12px,1.8vw,26px);white-space:nowrap}
  .site-foot .language-slot .mobile-contact-link{color:var(--mute)}
  .site-foot .language-slot .mobile-contact-link:hover{color:var(--accent)}
  .language-slot > .tgl button:first-child{padding-left:0}
}
/* EN/UA не має власного вертикального просвіту: напис стоїть точно в
   24px-рядку шапки, на тій самій вертикалі, що й лінійка. */
@media (max-width:640px){
  .meta .switches > .tgl#lang button{
    padding:0;min-height:24px;margin-block:0;line-height:24px
  }
}

/* Десктопна шапка має дихати від лінійки так само, як копірайт у футері:
   навігація відступає зліва на 8px, правий блок — справа на 8px. В
   англійській версії .cols уже внизу, тому шапка переходить із трьох
   колонок у дві, але сама навігація лишається у верхньому рядку. */
@media (min-width:641px){
  .home-meta .parts{padding-left:var(--chrome-pad)}
  .home-meta .switches{justify-self:end}
  :root[lang="en"] .home-meta,
  :root[lang="uk"] .home-meta{grid-template-columns:minmax(0,1fr) auto}
  :root[lang="en"] .home-meta .parts,
  :root[lang="uk"] .home-meta .parts{grid-column:1;grid-row:1}
  :root[lang="en"] .home-meta .switches,
  :root[lang="uk"] .home-meta .switches{grid-column:2;grid-row:1}
}

/* ── навігація головної ───────────────────────────────────── */
/* На широкому екрані розділи стоять між службовою інформацією та
   перемикачами. На телефоні розділи лишаються видимими, а в плашку
   переноситься службова група — той самий overflow-контракт, що й у
   сторінок Photo, Video та Design. */
.home-meta{position:relative;grid-template-columns:minmax(0,1fr) auto auto;column-gap:clamp(18px,3vw,48px)}
.home-meta .parts{display:flex;align-items:center;gap:clamp(12px,1.8vw,26px);justify-self:start;min-width:0}
.home-meta .part{font-size:var(--fs-label);letter-spacing:var(--ls-tiny);text-transform:uppercase;font-weight:600;
  color:var(--mute);white-space:nowrap;padding-block:16px;line-height:1;display:inline-block;transform-origin:center;transition:color 220ms var(--ease),transform 220ms var(--ease),-webkit-text-stroke 220ms var(--ease)}
@media (pointer:fine){
.home-meta .part{padding-block:9px}
}
@media (hover:hover){
.home-meta .part:hover{color:var(--ink);transform:scaleX(1.025);-webkit-text-stroke:.18px currentColor}
}
.home-meta.header-menu-mode{position:relative;grid-template-columns:minmax(0,1fr) auto}
.home-meta.header-menu-mode > .parts{grid-column:1;grid-row:1;min-width:0;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}
.home-meta.header-menu-mode > .header-menu-toggle{
  grid-column:2;grid-row:1;justify-self:end;display:grid;place-items:center;
  appearance:none;width:44px;height:44px;margin:-10px -8px -10px 0;padding:0;
  border:0;background:transparent;color:var(--ink);cursor:pointer
}
.home-meta.header-menu-mode .header-menu-panel .contact-link{
  display:flex;align-items:center;width:100%;min-height:40px;padding:10px 0;text-align:left;white-space:normal
}
.home-meta.header-menu-mode .header-menu-panel .switches > .tgl{
  display:grid;grid-template-columns:auto auto;gap:clamp(12px,1.8vw,26px);align-items:center;width:100%;min-height:40px
}
.home-meta.header-menu-mode .header-menu-panel .tgl button{
  width:auto;min-height:40px;margin:0;padding:10px 0 10px 16px
}
/* Єдиний контракт компактної шапки з Photo, Video та Design:
   видимий рядок завжди 24px, а touch-зона бургеру не роздуває його. */
@media (max-width:760px){
  .home-meta.header-menu-mode{
    --mobile-meta-row:24px;
    grid-template-rows:var(--mobile-meta-row);
    padding-top:var(--meta-pad-top);
    padding-bottom:var(--meta-pad-bottom);
    align-items:center
  }
  .home-meta.header-menu-mode > .parts{
    align-self:center;align-items:center;height:var(--mobile-meta-row);padding:0 0 0 var(--chrome-pad)
  }
  .home-meta.header-menu-mode > .parts > .part{line-height:1}
  .home-meta.header-menu-mode > .header-menu-toggle{
    align-self:center;width:24px;height:24px;margin:0 8px 0 0
  }
  .home-meta.header-menu-mode:not(.header-menu-open) > .header-menu-panel{
    transform:translate3d(0,-6px,0) scale(.95,.98)
  }
}
/* Розділи в панелі стоять першими й тим самим стовпчиком рядків, що й
   службові посилання під ними: та сама висота рядка, те саме поле. */
.home-meta.header-menu-mode .header-menu-panel .parts{
  position:static;display:grid;grid-template-columns:1fr;grid-column:auto;grid-row:auto;
  justify-self:stretch;width:100%;height:auto;margin:0;padding:0;gap:0;overflow:visible
}
.home-meta.header-menu-mode .header-menu-panel .part{
  display:flex;align-items:center;width:100%;min-height:40px;padding:10px 0;
  line-height:1;white-space:normal
}
/* Відбивка між розділами й службовою групою — та сама волосяна лінійка,
   якою на всьому сайті розділені рядки. Вона з'являється рівно тоді, коли
   над групою справді стоять розділи, тобто тільки на головній. */
.home-meta.header-menu-mode .header-menu-panel .parts + .switches{
  margin-top:10px;padding-top:10px;border-top:var(--rule) solid var(--divider)
}
/* ── заклик замовити послугу ──────────────────────────────── */
/* На телефоні розділи їдуть у бургер, а на їхньому місці в рядку шапки
   лишається єдина дія сторінки. Охра тут за тим самим правилом, що й
   усюди на сайті: вона означає «сюди можна натиснути». Лінійки під
   написом немає — сам колір уже виділяє його з рядка, а риска робила з
   заклику перекреслений напис на 24px-рядку. Широко заклику немає: там у
   рядку стоять і розділи, і умови, і контакти, і зайвий заклик лише
   сперечався б із ними.
   Поле й рівне від'ємне зовнішнє поле — той самий прийом, яким винесено
   44px ціль перемикачів: коробка росте, видимий рядок лишається 24px.
   Висота при цьому мусить бути 24+20, а не 24: box-sizing тут border-box,
   і 24px разом із полями лишали б написові 4px — лінійка під ним ставала
   б перекресленням. */
.order-cta{display:none}
@media (max-width:760px){
  .home-meta.header-menu-mode > .order-cta{
    grid-column:1;grid-row:1;align-self:center;justify-self:start;
    display:inline-flex;align-items:center;position:relative;
    height:calc(var(--mobile-meta-row) + 20px);margin-left:var(--chrome-pad);
    padding-block:10px;margin-block:-10px;
    font-size:var(--fs-label);letter-spacing:var(--ls-tiny);text-transform:uppercase;
    font-weight:700;font-variation-settings:"wght" 700;line-height:1;
    color:var(--pencil);white-space:nowrap;transform-origin:left center;
    transition:transform 220ms var(--ease)
  }
  @media (hover:hover){
    .home-meta.header-menu-mode > .order-cta:hover{transform:scaleX(1.025)}
}
}
/* ── герой ─────────────────────────────────────────────────── */
/* усе, що клієнт має побачити не гортаючи, живе в одному гріді:
   ім'я, одне речення по суті, три ремесла дрібним кеглем, кнопка й
   статус — і портрет праворуч. Доти перший екран був двома окремими
   секціями на пів екрана кожна (ім'я з лідом, тоді сходи фахів із
   фото), займав півтора екрана і не давав куди натиснути */
.hero{
  display:grid; grid-template-columns:repeat(12,1fr);
  /* другий рядок — 1fr: портрет спанить обидва, і коли він вищий за
     ім'я з текстом, надлишок дістається саме йому, а не імені.
     Через це текстова колонка витягується рівно на висоту знімка */
  grid-template-rows:auto 1fr;
  column-gap:var(--colgap); row-gap:clamp(20px,2.6vh,32px);
  padding-block:clamp(10px,2vh,28px) clamp(34px,6vh,84px);
}
/* вісім колонок, а не сім: українське «Русанівський» довше за
   «Rusanivsky» рівно настільки, що в семи вставало впритул до межі —
   а рядок не переноситься */
.name{
  grid-column:1/span 7; grid-row:1;
  /* трохи жирніше за 400: на такому кеглі тонкий накреслення читалося як
     недонабране, а 500 лишає ім'я легким і водночас дає йому вагу */
  font-family:var(--font); font-stretch:var(--display-stretch);
  font-size:var(--fs-name); font-weight:600;
  letter-spacing:-.045em; line-height:.94;
}
.name span{display:block; white-space:nowrap}
/* флекс-стовпчик, а не потік: .act іде на margin-top:auto й падає на
   самий низ колонки, тобто на нижню межу портрета. Верх імені і низ
   кнопки стають двома горизонталями, між якими затиснутий знімок —
   доти він висів у куті, ні до чого не прив'язаний */
/* текст починається з другої колонки, а ім'я лишається на першій — той
   самий уступ, що й у переліку напрямків нижче, де номер стоїть у першій
   колонці, а назва починається з другої. Перша колонка стає полем, яке
   проходить крізь усю сторінку.
   flex-end садить абзац на нижню межу колонки: колонка розтягнута на
   висоту портрета (другий ряд сітки — 1fr), тож остання лінія тексту
   стає врівень з нижнім краєм знімка */
.hero-copy{
  grid-column:1/span 7; grid-row:2; padding-left:var(--col2);
  display:flex; flex-direction:column; justify-content:flex-end; min-width:0;
}
/* лід стоїть у восьми колонках, а не в чотирьох, тож без обмеження міри
   рядок ішов би на 880px. 50ch тримає його в половині колонки — це та
   сама ширина, на якій читається абзац у книжці. Кегль трохи більший за
   попередній: тут це єдиний суцільний текст першого екрана */
.lede{
  margin:0; max-width:50ch;
  font-size:var(--fs-text); line-height:1.5; text-wrap:pretty;
}

@supports (width:round(1px,1px)){
  :root{
    --meta-pad:round(clamp(4px,.8vh,10px),1px);
    --meta-pad-top:round(clamp(16px,3vw,24px),1px);
    --meta-pad-bottom:round(clamp(12px,3.75vw,18px),1px);
  }
}
/* ── напрямки: рядки того самого крою, що й перелік соцмереж ───── */
.work{padding-block:0 clamp(32px,5.5vh,75px)}
/* підпис розділу стоїть у першій колонці — тій, яку лінійка звільнила, —
   і вирівняний по її правому краю: права межа напису впирається в те саме
   місце, від якого за міжколонником починається лінійка.
   Нульова висота, а не від'ємне поле: лінійка сусіднього блоку лягає рівно
   на верхню межу тексту, і якщо довший український підпис переноситься,
   зайвий рядок звисає в порожню колонку замість зсувати все під собою.
   Флекс, а не text-align: коли підпис ширший за колонку (українські довші
   за англійські), text-align лишає його на лівій межі й пускає через
   лінійку — заміряно: «ЗАМОВЛЕННЯ» в коробці на 60px малюється від 200 до
   288. justify-content:flex-end тримає праву межу на місці й вирощує напис
   ліворуч, у поле сторінки, де для нього є місце */
.work h2,.clients h2{
  font-size:var(--fs-label); line-height:1; height:0;
  display:flex; justify-content:flex-end; align-items:flex-start;
  text-align:right; padding-right:calc(100% - var(--col1));
  position:relative; z-index:1;
}
/* рядки живуть на тій самій 12-колонковій сітці, що й решта сторінки:
   кожен .spec підхоплює її треки через subgrid, тож номери, назви й
   переліки в усіх рядках стоять на спільних вертикалях. Раніше кожен
   рядок був окремою сіткою з auto-колонками — праві краї збігались, а
   ліві розповзались за довжиною слів */
.specs{
  display:grid; grid-template-columns:repeat(12,1fr);
  column-gap:var(--colgap);
  list-style:none; padding:0; margin:0;
}
.spec{
  display:grid; grid-template-columns:subgrid; grid-column:1/-1;
  align-items:baseline; padding-block:var(--rule-gap);
  min-height:64px; position:relative;
}
/* Номер стоїть у першому треку з полем до початку лінійки. Оскільки
   repeat(12,1fr) має мінімум за вмістом, це розширює перший трек так, щоб
   номер залишався праворуч від лінійки на будь-якій ширині. */
.spec .no{grid-column:1; margin-left:var(--col2); text-align:right}
/* назва вирівняна по правому краю своєї коробки, тож положення задає
   тільки права межа діапазону: кінець шостої колонки. Ліва межа лише
   каже, де почнеться перенос. Коробка починається з третьої колонки, а
   не з другої: друга віддана номеру, і назва, що зайшла б у неї, ставала б
   у сітці на рядок нижче за нього — авторозміщення не кладе два елементи
   в одну клітинку. Перелік — на 8–11, перша колонка лишається наскрізним
   полем сторінки */
.spec h3{grid-column:3/7}
.spec ul{grid-column:8/span 4}
/* лінійка стоїть на верхній межі кожного рядка, а не під ним: так під
   останнім рядком її немає сама собою — доти це доводилось окремо
   скасовувати, а першому рядку дописувати border-top. Ліва межа — початок
   другої колонки: перша лишається наскрізним полем, у якому стоїть підпис
   розділу */
.spec::before{
  content:""; position:absolute; left:var(--col2); right:0; top:0;
  height:var(--rule); background:var(--divider);
}
/* лінійка ховера — окремим шаром поверх розділювача, тож малює його повну
   товщину, а не залишок під ним. Стоїть там само, де розділювач: на верхній
   межі рядка і від тієї самої вертикалі */
.spec::after{
  content:""; position:absolute; left:var(--col2); right:0; top:0;
  height:var(--pen); background:var(--pencil);
  transform:scaleX(0); transform-origin:left;
  transition:transform 620ms var(--ease); will-change:transform;
}
/* фіксована ширина номера: «01» вужче за «02»..«04», а на вузькому екрані
   номер стоїть в auto-колонці, тож перший рядок з'їжджав на 2px вліво.
   tnum у цій гарнітурі не допомагає, тому ширина задана явно */
.spec .no{
  font-size:var(--number-size); letter-spacing:-.02em; font-weight:600; color:var(--mute);
  min-width:3ch; line-height:round(1.55em,1px);
}
/* той самий набір, що й назви в переліку соцмереж — без капітелі.
   Вирівняні по правому краю своєї коробки, тож упираються в спільну
   вертикаль замість розповзатися ліворуч за довжиною слова.
   Падінга під стрілку тут немає: вона й так стоїть поза потоком, на
   left:100%, тож на ховері рядок не смикається без нього, а з ним текст
   відступав від своєї вертикалі на .9em — тобто на 54px при 60 кеглі */
.spec h3{
  margin:0;
  font-family:var(--font); font-stretch:var(--display-stretch);
  font-size:var(--fs-title); font-weight:600;
  letter-spacing:-.035em; line-height:1.02;
  color:var(--ink);
  text-align:right;
}
.spec .sect{position:relative; display:inline-block; transition:transform 380ms var(--ease),color 260ms var(--ease); transform-origin:left}
/* Вулична фотографія завжди має два рядки. Окремі текстові вузли зберігають
   мовний білд і дають обом рядкам одну ліву вертикаль — без висячого відступу
   першого коротшого слова. */
.spec.under .sect{text-align:left}
.spec.under .sect > span{display:block}
@media (min-width:641px){
  .spec.under .sect{text-align:right}
}
/* стрілка вниз-праворуч: веде всередину сайту. left:100% рахувався від
   коробки .sect, а не від кінця слова — коли заголовок переносився на
   два рядки, коробка розтягувалась на всю доступну ширину (так працює
   auto-width переносного inline-block), і стрілка опинялась далеко
   праворуч від «photography», у порожньому місці. inline-block у
   звичайному потоці, як на .cat[target], прибивається до останньої
   літери, а не до краю коробки, хай там яка вона завширшки */
.spec .sect::after{
  content:"↘"; display:inline-block; margin-left:.16em;
  font-size:.36em; vertical-align:.95em; line-height:1; color:var(--ink);
  opacity:0; transform:translate(-.3em,-.3em);
  transition:opacity 300ms var(--ease), transform 300ms var(--ease);
}
/* розділ, що живе на сторонньому сайті, показує звичну стрілку назовні */
.spec .sect[target]::after{content:"↗"; transform:translate(-.3em,.3em)}
/* У Street photography назва навмисно розбита на два рядки. На телефоні
   стрілка належить другому слову, а на широкому екрані — першому: в обох
   випадках вона лишається одразу після останньої літери свого рядка. */
.spec.under .sect::after{content:none}
.spec.under .sect > span:last-child{position:relative;width:max-content;max-width:100%}
.spec.under .sect > span:last-child::after{
  content:"↗"; position:absolute; left:100%; top:.35em; margin-left:.16em;
  font-size:.36em; line-height:1; color:var(--ink);
  opacity:0; transform:translate(-.3em,.3em);
  transition:opacity 300ms var(--ease), transform 300ms var(--ease);
}
@media (min-width:641px){
  .spec.under .sect{width:100%}
  .spec.under .sect > span:first-child,
  .spec.under .sect > span:last-child{
    width:100%;max-width:none;text-align:right
  }
  .spec.under .sect > span:first-child{position:relative}
  .spec.under .sect > span:first-child::after{
    content:"↗"; position:absolute; left:100%; top:.35em; margin-left:.16em;
    font-size:.36em; line-height:1; color:var(--ink);
    opacity:0; transform:translate(-.3em,.3em);
    transition:opacity 300ms var(--ease), transform 300ms var(--ease);
  }
  .spec.under .sect > span:last-child::after{content:none}
}
/* Перші три напрямки ведуть усередину сайту, але окремого маркера їм не
   потрібно: назва й так працює як самостійний пункт навігації. */
.work .spec:not(.under) .sect::after{content:none}
/* перелік іде на два свої рядки нижче, ніж стояв доти. align-self:start
   виводить його з базового вирівнювання рядка — інакше саме він задавав
   би базову лінію і тягнув номер із назвою вниз за собою */
.spec ul{
  list-style:none; padding:0; align-self:start;
  font-size:var(--fs-text); line-height:1.4;
  margin:calc(var(--fs-title) * .55 + 2.8em) 0 0;
  display:grid; gap:6px; justify-items:start;
}
.spec li{
  font-size:inherit; line-height:inherit; color:var(--ink);
  letter-spacing:.01em; text-wrap:pretty;
}
.spec.under li{color:var(--mute)}
.spec .it{
  color:inherit; text-decoration:none;
  display:inline; box-decoration-break:clone; -webkit-box-decoration-break:clone;
  /* поле піднімає ціль дотику з 18 до 26px; .it — рядковий, тож висоту
     рядка це не змінює. Олівцеву лінію зсуваємо назад на ті самі 4px,
     інакше вона поїхала б униз разом із нижньою межею поля */
  padding-block:4px;
  background-image:linear-gradient(var(--pencil),var(--pencil));
  background-repeat:no-repeat; background-position:0 calc(100% - 4px);
  background-size:0% var(--pen);
  transition:background-size 380ms var(--ease), color 240ms var(--ease);
}
/* у категорій стрілки більше немає — лишилась тільки там, де посилання
   справді виводить із сайту */
.spec a.it[target]::after{
  content:"↗"; display:inline-block; margin-left:.35em; font-size:.9em; color:var(--ink);
  opacity:0; transform:translate(-3px,3px);
  transition:opacity 300ms var(--ease), transform 300ms var(--ease);
}
@media (hover:hover){
  /* наведення будь-де в рядку — і на розділ, і на категорію — фарбує
     назву розділу та зсуває її вправо */
  .spec:hover .sect{color:var(--pencil);transform:translateX(clamp(8px,1.4vw,22px))}
  .spec:hover::after{transform:scaleX(1)}
  /* Відокремлений нижній рядок .under зберігає власну стрілку назовні. */
  .work .spec.under .sect:hover > span:last-child::after{opacity:1; transform:none}
  .work .spec.under .sect:hover > span:first-child::after{opacity:1; transform:none}
  .spec .it:hover{color:var(--accent)}
  .spec a.it[target]:hover::after{opacity:1; transform:none}
}
.spec:active .sect{color:var(--pencil);transform:translateX(10px)}
.spec:active::after{transform:scaleX(1)}
.spec .it:active{color:var(--accent)}
.spec a.it:focus-visible{outline:2px solid var(--accent); outline-offset:3px}
/* в останньому рядку категорія одна, і в правій колонці вона висіла
   самотньою стрічкою навпроти порожнечі. Тут вона стоїть під назвою й
   правим краєм по тій самій вертикалі — читається як продовження назви,
   а не як окремий пункт. Посилання на ній немає: воно вже на самій назві */
/* підпис стоїть рівно в тій самій коробці, що й назва над ним: ті самі
   треки і те саме від'ємне поле, тож обидва праві краї лягають на одну
   вертикаль. Доти коробка стояла на треках 2–8, тобто на цілу колонку
   правіше за назву, а .9em падінга той розрив лише приховували: заміряно
   — на 1440 підпис виступав на 56px, на 1100 на 38, на 700 на 14, і
   найпомітніше це ставало саме тоді, коли довга назва переносилась.
   Просвіт рахується від кегля назви, як і зсув переліків у сусідніх
   рядках, — тоді він тримається однаковим на всіх ширинах */
.spec.under ul{
  grid-column:3/7; grid-row:2;
  margin:calc(var(--fs-title) * .55) 0 0;
  justify-items:end; text-align:right;
}
/* поле на 120px варте себе, поки сторінка широка. Від 960 воно з'їдає
   чверть рядка — там підпис лягає вертикально, а колонка сходить до
   20px: те саме, що доти вмикалось аж на телефоні */
@media (max-width:960px){
  /* підпис стає вертикальним: горизонтально він просить під себе колонку
     на 120px, а вузько це чверть рядка. Повернутий, він займає ширину
     одного рядка, а не всього напису, — решта віддана вмісту, і трохи
     повітря лишається між ним і лінійкою.
     Коробка лишається нульової висоти й на своєму місці: обертання не
     чіпає верстки, тож лінійка й далі стоїть на межі напису — тільки
     тепер це його ліва межа, а не верхня. rotate(90deg) translateY(-1em)
     повертає за годинниковою довкола лівого верхнього кута і піднімає на
     висоту рядка, щоб напис пішов униз від тієї самої точки */
  .work h2,.clients h2{
    justify-content:flex-start; padding-right:0;
    /* rotate лишається окремою властивістю, незалежною від hover-руху.
       Центр обертання .5em .5em: за годинниковою довкола нього рядок
       лягає рівно в колонку завширшки з себе, від тієї самої верхньої
       межі, на якій стоїть лінійка */
    transform-origin:.5em .5em; rotate:90deg;
    /* width:max-content — інакше коробка лишається на всю ширину верстки,
       а після повороту ця ширина стає висотою: підпис підвала тягнув за
       собою 358px, з них 113 звисали нижче за сам підвал і додавалися до
       висоти сторінки порожнечею. Тепер коробка завширшки з напис */
    width:max-content;
  }
}
/* На десктопі номер і назва сідають на спільну базову лінію — так само,
   як у правильному переліку на сторінці «Контакти». Розмір і міжряддя
   номера задані явно: без цього він успадковував більший кегль суцільного
   тексту й візуально піднімався відносно букв. */
@media (min-width:641px){
  .spec{align-items:baseline}
  .spec .no{
    font-size:var(--number-size);font-weight:600;letter-spacing:-.02em;
    line-height:round(1.55em,1px);color:var(--mute)
  }
}
/* вузько назва розділу й перелік знову стоять один під одним, але всі
   переліки починаються з однієї лівої вертикалі */
@media (max-width:640px){
  /* дванадцяти колонок тут уже немає, але перша лишається для номера,
     а назва й категорії живуть у спільній другій колонці */
  /* На мобільному ім'я — головний якір першого екрана: трохи більше й
     важче за назви напрямків, щоб ієрархія читалася одразу. */
  .name{font-size:clamp(48px,11vw,72px);font-weight:700}
  .specs{display:block; margin-left:var(--col2)}
  .spec::before,.spec::after{left:0}
  .spec{
    display:grid; grid-template-columns:minmax(3ch,auto) minmax(0,1fr);
    /* Для однорядкових назв номер і заголовок мають спільну базову лінію. */
    column-gap:clamp(14px,2.4vw,36px); row-gap:24px; align-items:baseline;
  }
  /* У четвертого пункту назва може стати дворядковою: номер лишається
     напроти першого рядка, а не сідає на базову лінію останнього. */
  .spec.under{align-items:start}
  /* У меншого номера своя метрика шрифту, тому для дворядкового заголовка
     підтягуємо його видиму базову лінію до першого рядка, як у 01–03. */
  .spec.under .no{margin-top:.45em}
  .spec .no{grid-column:1; grid-row:1; margin-left:0; text-align:left}
  /* у вузькій сітці колонок-треків немає, тож і добирати міжколонник
     від'ємним полем нема від чого */
  /* min-width:0 — щоб трек 1fr не роздувався до найдовшого слова назви:
     на 320px «фотографія» розпирала рядок і виносила сторінку за край */
  .spec h3,.spec ul{min-width:0}
  .spec h3{grid-column:2; grid-row:1; margin-right:0; text-align:left}
  .spec ul{
    grid-column:2; grid-row:2; margin:0; align-self:auto;
    justify-items:start; text-align:left;
  }
  .spec.under ul{
    grid-column:2; grid-row:2; margin:0;
    justify-items:start; text-align:left;
  }
  /* Довга назва верстки — єдина в списку, що не влазить у рядок телефона.
     Доти її тримав row-gap:0: список ставав щільнішим за сусідні, аби
     відіграти висоту переносу. Гірше — невидима стрілка ::after (вона
     inline-block і займає місце навіть при opacity:0) на 402 і 414px
     їхала на другий рядок сама, і під пунктом зяяв порожній рядок.
     Тепер рядок свідомо розбитий на два: max-width змушує перенос на
     будь-якій мобільній ширині, balance ділить його рівно, і стрілці
     завжди є місце біля останнього слова. Просвіт повертається до 6px —
     того самого, що в списках відео й фото. */
  .spec.design-spec ul{row-gap:6px}
  .spec.design-spec li{max-width:24ch;text-wrap:balance}
  /* На телефоні назви напрямків трохи компактніші, але лишаються
     головним акцентом списку; вага 700 тримає їх виразними. */
  .spec h3{font-size:clamp(23.2px,6.16vw,32px);font-weight:700}
}
/* На дуже вузьких телефонах ім’я й великі назви зменшуються разом:
   пропорція між ними лишається тією самою, але довгі українські слова
   отримують ще трохи повітря для переносу. */
@media (max-width:360px){
  .name{font-size:clamp(40px,10.5vw,52px)}
  .spec h3{font-size:clamp(20px,5.44vw,25.6px)}
}
/* портрет на трьох правих колонках: правою межею він і далі стоїть на
   краю верстки, як логотипи клієнтів і рядок підвалу, а ліва з'їхала з
   9-ї лінії на 10-ту. З чотирьох колонок вибирати не було з чого — при
   трьох або права межа відходить від краю сторінки на цілу колонку, або
   ліва сходить зі спільної вертикалі; розрив зі спільною вертикаллю
   помітний менше, ніж діра завширшки 115px біля правого поля.
   Він спанить обидва рядки героя: його висота задає висоту текстової
   колонки ліворуч. align-self:start лишає йому пропорцію 4:5 */
.figwrap{grid-column:9/span 4; grid-row:1/span 2; align-self:start}
.figwrap figure{width:100%}
.figwrap .shot picture{width:100%; height:auto}
/* На десктопі ім'я має невеликий оптичний вихід ліворуч.
   Позиційний зсув не змінює ширини треків і не зачіпає мобільний стек. */
@media (min-width:961px){
  .name{position:relative; left:-8px}
}
figure{margin:0; position:relative; z-index:1}
.shot{
  position:relative; display:flex; background:var(--surface);
  /* тінь лише знизу: великий розмив і від'ємний spread тримають її
     тихою й компактною, а не плямою під усім кадром */
  box-shadow:0 20px 34px -18px color-mix(in srgb,#000 18%,transparent);
}
.shot picture{
  display:block; position:relative; flex:1 1 auto; aspect-ratio:4/5;
  overflow:hidden;
}
.shot img{width:100%; height:100%; object-fit:cover}
/* середні екрани: ім'я на 7,4vw ще тримається у восьми колонках, але
   портрет у чотирьох стає завузьким, щоб сюжет читався. Віддаємо йому
   п'яту колонку за рахунок текстової — межа з'їжджає з 9-ї лінії на 8-му
   тільки тут, де переліків категорій поряд усе одно немає */
@media (max-width:1100px){
  .name{grid-column:1/span 7}
  .hero-copy{grid-column:1/span 7}
  .figwrap{grid-column:9/span 4}
}
/* вузько колонки поряд не стоять: ім'я, портрет, текст і дія йдуть одне
   під одним. Портрет другим — обличчя одразу під іменем, — але кнопка
   лишається над згином, бо кадр тут ширший і нижчий за вертикальний */
@media (max-width:960px){
  .hero{grid-template-rows:none; row-gap:clamp(22px,3.4vh,34px)}
  .name,.hero-copy,.figwrap{grid-column:1/-1; grid-row:auto}
  /* у стосі абзац читається на всю ширину: тримати під нього поле в
     сімдесят із гаком пікселів на телефоні дорожче, ніж воно варте */
  .hero-copy{padding-left:0}
  /* спершу текст, потім знімок: клієнт читає, хто це і що робить, і аж
     тоді бачить обличчя — на вузькому екрані фото між іменем і текстом
     відсувало сам текст на другий екран */
  .name{order:1}
  .hero-copy{order:2}
  .figwrap{order:3; width:min(100%,420px); max-width:none; justify-self:center}
  .figwrap figure{width:100%}
  .figwrap .shot picture{height:auto; width:100%}
  /* горизонталь, а не вертикаль: у стосі кадр 3:4 виростав до 560px
     заввишки і сам виштовхував кнопку за згин планшета. Сюжет знімка
     по центру, тож object-fit:cover лишає в кадрі і обличчя, і камеру */
  .shot picture{aspect-ratio:5/4}
  .lede{max-width:38ch}
}

/* ── клієнти ─────────────────────────────────────────────── */
.clients{
  /* поле згори невелике: свій відступ під переліком уже віддав .work,
     і два повних просвіти поспіль розривали б сторінку надвоє */
  padding-block:clamp(12px,1.8vh,26px) clamp(34px,6vh,84px);
  /* зріст, від якого рахуються всі чотири марки */
  /* На середніх ширинах 1,7vw майже весь час впирається в 13px — марки
     стають візуально слабшими саме на планшеті. Піднімаємо нижню межу й
     лишаємо той самий максимум: на широкому десктопі розмір не зростає. */
  --lg:clamp(18px,2.1vw,25px);
}
/* марки стоять поряд, одна за одною, і всім рядом притиснуті до правого
   краю верстки — так само, як перелік категорій у рядках вище і перелік
   соцмереж у підвалі. Розтягнутий на всю ширину ряд робив би між ними
   поля по двісті пікселів, і четвірка переставала б читатися як група */
.logos{
  /* лінійка над марками — та сама, що відкриває перелік напрямків, і
     стоїть так само: по верхній межі підпису і від початку другої колонки.
     Не border-top, бо його ліву межу не зсунути; absolute виводить псевдо
     з флекс-потоку, тож марок він не чіпає */
  position:relative;
  /* марки стоять рівно в тій коробці, яку окреслює лінійка над ними: доти
     ряд ішов на всю ширину верстки і на вузькому екрані заходив у першу
     колонку, під підпис. Тепер він починається там, де починається лінійка,
     а що не вміщається — переноситься другим рядом */
  list-style:none; margin:0 0 0 var(--col2); padding:var(--rule-gap) 0 0;
  display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-start;
  column-gap:clamp(26px,3.6vw,54px); row-gap:clamp(24px,4vw,40px);
}
.logos::before{
  content:""; position:absolute; left:0; right:0; top:0;
  height:var(--rule); background:var(--divider);
}
/* марки приходять різними форматами — від квадратної монограми до напису
   в два рядки. Спільна висота зробила б монограму вдвічі важчою за інших,
   спільна ширина — навпаки; тож зріст кожної заданий окремо, і множник
   вирівнює саме оптичну вагу. Ширина з нього ж і пропорції самої марки */
/* марка — посилання на сайт клієнта; приглушена, доки на неї не навели,
   як і назви категорій у рядках вище */
.logos a{display:block; color:inherit}
@media (hover:hover){
.logos a:hover .lg{color:var(--ink)}
}
.logos a:active .lg{color:var(--ink)}
.logos a:focus-visible{outline:2px solid var(--accent); outline-offset:6px}
/* Логотип малюється маскою, а не картинкою: колір дає currentColor, з
   файлу читається лише альфа. Тому три растрові марки лежать у WebP —
   у ньому альфа стискається без утрат, і 77 КБ трьох PNG стали 43 КБ
   при тій самій роздільності (scripts/make-client-masks.mjs). */
.lg{
  display:block; position:relative; background:currentColor;
  color:color-mix(in srgb,var(--ink) 70%,transparent);
  transition:color 280ms var(--ease);
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-image:var(--src); mask-image:var(--src);
}
.lg.kmbs{--src:url(/img/clients/kmbs.svg); height:var(--lg); width:calc(var(--lg) * 3.09)}
.lg.naukma{--src:url(/img/clients/naukma.webp); height:calc(var(--lg) * 1.38); width:calc(var(--lg) * 1.46)}
.lg.defenders{--src:url(/img/clients/defenders-ukma.webp); height:calc(var(--lg) * 1.64); width:calc(var(--lg) * 4.79)}
.lg.kooperativ{--src:url(/img/clients/kooperativ.svg); height:calc(var(--lg) * .91); width:calc(var(--lg) * 4.93)}
.lg.yd{--src:url(/img/clients/yd.svg); height:calc(var(--lg) * 1.2642); width:calc(var(--lg) * 1.9012)}
.lg.tsyronian{--src:url(/img/clients/tsyronian.svg); height:calc(var(--lg) * 1.1); width:calc(var(--lg) * 3.8)}
.lg.shylero{--src:url(/img/clients/shylero.webp); height:calc(var(--lg) * 1.29); width:calc(var(--lg) * 4.98)}
/* на телефоні марки лишаються рядом, а не сіткою два на два: --lg тут не
   1,7vw (це давало б 13px — марки читалися як дрібний шум під заголовком),
   а 5,6vw, і міжмарковий просвіт стискається їм під розмір. На типових
   ширинах від 320 до 480 четвірка так стає в один рядок; коли не стає,
   flex-wrap переносить останню марку, і це прийнятніше за дрібний кегль */
@media (max-width:480px){
  .clients{--lg:clamp(18px,5.6vw,24px)}
  .logos{column-gap:clamp(12px,4vw,20px); row-gap:clamp(18px,5vw,26px)}
}
/* ── підвал сайту ─────────────────────────────────────────── */
/* підвал стоїть на тому самому тлі, що й уся сторінка, і відділений
   такою ж волосяною лінійкою, як кожен розділ вище. Доти він був
   темною плашкою, і сенс у ній був лише в світлій темі: на папері вона
   давала контраст 11,2:1 і читалася як подія, а на темному тлі — 1,41:1,
   тобто ледь помітну пляму замість блоку.
   Прийом працював наполовину, а сторінка з волосяних лінійок і
   повітря обходиться без суцільної заливки */
.site-foot{
  color:var(--ink);
  --uline:2px;
  /* поле підвала винесено у змінну: коли підпис вертикальний, лінійку
     доводиться малювати не від нього, а від самої плашки — і треба знати,
     на якій висоті в ній стоїть перший рядок */
  --foot-pad:clamp(22px,3.85vh,52px);
}
/* контакти починаються з другої колонки — від тієї самої вертикалі, від
   якої йдуть лінійки й номери на всій сторінці. Доти вони стояли з
   третьої й були єдиним блоком сайту зі своїм уступом. Не grid-column:2,
   а поле в --col2: трек сітки й наскрізне поле сторінки — різні міри,
   відколи колонка тримає під собою підпис */
.foot-in .say{grid-column:1/-1; margin-left:var(--col2)}
.foot-in .say,.foot-in .k,.foot-bar > .cols{min-width:0}
/* Цілі дотику: контакти підвалу давали 22px, марки клієнтів 20px при
   нормі 24px. Поле росте, від’ємне зовнішнє поле повертає потік. */
.logos li > a{padding-block:3px;margin-block:-3px;display:inline-block}
.site-foot .lines > a::after{
  content:"↗"; display:inline-block; margin-left:.12em; font-size:.34em;
  vertical-align:.95em; color:var(--ink); opacity:0; transform:translate(-.25em,.25em);
  transition:opacity 320ms var(--ease), transform 320ms var(--ease);
}
.site-foot .foot-meta{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:baseline;gap:clamp(12px,1.8vw,26px);padding-left:var(--chrome-pad);padding-right:var(--chrome-pad);color:var(--mute)}
/* вузько сітка підвалу згортається в одну колонку, а контакти відходять
   за першу — за ту саму вертикаль, від якої йде лінійка над ними */
@media (max-width:640px){
  /* вертикальні поля вузько рахуються від ширини екрана, а не від висоти.
     Усі ці просвіти стояли на vh, і на телефоні 844px заввишки вони
     виходили такі самі, як на десктопі, — але екран удвічі вужчий, тож
     відносно рядка та сама порожнеча читалась удвічі більшою. Заміряно на
     390x844: під переліком 46px, під марками 50, поля підвала 32+32,
     нижній рядок 22+28. Разом із хвостом від повороту це давало 617px
     від останнього рядка до кінця сторінки при 223px самого вмісту */
  .work{padding-bottom:clamp(48px,9vw,64px)}
  .clients{padding-block:10px clamp(24px,6vw,32px)}
  .site-foot{--foot-pad:clamp(18px,5vw,24px)}
  .foot-bar{--footer-row-gap:clamp(12px,1.8vw,26px);grid-template-columns:1fr;padding-block:calc(var(--meta-pad) + 8px) clamp(18px,4.5vw,24px)}
  .foot-bar > .cols{padding:0}
  .foot-bar > .cols{margin-left:0}
  .site-foot .foot-meta{width:100%;flex-direction:row;flex-wrap:nowrap;align-items:baseline;justify-content:flex-start;gap:var(--footer-row-gap);padding:0;min-width:0;text-align:left;white-space:nowrap}
  .site-foot .foot-meta .tiny{white-space:nowrap;min-width:0}
}
.rev [data-rev].is-in{opacity:1; translate:none; transition:opacity 260ms var(--ease), translate 300ms var(--ease)}
.rev [data-rev].is-in{transition-delay:var(--d,0ms)}
