/* ══════════════════════════════════════════════════════════════════════════════
   vendor/ks-cabinet.css — СПІЛЬНИЙ CSS ЧОТИРЬОХ КАБІНЕТІВ (BRIEF-63G §4).

   Тут лежать правила, які були БАЙТ-У-БАЙТ однакові в інлайн-блоках
   /driver · /client · /dispatcher · /ceo. Критерій — розбір CSSOM тим самим
   рушієм браузера (CSSStyleSheet.replaceSync + обхід cssRules), а НЕ порівняння
   рядків тексту: текстове порівняння завищує спільну частину більш ніж удвічі,
   бо рахує форматування.

   🔴 ПРИЧИНА ВИНОСУ — НЕ БАЙТИ, А РОЗХОДЖЕННЯ. Чотири копії одного правила
   розходяться мовчки: саме так у продукті вже жили різні товщини обведення в
   кабінетах і на лендінгу, і саме так резерв підрядка з'явився в коді, не
   з'явившись у ратифікованому макеті.

   🔴 ПІДКЛЮЧАЄТЬСЯ ПЕРЕД інлайн-блоком кабінету, одразу після ks-tokens.css.
   Отже інлайн лишається ОСТАННІМ і виграє нічиї рівної специфічності — рівно як
   до виносу. 41 правило сюди НЕ переїхало: для них ко-збіг на ВІДРЕНДЕРЕНОМУ DOM
   довів справжню нічию з правилом, що стояло ПЕРЕД ними, — у тому самому
   кабінеті або в іншому, бо порядок спільних правил між кабінетами теж різний.
   🔴 Набір рахувався як НЕРУХОМА ТОЧКА, а не одним проходом: правило, лишене
   інлайном, саме створює нову нічию з тим, що поїхало. Перелік і причина по
   кожному — у звіті хвилі REPORT-63G.md.

   🔴 КОМЕНТАРІ ПЕРЕЇХАЛИ РАЗОМ ІЗ ПРАВИЛАМИ, і лише там, де переїхав ВЕСЬ
   прогін правил під коментарем. Коментар, що лишився описувати вилучене
   правило, — це те саме, що коментар, який бреше про код.

   ⚠ Файл ГЕНЕРОВАНИЙ виносом. Правити його руками не треба: правка має піти в
   кабінет. Ім'я контентно-адресоване — після зміни виконати `make vendor-hash`.
   ══════════════════════════════════════════════════════════════════════════════ */
/* 🔴 BRIEF-13 §3.3 · ЛОКАЛЬНОГО :root БІЛЬШЕ НЕМАЄ. Усі 87 визначень переїхали
     у /vendor/ks-tokens.9fcbb5962b.css — один файл на п'ять поверхонь. Тримає C51. */
*{margin:0;padding:0;box-sizing:border-box}
/* 🔴 §4 · БАЗОВИЙ КЕГЛЬ — ТОКЕН, А НЕ БРАУЗЕРНИЙ ДЕФОЛТ. Вимір власника: html і
     body стояли на 16px, якого в драбині §6.2 НЕМАЄ ВЗАГАЛІ; від них через em/%
     народжувались 8.64 · 7.92 · 14.4 · 28.8 · 9.36 — тобто півпіксельні кеглі, які
     ратифіковано скасовано 23.08. Лендінг переведено попередньою хвилею; кабінети
     не чіпали, і всі чотири лишались на дефолті. --fs-6 = 15px. */
html{font-size:var(--fs-6)}
body{background:var(--bg);color:var(--text);font-family:'Arimo','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:var(--fs-6);min-height:100vh;-webkit-font-smoothing:antialiased}
/* R5 · background copied 1:1 from the main site (#pan-stage: hero.webp + the exact
     pan-overlay gradient + grain). Same DOM/CSS => computed background matches the homepage. */
#pan-stage{position:fixed;inset:0;z-index:var(--z-base);overflow:hidden;pointer-events:none}
#pan-img{position:absolute;left:50%;top:0;width:auto;height:220vh;min-width:100%;object-fit:cover;transform:translate(-50%,0)}
#pan-overlay{position:absolute;inset:0;background:radial-gradient(120% 90% at 50% 38%, transparent 0%, var(--hero-veil-1) 62%, var(--hero-veil-2) 100%), linear-gradient(180deg, var(--hero-veil-4) 0%, var(--hero-veil-3) 22%, var(--hero-veil-3) 70%, var(--hero-veil-5) 100%)   /* BRIEF-13 §4.1 · СЕРПАНОК ТЕЖ ІЗ ТОКЕНІВ. Проміжних сходинок затемнення драбина не має (ink живе на .82 і 1), тож п'ять довільних альф зведені до двох станів: прозоро → --surface-sunk. Вигляд трохи темніший по краях. */}
#pan-grain{position:absolute;inset:0;opacity:0.05;mix-blend-mode:overlay;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E")}
::selection{background:var(--accent-line);color:var(--text)}
/* T-4.2 · a11y — global keyboard focus ring (main-site canon: 2px orange outline, 2px offset).
     Only shows for keyboard/AT focus (:focus-visible), so mouse clicks are unaffected. */
:focus-visible{outline:2px solid var(--accent) !important;outline-offset:2px !important}
.wrap{position:relative;z-index:var(--z-raised);max-width:var(--container-wide);margin:0 auto;padding:var(--pad-24) var(--pad-24) var(--pad-60)}
h1,h2,.brand{font-family:'Arimo',sans-serif}
select option{background:var(--panel);color:var(--text)}
/* ══ §2.5 · G + J2 — РІВНІ РОЗРЯДИ І ПОДАЧА ГРОШЕЙ ═══════════════════════
     Розмітку дає KSFmt.digits() у vendor/ks-cabinet.js (одна копія на продукт).
     Ширини — токенами в ks-tokens.css: тут лише те, ЯК вони застосовуються.
     🔴 Копійки меншим кеглем і --muted, але БЕЗ підняття над базовою лінією:
     варіант із підняттям власник відхилив (J2, 29.08.2026). vertical-align тут
     навмисно не чіпається — інакше цифри поїдуть угору. */
.dig{display:inline-block;width:var(--dig-w);text-align:center}
.sep{display:inline-block;width:var(--sep-w);text-align:center}
.cents{font-size:var(--cents-size);color:var(--muted)}
/* §4 · КОНТЕКСТИ КОПІЙОК — усі три значення з драбини §6.2, не похідні.
     Дефолт --fs-2 (10px) обслуговує табличний рядок (11–13px); картка-показник і
     підсумок формули називають свої, бо під 20px і 40px десятипіксельні копійки
     загубились би. Читач один — .cents; тут лише значення. */
/* ⚠ BRIEF-DEMO-02 §2.1 · `.rs-stat b` — ще один контекст, де число велике, а
   дефолт `--cents-size` (--fs-2, 10px) обслуговує ТАБЛИЧНИЙ рядок: під числом
   18–24px копійки в ньому губляться. Перелік контекстів один на продукт. */
.kpi .v,.p-kpi .v,.calc-res .v,.rs-stat b{--cents-size:var(--fs-5)}
.ks-sum3 > .kpi.net .v{--cents-size:var(--fs-7)}
/* ══ §2.8 · F — МАТЕРІАЛ ПОВЕРХНІ ══════════════════════════════════════════
     1px світлого блиску по верхній кромці картки й блоку графіка: поверхня читається
     як матеріал, що ловить світло згори, а не як пляма іншого відтінку.
     🔴 Через ::before, а не через <span class="edge"> з макета: елемент довелось би
     дописати в КОЖНЕ місце рендеру картки (їх десятки на чотири кабінети), і кожне
     стало б місцем, де його колись забудуть. Вигляд той самий, носій — один.
     position:relative ставимо тут же: без нього ::before ляже не по кромці. */
.kpi,.p-kpi,.chart-block{position:relative}
.kpi::before,.p-kpi::before,.chart-block::before{
    content:'';position:absolute;inset:0 0 auto;height:1px;pointer-events:none;
    border-radius:var(--r-3) var(--r-3) 0 0;
    /* 🔴 --border, а не той самий колір, розписаний руками: rgb(var(--hue-light)/var(--a-3))
       це БУКВАЛЬНО означення --border у ks-tokens.css. C47 на це червонів у чотирьох
       кабінетах, і має рацію — розписаний токен це той самий літерал, просто довший. */
    background:linear-gradient(90deg,transparent,var(--border),transparent)}
/* Дуже слабкий акцентний серпанок під шапкою — щоб верх екрана не був чорною
     смугою. Радіальний, --accent-tint, під усім вмістом і без перехоплення кліків. */
.wrap::before{
    content:'';position:absolute;top:0;left:0;right:0;height:220px;pointer-events:none;
    z-index:var(--z-base);
    background:radial-gradient(120% 100% at 50% 0%,var(--accent-tint),transparent 70%)}
/* ══ §2.10 · L — ІДЕНТИЧНІСТЬ У ШАПЦІ ══════════════════════════════════════
     Ініціали · ім'я · рядок ролі. «Вийти» і мова переїхали ПІД цей блок, тож
     шапка читається згори вниз: хто я → що я можу зробити з сесією. */
.ks-me{display:flex;align-items:center;gap:var(--sp-2);min-width:0}
.ks-me-ava{width:32px;height:32px;flex:0 0 auto;border-radius:var(--r-round);
    display:grid;place-items:center;background:var(--accent-tint);
    border:1px solid var(--accent-border);color:var(--accent);
    font-size:var(--fs-3);font-weight:var(--fw-3);line-height:var(--lh-1)}
/* C48 · інтерліньяж із токена; центрує все одно place-items */
.ks-me-txt{display:flex;flex-direction:column;min-width:0}
.ks-me-name{font-size:var(--fs-4);font-weight:var(--fw-2);line-height:var(--lh-1);
    color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ks-me-role{font-size:var(--fs-1);letter-spacing:var(--ls-5);text-transform:uppercase;
    color:var(--dim);margin-top:var(--optical);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ks-me-actions{display:flex;align-items:center;gap:var(--sp-2)}
.header-right{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap;justify-content:flex-end}
@media(max-width:560px){
.ks-me-txt{display:none}
/* на телефоні лишаються ініціали — рядок ролі не влазить */
.header-right{gap:var(--sp-2)}
}
/* glass-card recipe — main-site canon, applied to every card */
.glass{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);box-shadow:var(--elev-2);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2)}
@media(hover:hover){
/* велика картка: rest --elev-2 */
.glass:not(.login-card):not(.error-box):hover,.chart-block:hover{
      border-color:var(--accent-line);box-shadow:var(--elev-3)}
/* 🔴 .day-summary у СПОКОЇ тіні не має взагалі (тінт + бордер, без elevation),
       тож «щабель вище» для неї — перший щабель драбини, --elev-1, а не --elev-3. */
.day-summary:hover{border-color:var(--accent-line);box-shadow:var(--elev-1)}
}
/* LOGIN — T-4.2 · presented as a modal like the main-site login: the screen dims + blurs the
     hero background (backdrop) and the card elevates + animates in with the site's smoothModalIn.
     Fix-pass B3 · scrim eased to 0.55 + blur 12px (was 0.72/8px) so the branded hero reads as a
     dimmed, translucent backdrop instead of flat black — the site's 0.72 value dims a bright page,
     but here it sat over the already-dark hero and looked opaque. Auth markup/JS is unchanged.
     (The /client cabinet is gated by a redirect and never shows this screen; rules inert but synced.) */
.login-screen{position:relative;z-index:var(--z-raised);display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;padding:var(--sp-4);background:var(--scrim);-webkit-backdrop-filter:var(--blur-1);backdrop-filter:var(--blur-1);animation:smoothBackdropIn var(--dur-3) var(--ease-out) both}
/* T-4.3 · panel = site login modal recipe: opaque dark (not glass) so the form never shows through */
.login-card{width:100%;max-width:400px;padding:var(--sp-6);background:var(--panel);border:1px solid var(--border);border-radius:var(--r-3);-webkit-backdrop-filter:var(--blur-3);backdrop-filter:var(--blur-3);box-shadow:var(--elev-3);animation:smoothModalIn var(--dur-3) var(--ease-out) both}
@media(prefers-reduced-motion:reduce){
.login-screen,.login-card{animation:none}
}
/* R2 · logo lockup copied 1:1 from the main site header (mark + KOSTKIFF / Logistics) */
.ks-logo{display:inline-flex;align-items:center;gap:var(--sp-3)}
.ks-logo-mark{position:relative;width:34px;height:34px;border-radius:var(--r-2);background:var(--surface);border:2px solid var(--accent);display:flex;align-items:center;justify-content:center;overflow:hidden;flex:0 0 auto}
.ks-logo-svg{display:block}
/* BRIEF-13 §4.1 · ЛОГОТИП — ТЕЖ ТОКЕНИ. Кольори жили презентаційними атрибутами
     SVG (stroke="#ffffff" / "#F39444"), тобто повз дизайн-систему; друкарське
     правило чіплялось за той самий атрибут. Тепер обидві риски беруть колір із
     currentColor, а він — із токена; друк перевизначає клас, а не літерал. */
.ks-logo-svg .lg-k{color:var(--text)}
.ks-logo-svg .lg-a{color:var(--accent)}
.ks-logo-words{display:flex;flex-direction:column;line-height:var(--lh-1);text-align:left}
.ks-logo-name{font-size:var(--fs-6);font-weight:var(--fw-2);letter-spacing:var(--ls-3);color:var(--text)}
.ks-logo-desc{font-size:var(--fs-1);font-weight:var(--fw-1);letter-spacing:var(--ls-4);text-transform:uppercase;color:var(--muted);margin-top:var(--sp-1)}
.brand{display:flex;justify-content:center;margin-bottom:var(--sp-2)}
.login-sub{text-align:center;color:var(--muted);font-size:var(--fs-4);margin-bottom:var(--sp-6);letter-spacing:var(--ls-7)}
.field{margin-bottom:var(--sp-3)}
.field label{display:block;font-size:var(--fs-2);font-weight:var(--fw-2);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4)}
/* T-4.3 · inputs = site login modal recipe: 12px radius (not pill), 14px text */
.field input{width:100%;height:46px;padding:0 var(--pad-16);background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);color:var(--text);font-size:var(--fs-6);font-family:inherit;outline:none;transition:border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out)}
.field input:focus{border-color:var(--accent-line);box-shadow:var(--ring)}
/* C.8 · «Око» показу пароля. Кнопка лежить ВСЕРЕДИНІ поля справа; інпут дістає правий
     padding на її ширину, щоб довгий пароль не заповзав під іконку і висота 46px не збилась.
     Ціль натискання 32×32 CSS-px (вимога — не менше 24×24), іконка 18px, колір currentColor. */
.pw-wrap{position:relative;display:block}
.pw-wrap input{padding-right:var(--pad-46)}
.pw-eye{position:absolute;top:50%;right:7px;transform:translateY(-50%);width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;margin:0;border:0;background:transparent;color:var(--text);opacity:.62;border-radius:var(--r-2);cursor:pointer;transition:opacity var(--dur-2) var(--ease-out)}
.pw-eye:hover,.pw-eye:focus-visible{opacity:1}
.pw-eye:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.pw-eye svg{width:18px;height:18px;display:block;pointer-events:none}
@media(prefers-reduced-motion:reduce){
.pw-eye{transition:none}
}
.field input::placeholder{color:var(--dim)}
/* primary button = the site's .ks-apply CTA: white by default → orange on hover with the exact site glow */
.btn{width:100%;padding:var(--pad-15);background:var(--text);color:var(--bg);border:1px solid transparent;border-radius:var(--r-pill);font-family:'Arimo',sans-serif;font-size:var(--fs-5);font-weight:var(--fw-2);cursor:pointer;transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out);margin-top:var(--sp-2);letter-spacing:var(--ls-7);box-shadow:var(--elev-1)}
@media(hover:hover){
/* §3/канон §2 · hover-правило загорнуто в @media(hover:hover): без цієї обгортки
     на тач-екрані :hover ЗАЛИШАЄТЬСЯ після зняття пальця, і натиснута кнопка
     лишалась оранжевою (доказ — smoke/adaptive-wave.mjs · W8, на pre-fix червоніє). */
.btn:hover{background:var(--accent);color:var(--on-accent);border-color:var(--accent-text);box-shadow:var(--glow)}
}
.btn:active{transform:translateY(1px)}
/* §9A.4 · вимкнена кнопка — .45, одне значення на продукт (було .55). */
.btn:disabled{opacity:.45;cursor:default;transform:none}
/* T-4.3 · login CTA = site modal recipe: orange primary (not white), lighter-orange hover + glow */
.login-card .btn{background:var(--accent);color:var(--on-accent);border-color:transparent;font-size:var(--fs-6);font-weight:var(--fw-2)}
@media(hover:hover){
/* ── BRIEF-16 §5 · КНОПКА-ДІЯ: ОДИН РЕЦЕПТ ІЗ ЛЕНДІНГОМ (DESIGN-SYSTEM.md §9A.4) ──
     Спокій уже був без свічення — тут це не міняється. Міняються дві речі:
     (1) заливка на ховері СВІТЛІШАЄ (filter:brightness), а не лишається тією самою —
         інакше єдиний сигнал ховера це тінь, і кнопка виглядає незмінною;
     (2) підйому на ховері більше немає: §9A.4 дає кнопці translateY лише в active
         (натискання), а лифт лишається карткам (§9A.5). */
.login-card .btn:hover{background:var(--accent);color:var(--on-accent);border-color:var(--accent-text);
    filter:brightness(1.08);box-shadow:var(--glow);transform:none;transition-duration:var(--dur-2)}
}
.login-card .btn:active{filter:brightness(1.08);box-shadow:var(--glow);transform:translateY(1px);transition-duration:var(--dur-1)}
.login-card .btn:focus-visible{box-shadow:var(--ring)}
.login-card .btn:disabled{opacity:.45;filter:none;box-shadow:none;transform:none}
.login-error{color:var(--neg);font-size:var(--fs-4);text-align:center;margin-top:var(--sp-3);min-height:18px}
/* BRIEF-RESULTS-01 §5.3 · рядок заявки під кнопкою «Увійти». Лежить у vendor, бо
   екран входу однаковий у всіх чотирьох кабінетах: чотири копії цього правила
   розійшлись би на першій же правці. Лише токени, жодних літералів кольору. */
.login-apply{margin-top:var(--sp-4);text-align:center;font-size:var(--fs-4);color:var(--muted);line-height:var(--lh-3)}
.login-apply a{color:var(--accent);text-decoration:none;white-space:nowrap}
.login-apply a:hover{text-decoration:underline}
/* T-19 V-05 · ПРАВИЛО МЕРТВЕ — лишено як надгробок, щоб його не «відновили».
     Хедер живе всередині .ks-sticky-top, а там `.ks-sticky-top .header{display:contents}`
     (десктоп) / `{display:flex;flex-wrap:nowrap}` (≤900px) перебивають і display, і
     grid-template, і всі box-властивості. Виміряно живцем (computed display):
     1280px → contents · 900/700/500px → flex, flex-wrap:nowrap, justify:space-between.
     Плюс 3-зонний грід писався під центральну зону, якої в розмітці більше немає:
     дітей рівно двоє — .logo і .header-right. */
.header .logo{display:flex;align-items:center;min-width:0}
.header .ks-logo-mark{width:32px;height:32px;border-radius:var(--r-2)}
.header .ks-logo-name{font-size:var(--fs-6)}
.header-right{display:flex;align-items:center;justify-content:flex-end;gap:var(--sp-3);flex-wrap:wrap;min-width:0}
.logout{background:none;border:1px solid var(--border);color:var(--muted);padding:var(--pad-9) var(--pad-18);border-radius:var(--r-pill);font-size:var(--fs-3);font-family:'Arimo',sans-serif;font-weight:var(--fw-2);cursor:pointer;transition:background-color var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out),border-color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out);letter-spacing:var(--ls-7)}
@media(hover:hover){
/* T-H3 · ghost hover = hover НЕАКТИВНОГО СЕГМЕНТА капсули: підкладка --surface,
     текст --text, БЕЗ свічення й без підйому. 🔴 Бордер на ховері НЕ ЧІПАЄМО (T-H4, 19.08):
     сегменти капсули в шапці мають border:none, у них бордер не реагує взагалі, тож
     оранжевий --accent-line на «Вийти» був єдиною реакцією контуру в усьому ряду —
     кнопка жовтіла, сусідні сегменти ні. Один візерунок наведення на всю шапку. ~~T-4.2: суцільна біла заливка +
     білий ореол 0 0 24px + lift~~ — скасовано 19.08 (TASK §3, рішення власника): ореол на
     кнопці поряд із капсулою читався як те саме свічення, яке хвиля 3 з капсули прибрала. */
.logout:hover{background:var(--surface);color:var(--text);box-shadow:none}
}
.logout:active{transform:translateY(1px)}
/* T-H1 · --ks-lang-h живе ТУТ, а не на .ks-sticky-top: ту саму капсулу мов носить і
     екран входу (#loginLangSw), який до липкого хедера не належить. Одне число на обидва
     місця; зовнішня висота набирається сама: 28 + 2×інсет(4) + 2×бордер(1) = 38 = --ks-ctl-h. */
.lang-sw{--ks-lang-h:28px;display:flex;gap:var(--sp-1);background:var(--panel);border:1px solid var(--border);border-radius:var(--r-3);padding:var(--sp-1)}
/* BRIEF-3 §1 · та сама капсула, що й меню */
.lang-btn{display:inline-flex;align-items:center;justify-content:center;height:var(--ks-lang-h,28px);min-height:24px;border:none;background:none;color:var(--muted);font-family:inherit;font-size:var(--fs-2);font-weight:var(--fw-2);padding:var(--pad-5) var(--pad-10);border-radius:var(--r-pill);cursor:pointer;transition:background-color var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out),border-color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out);letter-spacing:var(--ls-5)}
/* T-4.2 · ≥24px tap target (WCAG 2.5.8) */
.lang-btn.active{background:var(--text);color:var(--bg)}
@media(hover:hover){
/* BRIEF-3 §1 · біла, не оранжева */
.lang-btn:not(.active):hover{color:var(--text);background:var(--surface)}
}
/* TABS — pills, active = orange fill with dark text (main-site button language) */
.tabs{display:flex;gap:var(--sp-2);margin-bottom:var(--sp-4)}
.tab{flex:1;padding:var(--pad-13) var(--pad-18);background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);color:var(--muted);font-family:'Arimo',sans-serif;font-size:var(--fs-3);font-weight:var(--fw-2);cursor:pointer;text-align:center;transition:background-color var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out),border-color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out);letter-spacing:var(--ls-5);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2)}
/* 🔴 §2.6 · E2 · АКТИВНА ВКЛАДКА — ТИХА ПІДКЛАДКА, не помаранчева й не біла.
     Виміряний контраст до тла: помаранчева 8,88:1 · біла 19,2:1 · E2 1,16:1.
     Помаранчева заливка тут кричала гучніше за головне число на екрані —
     вкладка має казати «ви тут», а не змагатися з даними. */
.tab.active{background:var(--surface-2);border-color:var(--border-strong);color:var(--text);box-shadow:none}
@media(hover:hover){
/* BRIEF-3 §2 · свічення скасовано */
.tab:not(.active):hover{border-color:var(--border-strong);color:var(--text);background:var(--surface)}
}
/* ── §1 · K · ІКОНКА В ТАБІ ────────────────────────────────────────────────
     Розмір і колір — у CSS (§9): 16×16 (кегль підпису --fs-3, 20px переважив би
     текст), колір успадковується через currentColor від самого таба, тож активний
     і неактивний стани фарбують іконку разом із підписом безкоштовно. */
.tab{display:flex;align-items:center;justify-content:center;gap:var(--sp-2)}
.tab .tab-ic{flex:0 0 16px;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}
.tab .tab-lbl{min-width:0}
/* ── §1 · K · ІКОНКА НА ДІЇ ────────────────────────────────────────────────
     Кнопки дій над таблицею: іконка перед підписом, той самий контур §14.3. */
.tbl-act{display:inline-flex;align-items:center;gap:var(--sp-1)}
.tbl-act .act-ic{flex:0 0 14px;width:14px;height:14px;display:inline-flex}
.per-step .ic,.wk-btn .ic,.goal-btn .ic{width:16px;height:16px;display:block}
.sort-caret{display:inline-flex;align-items:center;justify-content:center;width:11px;height:11px;vertical-align:middle}
.sort-caret .ic{width:100%;height:100%;display:block}
.ks-sort-dir .ic{width:16px;height:16px;display:block}
/* ── Period stepper arrows (‹ newer / › older) · ghost recipe §2.3 — two views of one state ── */
.per-step{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:44px;height:46px;padding:0;background:var(--surface);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2);border:1px solid var(--border);color:var(--text-2);border-radius:var(--r-pill);box-shadow:none;font-size:var(--fs-6);line-height:var(--lh-1);cursor:pointer;-webkit-appearance:none;appearance:none;transition:background var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out)}
@media(hover:hover){
.per-step:not(:disabled):hover{background:var(--surface);color:var(--text);box-shadow:none}
}
@media(prefers-reduced-motion:no-preference){
.per-step:not(:disabled):active{transform:translateY(1px)}
}
.per-step:disabled{opacity:.55;cursor:default;transform:none;box-shadow:none}
/* без .tool-select: у /driver селектор періоду цього класу не має — виміряно, саме там контрол і лишався роздутим */
/* 🔴 `nowrap` + вузьке місце = обріз. Виміряно на /dispatcher@768: підпис
   «latest available — 2026-W30» просить 141px, дістається 131 — останні
   символи року зрізані. Смуга 561…900 нижче ніяк не оброблялась: блок
   ≤560 віддає підпису власний рядок, а вище 900 місця вистачає.
   Дозволяємо перенос там, де рядка не вистачає: `nowrap` лишається як
   намір «не рвати без потреби», але не ціною зрізаного тексту. */
.per-qual{font-size:var(--fs-3);color:var(--dim);margin-left:var(--sp-2);white-space:nowrap;min-width:0}
@media(max-width:900px){
.per-qual{white-space:normal}
}
@media(max-width:560px){
.per-qual{flex:1 1 100%;margin-left:0;margin-top:var(--sp-1)}
.per-step{width:40px}
}
.per-group>select,.per-group>.tool-select{flex:0 1 auto}
.tool-select{flex:0 1 auto}
.tool-btn{height:46px;padding:0 var(--sp-4);border-radius:var(--r-pill);background:var(--text);color:var(--bg);border:1px solid transparent;font-family:inherit;font-size:var(--fs-5);font-weight:var(--fw-2);cursor:pointer;box-shadow:var(--elev-1);transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out);letter-spacing:var(--ls-7);white-space:nowrap}
@media(hover:hover){
.tool-btn:hover{background:var(--accent);color:var(--on-accent);border-color:var(--accent-text);box-shadow:var(--glow)}
}
.tool-btn:active{transform:translateY(1px)}
/* CARD HEAD — a label (+ optional trailing meta/action) that sits ABOVE its
     card instead of inside it, so the card itself stays compact. Shared by
     the week digest, weekly goal, and net-estimate calculator. */
.card-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-3);flex-wrap:wrap;margin:0 var(--optical) var(--sp-3)}
.card-head-label{font-family:'Arimo',sans-serif;font-size:var(--fs-2);font-weight:var(--fw-2);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4)}
.delta-up{color:var(--pos)}
.delta-down{color:var(--neg)}
/* ≥4.5:1 (WCAG AA) — only alpha */
.goal-btn{height:38px;padding:0 var(--pad-16);border-radius:var(--r-pill);background:var(--text);color:var(--bg);border:1px solid transparent;font-family:inherit;font-size:var(--fs-3);font-weight:var(--fw-2);cursor:pointer;box-shadow:var(--elev-1);transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out)}
@media(hover:hover){
.goal-btn:hover{background:var(--accent);color:var(--on-accent)}
}
/* ghost (Edit / ✕) stays flat — the resting shadow is for the solid white CTAs only */
.goal-btn.ghost{background:none;border:1px solid var(--border);color:var(--muted);box-shadow:none}
@media(hover:hover){
.goal-btn.ghost:hover{background:var(--surface);color:var(--text);box-shadow:none}
}
.goal-btn.ghost:active{transform:translateY(1px)}
/* §7.15 · min-height:90px «на око» ПРИБРАНО — рівну висоту тепер дає grid-auto-rows:1fr
     на .kpis; flex-центрування вмісту лишається (воно й тримає текст по центру картки). */
.kpi{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);padding:var(--pad-16);text-align:center;box-shadow:var(--elev-1);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2);min-width:0;display:flex;flex-direction:column;justify-content:center;min-height:120px}
/* §2 · min-height на БАЗОВОМУ носії: набір «доданки + підсумок» їде класом .kpis, не .kpi-grid, тож правка лише в сітковому рецепті його не діставала — виміряно 100.14px замість 120 */
.kpi .v{font-family:'Arimo',sans-serif;font-size:var(--kpi-v);font-weight:var(--fw-2);color:var(--accent);line-height:var(--lh-1);letter-spacing:var(--ls-2);word-break:break-word}
.kpi .v .na{color:var(--muted);font-size:1em}
.kpi .l{font-size:var(--fs-1);color:var(--muted);margin-top:var(--sp-1);text-transform:uppercase;letter-spacing:var(--ls-4);line-height:var(--lh-2)}
.kpi-delta{font-size:var(--fs-1);font-weight:var(--fw-2);line-height:var(--lh-2);margin-top:var(--sp-1)}
/* §I.4/L.1 · футер трип-листа: лічильник «100 із 1047» ліворуч, «Показати більше» праворуч.
     Сама коробка НЕ розкривається → var(--r-3); кнопка всередині — дія → var(--r-pill). */
.tl-more{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);flex-wrap:wrap;
    margin-top:var(--sp-3);padding:var(--pad-16) var(--sp-4);background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);
    -webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2)}
/* §2.1 · над hero без blur крізь --surface .05 видно фото */
.tl-more-count{font-size:var(--fs-3);color:var(--muted)}
.day-group{margin-bottom:var(--sp-6)}
.day-header{display:flex;align-items:center;gap:var(--sp-2);margin:0 var(--optical) var(--sp-3)}
.day-name{font-family:'Arimo',sans-serif;font-size:var(--fs-4);font-weight:var(--fw-2);color:var(--text)}
.day-count{font-size:var(--fs-3);color:var(--muted);display:none}
.day-group.collapsed .day-trips{display:none}
.day-summary{position:relative;cursor:pointer;display:flex;flex-wrap:wrap;gap:var(--sp-3) var(--sp-4);background:var(--accent-tint);border:1px solid var(--accent-wash);border-radius:var(--r-3);padding:var(--pad-16);padding-right:calc(var(--pad-16) + var(--pad-40));margin-bottom:var(--sp-3);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2)}
.day-toggle{position:relative;display:flex;align-items:center;justify-content:center;background:var(--surface);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2);border:1px solid var(--border);color:var(--muted);cursor:pointer;padding:0;transition:transform var(--dur-2) var(--ease-out),background var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out)}
/* T-4.2 · expand the touch target to ≥44px (WCAG 2.5.5) without growing the visual button */
.day-toggle::before{content:'';position:absolute;inset:-8px}
.day-toggle svg{width:15px;height:15px}
@media(hover:hover){
.day-toggle:hover{background:var(--accent-wash);color:var(--text);border-color:var(--accent-line)}
}
.day-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
@media(prefers-reduced-motion:reduce){
.day-toggle{transition:none}
}
.day-group.collapsed .day-toggle{transform:rotate(-90deg)}
/* web/tablet (default): square toggle lives INSIDE the summary card, vertically centered */
.day-header .day-toggle{display:none}
.day-summary .day-toggle{display:flex;position:absolute;top:50%;right:var(--sp-3);width:28px;height:28px;border-radius:var(--r-2);transform:translateY(-50%)}
.day-group.collapsed .day-summary .day-toggle{transform:translateY(-50%) rotate(-90deg)}
.ds-item{display:flex;flex-direction:column;gap:var(--sp-1)}
/* ── BRIEF-7 §3.15 · РЯДОК ТИЖНЯ — НА ВСЮ ШИРИНУ ──────────────────────────────
   Колонки стояли фіксованим кроком від вмісту й тулились у лівій половині, а далі
   до стрілки лежала порожнеча. Тепер крок так само задає вміст (min-width), але
   вільне місце РОЗПОДІЛЯЄТЬСЯ між колонками (flex:1 1 auto), а не збирається в
   хвіст. На ≤560 — сітка 3×3 замість горизонтального сувою. */
.day-summary > .ds-item{flex:1 1 auto;min-width:5.5rem}
@media(max-width:560px){
.day-summary{display:grid!important;grid-template-columns:repeat(3,1fr);gap:var(--sp-3)}
.day-summary > .ds-item{min-width:0}
}
.ds-l{font-size:var(--fs-1);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4)}
.ds-v{font-size:var(--fs-4);font-weight:var(--fw-2);color:var(--text)}
.ds-v.green{color:var(--text)}
.ds-v.red{color:var(--neg)}
/* TRIP BADGE
   🔴 BRIEF-RESULTS-01 §5.7.3 · РЕЦЕПТ КАРТКИ `.trip` ВИДАЛЕНО — ВІН БУВ МЕРТВИЙ.
   Чотири правила (база, два ховери, `.trip.adj-row`) не мали жодного носія:
   грепом по всіх п'ятьох поверхнях і по vendor клас `trip` зустрічається лише як
   `trip-badge`, а картку рейсу давно малює `.ks-mobile-card`/`.ks-item`.
   ⚠ Мертве правило — не «нічого не коштує»: воно тягне за собою рядок у кожній
     перевірці, що перелічує ховер-рецепти (C57), і наступний читач витрачає час,
     шукаючи, де ж ця картка показується. Саме тому видалення, а не коментар.
   ⚠ `.trip` лишається у списках селекторів `@media print` кабінетів — це вже їхні
     файли, і прибирати звідти мертве ім'я значило б правити п'ять місць заради
     косметики; там воно нічого не вмикає. */
.trip-badge{font-size:var(--fs-2);font-weight:var(--fw-3);padding:var(--sp-1) var(--sp-3);border-radius:var(--r-pill);letter-spacing:var(--ls-5);white-space:nowrap}
.trip-badge.delivered{background:var(--info-wash);color:var(--info)}
.trip-badge.cancelled{background:var(--neg-wash);color:var(--neg)}
.trip-badge svg{width:16px;height:16px;flex:0 0 16px;vertical-align:-3px}
/* Partial-metric note («без компанії, що не дає цієї метрики») — visible, not a
   tooltip (§1.1).
   ⚠ BRIEF-RESULTS-01 §5.1 · КОД КОМПАНІЇ ЗВІДСИ ПРИБРАНО. Цей файл вантажить і
     демо-сторінка /results, а vendor віддається браузером цілком, коментарі
     включно — тобто трилітерний код був би справжньою назвою на сторінці, яка
     обіцяє анонімність. Сторож `smoke/results-no-real-names.mjs` це й спіймав. */
.pnote{display:block;font-size:var(--fs-2);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4);font-weight:var(--fw-2);margin-top:var(--optical)}
/* §I.3 · маркер дедхеду — той самий рецепт, що .pnote; курсор help натякає на підказку */
.dh-note{cursor:help;text-transform:none;letter-spacing:var(--ls-7)}
.dh-note:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:var(--r-1)}
.kpi-delta.delta-na{color:var(--muted)}
.pnote-cov{text-transform:none;letter-spacing:var(--ls-7)}
.ic{display:inline-block;vertical-align:middle}
/* §7.19 · overflow:hidden — СТРАХОВКА, а не заміна фіксу висоти: канвас фізично не може
     виїхати за межі своєї картки на сусідній блок. Сам розмір лагодить .chart-full нижче. */
.chart-block{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);padding:var(--sp-4);margin-bottom:var(--sp-4);box-shadow:var(--elev-2);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2);min-width:0;overflow:hidden}
.chart-block canvas{max-width:100%}
.chart-note{font-size:var(--fs-2);color:var(--muted);margin-top:var(--sp-3)}
/* T-3.1.3.8 · min-width:0 on every column so a chart's intrinsic canvas size
     can never push the grid (and the page) wider than the viewport */
.charts-2col{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3);margin-bottom:var(--sp-4);align-items:stretch}
.charts-2col>div{min-width:0;height:100%;display:flex;flex-direction:column}
.charts-2col>div>.chart-block,.charts-2col>.chart-block{flex:1 1 auto;margin-bottom:0;display:flex;flex-direction:column;min-width:0}
.charts-2col .chart-full{flex:1 1 auto;min-height:200px;height:auto}
.charts-2col>*{min-width:0}
/* T-19 V-09 · .ks-errnote — було інлайн-стилем у vendor/cabinet-tables.js (єдине
     місце, де токени жили в JS-рядку й не потрапляли в CSS-звірку). */
.ks-errnote{margin:0 0 var(--sp-3);padding:var(--pad-10) var(--pad-16);border:1px solid var(--border);border-radius:var(--r-3);background:var(--surface);color:var(--muted);font-size:var(--fs-4)}
/* 🔴 FRONT-22 §2 · БАНЕР «НЕПОВНІ ДАНІ» — оформлення. Розмітку будує ОДИН носій
     у vendor/cabinet-tables.js (KS.degraded); тут лише стилі, поруч із .ks-errnote,
     як і решта правил кабінету.
     Колір — --neg. Контракт §1.4 закріпив цей токен за ПОМИЛКОЮ («--neg — помилка і
     скасування»), а недочитаний довідник — саме помилка: числа на екрані занижені.
     Це НЕ «падіння» (фарбувати напрямок §1.4 забороняє) і НЕ зелений: у кабінетах
     зелений означає гроші (§1.4), тому банером він бути не може.
     Радіус --r-3 (12px): банер не розкривається, отже 12 за §3.1. */
.ks-incomplete{display:flex;align-items:flex-start;gap:var(--sp-2);
    margin:0 0 var(--sp-4);padding:var(--pad-10) var(--pad-16);
    border:1px solid var(--neg);border-radius:var(--r-3);
    background:var(--neg-wash);color:var(--text)}
.ks-incomplete .ks-inc-ico{flex:0 0 20px;width:20px;height:20px;color:var(--neg)}
.ks-incomplete .ks-inc-ico svg{display:block;width:20px;height:20px}
.ks-incomplete .ks-inc-body{display:flex;flex-direction:column;gap:var(--sp-1);min-width:0}
.ks-incomplete .ks-inc-title{font-size:var(--fs-5);font-weight:var(--fw-2);line-height:var(--lh-2)}
.ks-incomplete .ks-inc-src{font-size:var(--fs-4);color:var(--muted);line-height:var(--lh-2);
    overflow-wrap:anywhere}
/* BRIEF-VISUAL-64 §2.3 · технічний код причини (QUOTA_EXCEEDED) лишається на екрані для
   діагностики власника, але приглушеним: він пояснює вже сказане, а не додає твердження.
   --dim це a-6 — рівно межа §1.4 «прозорість тексту нижче a-6 заборонена», не нижче.
   Розділювач джерел має власний клас, щоб крапка не читалась як частина коду. */
.ks-incomplete .ks-inc-code{color:var(--dim);font-size:var(--fs-3);white-space:nowrap}
/* ⚠ Роздільник джерел — --dim, НЕ --faint. §1.4 дозволяє --faint «тільки для рамок і
   роздільників», але тут роздільник це ТЕКСТОВИЙ гліф, а на текст діє перша половина
   того ж правила: «прозорість тексту нижче a-6 заборонена». Виміряно на знімку 430px:
   на --faint крапка між двома джерелами не читалась, і «QUOTA_EXCEEDED · <код компанії>»
   зливалось в один рядок. */
.ks-incomplete .ks-inc-sep{color:var(--dim)}
/* T-4.2 step 7 (owner decision: variant A with threshold) · ONLY long tables (15+ rows) get a
     bounded height + internal scroll, so their sticky <th> pins and the header stays visible;
     short tables render full height with no inner scrollbar, exactly as before. Pure CSS via
     :has() — degrades gracefully (no :has → no cap, the pre-step-7 behaviour). */
.p-table-wrap:has(tbody tr:nth-child(15)){overflow:auto;max-height:70vh}
.p-table{width:100%;border-collapse:collapse;font-size:var(--fs-4)}
.p-table th{text-align:left;padding:var(--pad-16) var(--sp-4);font-size:var(--fs-2);font-weight:var(--fw-2);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4);border-bottom:1px solid var(--border);white-space:nowrap;position:sticky;top:0;z-index:var(--z-raised);background:var(--panel)}
/* 🔴 BRIEF-DEMO-02 §2.5 (Д5) · ДРУГА ПОЛОВИНА ПАРИ. `th` жив тут, `td` лишався
   інлайном у ceo/index.html — і будь-яка сторінка, що бере таблицю з vendor і не
   має власної копії, діставала шапку з відступами й тіло БЕЗ НИХ. Виміряно на
   /results: `th` → padding 16px 20px, `td` → padding 0px, border-bottom 0px.
   Рядки злипались, роздільників не було.
   ⚠ Пара розділена — це КЛАС, а не випадок: §4.1 брифу вимагає перелічити всі. */
.p-table tr:last-child td{border-bottom:none}
@media(hover:hover){
.p-table tbody tr:hover td{background:var(--surface)}
}
.p-table .td-gross{color:var(--text);font-weight:var(--fw-2);font-family:'Arimo',sans-serif;font-size:var(--fs-4)}
.p-table .td-rpm{color:var(--info);font-weight:var(--fw-2)}
.p-table .td-period{font-weight:var(--fw-2)}
.empty{text-align:center;color:var(--muted);padding:var(--pad-50) var(--sp-4);font-size:var(--fs-5)}
.loader{text-align:center;padding:var(--pad-60) var(--sp-4);color:var(--muted);font-size:var(--fs-5)}
/* NO fill-mode here (T-4.2 transparency fix): fill:both kept transform:translateY(0) on the
     containers forever, and a transformed ancestor becomes the backdrop root — it severed every
     card's backdrop-filter from the fixed hero behind it, so the frost never rendered. With no
     fill the transform clears the moment the .28s entrance ends (end frame == static state). */
[id^="view"]{animation:ksFade var(--dur-3) var(--ease-in-out)}
.day-trips{animation:ksFade var(--dur-3) var(--ease-in-out)}
@media(prefers-reduced-motion:reduce){
[id^="view"],.day-trips{animation:none}
}
.hidden{display:none!important}
/* T-3.1.3.6 · section headers get real breathing room: a clear break from the
     block above (--sp-6) and a clear gap before their own content (--sp-q16) —
     this was the main spacing complaint (labels sat right on top of their section). */
.section-label{font-family:'Arimo',sans-serif;font-size:var(--fs-2);font-weight:var(--fw-2);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4);margin:var(--sp-6) 0 0 var(--optical)}
/* BRIEF-6 §2 · УТОЧНЕННЯ — В ТОМУ САМОМУ РЯДКУ, що й підпис секції.
     Два підписи один під одним заборонені: «УСІ ПЕРІОДИ» над «МІЙ РОЗРАХУНОК»
     читалось як два заголовки поспіль. Період, компанія чи кількість ідуть
     приглушеним хвостом того самого рядка: «Мій розрахунок · усі періоди · W22–W34».
     Регістр і трекінг НЕ успадковуються — уточнення це текст, не мітка. */
.sl-q{text-transform:none;letter-spacing:var(--ls-3);font-weight:var(--fw-1);color:var(--dim);margin-left:var(--sp-2)}
.err-title{font-size:var(--fs-6);font-weight:var(--fw-3);margin-bottom:var(--sp-1)}
.err-body{font-size:var(--fs-4);color:var(--muted);margin-bottom:var(--sp-3)}
@media(max-width:860px){
.wrap{padding:var(--pad-16) var(--pad-14) var(--pad-60)}
/* Д5 · компактні відступи — теж ПАРА, і теж була розділена.
   🔴 САМЕ ПРАВИЛО ПЕРЕЇХАЛО В КІНЕЦЬ ФАЙЛА — див. пояснення там. Тут лишається
   лише цей слід, щоб наступний не шукав його в цьому блоці даремно. */
}
@media (orientation:portrait) and (min-width:768px){
.kpis{align-items:stretch}
/* §7.15 · min-height:94px «на око» прибрано — висоту рядів тримає grid-auto-rows:1fr */
.kpi{display:flex;flex-direction:column;justify-content:center}
}
@media(max-width:767px){
/* T-3.1.3.5.5 / T-3.1.3.6 · day-summary as an aligned grid, 4 columns so the
       strip stays compact instead of stretching tall */
.day-summary{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-3) var(--sp-3);padding-right:var(--pad-16)}
/* T-3.1.3.13 · mobile: round toggle moves out of the card and into the
       header row (right-aligned); trip count shows next to the day name/date
       instead of as its own summary tile (desktop has the tile, not this) */
.day-header .day-toggle{display:flex;margin-left:auto;align-self:center;width:26px;height:26px;border-radius:var(--r-pill)}
.day-summary .day-toggle{display:none}
.day-count{display:inline}
.ds-trips{display:none}
.lang-btn{min-height:24px;padding:var(--pad-6) var(--sp-3)}
}
@media(max-width:560px){
.p-table .c-rpm{display:none}
.tool-select{flex:1 1 45%}
.kpi{display:flex;flex-direction:column;justify-content:center}
}
@media print{
body{background:var(--print-bg)!important;color:var(--print-ink)!important}
#pan-stage{display:none!important}
.wrap{max-width:none;padding:0}
.day-group.collapsed .day-trips{display:block!important}
.day-toggle{display:none!important}
.header{border-color:var(--print-rule)}
.header .logo{color:var(--print-ink)!important}
.header .ks-logo-name{color:var(--print-ink)!important}
.header .ks-logo-desc{color:var(--print-muted)!important}
.header .ks-logo-mark{border-color:var(--print-ink)}
.header .ks-logo-svg .lg-k{color:var(--print-ink)!important}
.trip-badge.delivered{background:none!important;color:var(--print-pos)!important;border:1px solid var(--print-pos)}
.trip-badge.cancelled{background:none!important;color:var(--print-neg)!important;border:1px solid var(--print-neg)}
}
.panel-pad{padding:var(--sp-4)}
.section-hint{font-size:var(--fs-3);color:var(--muted);margin:0 var(--optical) var(--sp-3)}
.week-group>.day-summary{background:var(--surface);border-color:var(--border)}
.week-group>.day-header .day-name{color:var(--accent)}
.tl-table .td-id{font-weight:var(--fw-2);font-size:var(--fs-4);color:var(--text)}
.tl-table .td-date{color:var(--muted);white-space:nowrap}
.tl-table .td-lane .route-line{color:var(--text)}
.tl-table .td-lane .addr{color:var(--text)}
.tl-table .td-lane .arrow{color:var(--accent);margin:0 var(--sp-1)}
.tl-table .num{text-align:right}
.tl-total .td-period{text-transform:uppercase;letter-spacing:var(--ls-6);font-size:var(--fs-2);color:var(--muted)}
.tl-adj-block{margin:0 var(--optical) var(--sp-4);padding:var(--pad-16);background:var(--accent-tint);border:1px dashed var(--accent-line);border-radius:var(--r-3)}
.tl-adj-title{font-size:var(--fs-2);font-weight:var(--fw-2);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4);margin-bottom:var(--sp-3)}
.tl-adj-chips{display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.tl-adj-chip{display:inline-flex;align-items:center;gap:var(--sp-2);padding:var(--pad-5) var(--sp-3);border-radius:var(--r-pill);background:var(--accent-wash);border:1px solid var(--accent-line);font-size:var(--fs-3);white-space:nowrap}
.tl-adj-id{font-weight:var(--fw-2);color:var(--text)}
.tl-adj-amt{color:var(--text);font-weight:var(--fw-2)}
.metrics-banner{margin:var(--sp-6) var(--optical) 0;padding:var(--pad-16) var(--pad-2) 0;font-size:var(--fs-3);color:var(--muted);border-top:1px solid var(--border)}
.day-trips .nested-group{margin-left:var(--sp-3)}
@media print{
.p-table th{background:var(--print-bg)!important;color:var(--print-muted)!important;border-bottom:1px solid var(--print-rule)!important;position:static!important}
}
/* п.8 · .ks-mobile-table за замовчуванням прихований (планшет/десктоп); ≤900px-
     override нижче вмикає його. Дефолт ОБОВ'ЯЗКОВО перед медіа-блоком: інакше
     unscoped-правило після нього виграло б каскад на БУДЬ-ЯКІЙ ширині (порядок
     джерела важливіший за вкладеність у @media при однаковій специфічності). */
.ks-mobile-table{display:none}
/* ══════════════════ ЗАХІД 5 · ХЕДЕР ІЗ ТАБАМИ НА >900px ══════════════════
     Д1 · липкість — ОДИН механізм на всі ширини, а не другий поряд із мобільним.
     Правила .ks-sticky-top, які захід 1 тримав усередині @media(max-width:900px),
     підняті сюди, у базу; мобільний блок нижче в каскаді лишає собі ЛИШЕ те, чим
     справді відрізняється (вертикальні відступи, компоновка хедера) — тому ≤900px
     рендериться так само, як до заходу.
     Full-bleed: тло має йти від краю до краю вікна, а .wrap має бічний padding —
     тягнемо блок негативним margin і повертаємо відступ дзеркальним padding. */
.ks-sticky-top{position:sticky;top:0;z-index:var(--z-sticky);background:var(--panel);
    margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);
    padding-left:calc(50vw - 50%);padding-right:calc(50vw - 50%)}
#app.wrap{padding-top:0}
/* Д6 · ДВА РЕЖИМИ ПРИЛИПАННЯ <th> — тепер на ВСІХ ширинах, бо липкий хедер тепер
     теж на всіх. Правило те саме, що захід 4 виміряв і поставив для мобільної:
     position:sticky відлічує top від найближчого предка-СКРОЛЕРА, а не від viewport,
     а .p-table-wrap{overflow-x:auto} робить обгортку скролером ЗАВЖДИ (пара
     visible+auto за специфікацією дає auto по обох осях). Обгортка є → контекст
     прилипання = вона → top:0. Обгортки немає → контекст = viewport → зсув на
     виміряну висоту липкого блоку. Копії всередині @media(max-width:900px) прибрано:
     правило одне, живе тут. */
.p-table th{top:var(--ks-sticky-h,0px)}
.p-table-wrap .p-table th{top:0}
@media(min-width:901px){
/* Ж4 · зазор між блоками хедера. 20px — наявний токен --sp-4; 28px серед --sp-*
       НЕМАЄ (шкала йде 16·20·24·32), тож він оголошений локальною змінною тут, поряд
       із --ks-ctl-h, і :root лишається байт-у-байт незмінним. Вужчий зазор вмикається
       не «на око»: межу задано ВИМІРОМ — див. блок --sp-4 нижче. */
.ks-sticky-top{--ks-ctl-h:38px;--ks-menu-h:28px;--ks-tab-inset:4px;--ks-hdr-gap:28px;
      display:flex;align-items:center;gap:var(--ks-hdr-gap);
      padding-top:var(--sp-2);padding-bottom:var(--sp-2);
      margin-bottom:var(--sp-6);border-bottom:1px solid var(--border)}
/* Е1/Ж3 · «Вийти» бере ту саму висоту, підкладку, hairline і радіус, що коробки
       сегментованих груп.
       🔴 T-H3 (19.08) · ховер ТУТ доводиться переписувати, і це не дублювання. Це правило
       має специфічність 0-3-0 і задає background/border-color, а базовий `.logout:hover` —
       0-2-0. Тобто в липкому хедері базовий ховер програвав: підкладка й бордер лишались
       незмінними, застосовувались тільки box-shadow і color, яких тут немає, — звідси
       «широкий ореол без заливки» на прев'ю власника. Виміряно C10. */
.ks-sticky-top .header-right .logout{height:var(--ks-ctl-h);padding-top:0;padding-bottom:0;
      background:var(--panel);border:1px solid var(--border);border-radius:var(--r-3)}
@media(hover:hover){
.ks-sticky-top .header-right .logout:hover{background:var(--surface);
      color:var(--text);box-shadow:none}
}
.ks-sticky-top .header{display:contents}
.ks-sticky-top .logo{order:1;flex:0 0 auto}
.ks-sticky-top .tabs-wrap{order:2;flex:1 1 auto;min-width:0;margin:0;position:relative}
.ks-sticky-top .header-right{order:3;flex:0 0 auto;flex-wrap:nowrap}
/* ═══ Ж2 · СПІЛЬНИЙ РЕЦЕПТ СЕГМЕНТОВАНОЇ ГРУПИ ════════════════════════════
       Захід 6 мав рецепт коробки лише для панелі табів. Тепер його читають ОБИДВІ
       групи — таби й мови — з одного правила, а не з двох схожих наборів. Додати
       третю групу означатиме дописати селектор сюди, а не скопіювати блок.
       Зовнішній радіус --r-3 (§2.0: хром хедера не розкривається — див. Ж1),
       інсет --ks-tab-inset, висота --ks-ctl-h.
       overflow:hidden тримає glow активної капсули В МЕЖАХ коробки. */
.ks-sticky-top .tabs[role="tablist"],
    .ks-sticky-top .header-right .lang-sw{margin-bottom:0;gap:var(--sp-1);position:relative;overflow:hidden;
      align-items:stretch;
      background:var(--panel);border:1px solid var(--border);
      border-radius:var(--r-3);padding:var(--ks-tab-inset)}
/* BRIEF-3 §1 + T-H1 · висота задається СЕГМЕНТУ, капсула набирає свою сама:
       сегмент + 2×інсет + 2×бордер. Фіксувати висоту капсулі не можна — у мов
       .lang-btn має min-height:24px (WCAG 2.5.8, канон §4), і при капсулі 32px контентна
       коробка виходила 22px, тобто пігулка вилазила на 2px за нижній інсет.
       🔴 T-H1 (19.08) · значення сегмента ВИВОДИТЬСЯ НАЗАД із цільової зовнішньої висоти:
       усі три елементи хедера мусять дорівнювати --ks-ctl-h (38px), отже
       1(бордер) + 4(інсет) + 28(СЕГМЕНТ) + 4 + 1 = 38. Було 40 і 32 — це давало капсули
       50px і 42px проти 38px у «Вийти», і три різні висоти в одному ряду.
       --ks-lang-h оголошено на .lang-sw (базовий блок): ту саму капсулу носить екран входу.
       28px > 24px мінімуму дотику, а капсула вмикається лише від 901px — це миша. */
.ks-sticky-top .tabs[role="tablist"] .tab{height:var(--ks-menu-h)}
/* 🔴 Капсула ОБОХ груп — та сама арифметика: зовнішній радіус мінус інсет.
       Літералів 10px немає; зміниться --r-3 або інсет — концентричність
       перерахується сама в обох групах одночасно. */
.ks-sticky-top .tabs[role="tablist"] .ks-tab-ind,
    .ks-sticky-top .header-right .lang-sw .lang-btn{
      border-radius:calc(var(--r-3) - var(--ks-tab-inset))}
/* BRIEF-3 §1 · активна мова — БІЛА пігулка (--text/--bg), без свічення: оранжевий
       лишається за меню розділів, щоб дві капсули в одному ряду не сперечались.
       Роздільників між мовами немає — власник обрав варіант A (Ж2). */
.ks-sticky-top .header-right .lang-sw .lang-btn.active{
      background:var(--text);color:var(--bg);box-shadow:none}
/* 🔴 Коли компактне меню мов розкрите, воно лежить ПОЗА коробкою (position:absolute),
       і overflow:hidden обрізав би його. На час відкриття обрізання знімаємо: меню
       важливіше за утримання glow, а сам glow у цей момент перекритий панеллю меню. */
.ks-sticky-top .header-right .lang-sw.ks-lang-open{overflow:visible}
/* Е3 · min-height:44px знято НЕ мовчки — див. ::after нижче й §Е3 звіту:
       при висоті панелі 38px сегмент фізично не може бути 44px. */
.ks-sticky-top .tabs[role="tablist"] .tab{flex:1 1 0;min-width:0;position:relative;z-index:var(--z-raised);
      display:flex;align-items:center;justify-content:center;
      padding:0 var(--sp-3);white-space:nowrap;background:transparent;border:none;
      border-radius:calc(var(--r-3) - var(--ks-tab-inset));
      -webkit-backdrop-filter:none;backdrop-filter:none}
/* Е3/Ж5 · клікабельна зона сегмента тягнеться на ПОВНУ доступну висоту коробки:
       прозорий псевдоелемент перекриває інсет зверху й знизу. Далі не тягнеться
       свідомо — коробка має overflow:hidden, і все, що вийде за неї, обрізається не
       лише візуально, а й для хіт-тесту; знімати overflow не можна, на ньому
       тримається обмеження glow (§5 звіту заходу 5).
       🔴 Чому різні псевдоелементи: у таба ::before зайнятий РОЗДІЛЬНИКОМ, а в мовної
       кнопки ::after зайнятий СТРІЛКОЮ компактного режиму (▾). Тож кожна група бере
       той, що в неї вільний; геометрія зони — спільна. */
.ks-sticky-top .tabs[role="tablist"] .tab::after,
    .ks-sticky-top .header-right .lang-sw .lang-btn::before{content:'';position:absolute;
      left:0;right:0;top:calc(-1 * var(--ks-tab-inset));bottom:calc(-1 * var(--ks-tab-inset))}
.ks-sticky-top .header-right .lang-sw .lang-btn{position:relative}
/* 🔴 T-H2 (19.08) · РОЗДІЛЬНИКИ ПОВЕРНЕНО дослівно з 92fe442. BRIEF-3 просив їх
       прибрати — це була помилка брифу, власник їх не замовляв прибирати. Правило
       відновлене БАЙТ-У-БАЙТ, включно з тримом top/bottom:var(--ks-tab-inset) — руками
       нічого не підганяв. Смужка стала нижчою сама: інсет тепер 4px замість 2px, а сегмент
       28px замість 32px, тож 28-2*4=20px проти 28px у 92fe442.
       Роздільник малює ПРАВИЙ сусід пари; прилеглі до активного не малюються, щоб
       лінія не впиралась у заливку капсули. У мов роздільників не було й немає. */
.ks-sticky-top .tabs[role="tablist"] .tab+.tab::before{content:'';position:absolute;
      left:0;top:var(--ks-tab-inset);bottom:var(--ks-tab-inset);width:1px;background:var(--border)}
.ks-sticky-top .tabs[role="tablist"] .tab.active::before,
    .ks-sticky-top .tabs[role="tablist"] .tab.active+.tab::before{display:none}
/* 🔴 §2 ADDENDUM · КОЛІР АКТИВНОЇ ВКЛАДКИ НА ДЕСКТОПІ ЖИВЕ ТУТ, А НЕ НА .tab.active.
       Хвиля VISUAL-63 §2.6 перевела `.tab.active` з --accent на --surface-2 — і на 430
       це спрацювало, а на 1400/1194 ні: тут вкладки живуть капсулою (§14.9), сам таб
       ПРОЗОРИЙ, а помаранчеву плиту малює ковзний індикатор .ks-tab-ind під ним.
       Тобто рецепт E2 застосували не до того вузла, і перевірка VE2 цього не впіймала,
       бо міряла лише 1400 — ширину, де .tab.active і до хвилі був прозорий.
       Тепер E2 стоїть на самому індикаторі: заливка --surface-2, рамка --border-strong.
       Колір тексту активного таба перевертається разом із підкладкою: на --surface-2
       темна фарба --on-accent була б нечитною. Рух (transform) НЕ чіпаємо. */
.ks-sticky-top .tabs[role="tablist"] .tab.active{background:transparent;
      border-color:transparent;color:var(--text);box-shadow:none}
.ks-sticky-top .tabs[role="tablist"] .ks-tab-ind{position:absolute;left:0;top:0;z-index:var(--z-base);
      background:var(--surface-2);border:1px solid var(--border-strong);
      border-radius:calc(var(--r-3) - var(--ks-tab-inset));
      box-shadow:none;   /* BRIEF-3 §2 · свічення СКАСОВАНО: усередині капсули воно впиралось
                            у бордер за інсет і підсвічувало його зсередини */
      transition:transform var(--dur-2) var(--ease-out),width var(--dur-2) var(--ease-out)}
@media(prefers-reduced-motion:reduce){
.ks-sticky-top .tabs[role="tablist"] .ks-tab-ind{transition:none}
}
}
@media(min-width:901px) and (max-width:1100px){
/* Д5 · 901–1100px · ущільнюється ХРОМ, не таби.
     Вимір ДО заходу (найдовша з трьох мов — RU): шести сегментам /ceo на 901px
     бракує 50px, на 940px — 11px, від 1000px усе вміщається. Тому ущільнення
     вмикається саме до 1100px (наявний брейк канону §5), а не до довільної ширини. */
.ks-sticky-top .ks-logo-words{display:none}
.ks-sticky-top .tabs[role="tablist"] .tab{font-size:var(--fs-2)}
/* мовний перемикач згортається до поточної мови зі стрілкою; решта — у меню,
       яке будує KS.langInit САМЕ в цьому діапазоні (поза ним кнопки повертаються
       на свої місця, тож на ≤900px розмітка лишається незмінною) */
.ks-sticky-top .lang-sw{position:relative}
.ks-sticky-top .lang-sw .ks-lang-cur::after{content:'▾';margin-left:var(--sp-1)}
.ks-sticky-top .ks-lang-menu{position:absolute;top:calc(100% + var(--sp-1));right:0;
      display:none;flex-direction:column;gap:var(--sp-1);z-index:var(--z-drop);min-width:100%;
      background:var(--panel);border:1px solid var(--border);
      border-radius:var(--r-3);padding:var(--sp-1)}
.ks-sticky-top .lang-sw.ks-lang-open .ks-lang-menu{display:flex}
}
@media(max-width:900px){
/* 🔴 T-H1 (19.08) · ≤900px лишається як БУЛО. --ks-lang-h заведено для капсули шапки
       (28px → зовнішні 38px = висота «Вийти»); на мобільному ряд інший, «Вийти» там 32px,
       і піднімати капсулу мов до 38 означало б завести НОВУ нерівність замість полагодженої.
       auto повертає розмір із min-height:24px — рівно та геометрія, що до правки (34/24). */
.lang-sw{--ks-lang-h:auto}
/* п.1 · Таби розділів: influs — розтягуються (успадкований flex:1, не чіпали);
       не influs — горизонтальний скрол із НАВМИСНО підрізаним наступним табом.
       min-width — та межа, де flexbox перестає стискати й починає переповнювати: сам
       перемикач "розтягнутись / скролити" без жодного JS-виявлення ширини. */
.tabs-wrap{position:relative}
.tabs[role="tablist"]{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;flex-wrap:nowrap;scroll-behavior:smooth}
.tabs[role="tablist"]::-webkit-scrollbar{display:none}
.tabs[role="tablist"] .tab{flex:1 1 0;min-width:110px}
@media(prefers-reduced-motion:reduce){
.tabs[role="tablist"]{scroll-behavior:auto}
}
/* градієнт-затухання праворуч; .tabs-fit (усе влізло) і .tabs-end (доскролено до кінця)
       вимикають його — керує JS (ksInitTabsBar, cabinet-tables.js) виміром scrollWidth/scrollLeft. */
.tabs-wrap::after{content:'';position:absolute;top:0;right:0;bottom:0;width:32px;pointer-events:none;
      background:linear-gradient(to right,transparent,var(--panel));opacity:1;transition:opacity var(--dur-2) var(--ease-out)}
.tabs-wrap.tabs-fit::after,.tabs-wrap.tabs-end::after{opacity:0}
@media(prefers-reduced-motion:reduce){
.tabs-wrap::after{transition:none}
}
/* секція → секція: 24px зверху в того, що ВІДКРИВАЄ секцію; 12px до її вмісту */
.section-label{margin:var(--sp-4) 0 0 var(--optical)}
/* BRIEF-6 §2 (ред. 20.08) · шкала {12·20·32} з наявних токенів */
.gran-bar,.pnl-toolbar,.filters{margin-bottom:var(--sp-4)}
/* перший блок панелі секцію не відкриває — над ним хедер, а не попередня секція */
[id^="view"]>:first-child,[id^="view"]>*>:first-child{margin-top:0}
/* заголовок → підзаголовок = 8px; діє лише коли підзаголовок реально є (він
       може бути порожнім — #goalExtSub:empty), інакше лишається базові 12px до картки */
.wc-ext-head:has(+.wc-ext-sub:not(:empty)){margin-bottom:var(--sp-2)}
#goalExtSub:empty{display:none}
.chart-block{margin-bottom:var(--sp-4)}
.per-step{width:44px}
/* ═══ В4 · ХЕДЕР ═════════════════════════════════════════════════════════
       🔴 Це СКАСУВАННЯ частини п.6 заходу 1 (логотип в один рядок, ужимання до ~104px)
       на пряму вимогу власника — не «полагодження назад», а нове рішення.
       (а) ЗАЗОР ЗВЕРХУ: .wrap має власний padding-top (24px, і 16px на ≤860) — липкий
           блок починався ПІД ним, і над ним лишалась смуга фону сторінки. Забираємо
           padding у .wrap і віддаємо його самому липкому блоку: тепер він починається
           рівно від верху viewport на БУДЬ-ЯКІЙ ширині ≤900, без magic number.
       (б) логотип знову у два рядки — правило заходу 1 (.ks-logo-words{flex-direction:row})
           просто прибрано, база вже дає column.
       (в) мовні кнопки + «Вийти» — в один ряд із логотипом: базове ≤560px правило
           .header{flex-wrap:wrap} переносило .header-right на власний ряд.
       Не змінюється: липкість разом із табами, непрозоре тло --panel, full-bleed,
       зсув sticky-<th> на ВИМІРЯНУ висоту блоку.
       🔴 ЗАХІД 5 · саму липкість (position/top/z-index/тло/full-bleed) і #app.wrap{padding-top:0}
       піднято в БАЗУ — механізм тепер один на всі ширини. Тут лишається РІВНО те, чим
       мобільна відрізняється: власні вертикальні відступи блоку й компоновка хедера.
       Ім'я користувача більше не ховається — його немає зовсім (Д4, знято з усіх ширин). */
.ks-sticky-top{margin-bottom:var(--sp-3);padding-top:var(--pad-16);padding-bottom:var(--sp-3)}
.ks-sticky-top .header{display:flex;flex-wrap:nowrap;align-items:center;justify-content:space-between;
      gap:var(--sp-3);border-bottom:none;margin-bottom:var(--sp-3);padding-bottom:0}
.ks-sticky-top .header-right{flex:0 0 auto;flex-wrap:nowrap}
.ks-sticky-top .tabs-wrap{margin:0}
.ks-sticky-top .tabs[role="tablist"]{margin-bottom:0}
/* п.4 · дублікат "More trends" ховається, коли зовнішні per-chart заголовки вже показані */
.wc-ext-hide-mobile{display:none}
/* В8 · те саме для БУДЬ-ЯКОЇ порожньої примітки графіка в будь-якому кабінеті —
       окремі ID вище лишаються заради специфічності, це правило добирає решту
       (#ocProfitNote та ін.), щоб порожній підпис не додавав картці 12px нізвідки. */
.chart-note:empty{min-height:0;margin-top:0}
/* п.5 · відступи ВСЕРЕДИНІ карток — одна система: --sp-q16 скрізь. */
.chart-block,.trip{padding:var(--pad-16)}
/* flow-root, а не block: сітка не схлопує margin'и дітей, а звичайний блок —
       схлопує, і margin-top заголовка графіка «протікав» назовні, додаючи 8px до
       проміжку між картками (виміряно: 24 замість 16). flow-root дає той самий
       звичайний потік БЕЗ вирівнювання висот і без протікання margin'ів. */
.charts-2col{display:flow-root}
.charts-2col>div{height:auto;display:flow-root}
.charts-2col>div>.chart-block,.charts-2col>.chart-block{flex:0 0 auto;display:block;margin-bottom:var(--sp-3)}
/* ═══ п.8 / В1 / В5 · СПИСОК + ІНЛАЙН-РОЗГОРТАННЯ ════════════════════════
       Десктопна <table> (.ks-desktop-table, завжди в DOM — тіло того самого tableHTML())
       ховається; показується паралельний .ks-mobile-table з тих самих cols/rows/sort.
       В1 · ТИПОГРАФІКА. Мобільний список лежить ПОЗА <table>, тож не успадковував
       .p-table{font-size:var(--fs-4)} — і брав 16px від body. Звідси «шрифт ніби не з
       мого сайту»: назви компаній 15-16px замість 12px. Тепер розмір задає сам
       .ks-mobile-table, а кожен елемент звірений із СВОЇМ десктопним відповідником:
         .ks-row-id      ↔ td-ідентифікатор (--fs-4 / 600 / --text)
         .ks-row-metric  ↔ td.td-gross       (--fs-4 / 600 / --pos)
         .ks-row-t2      ↔ .section-hint     (--fs-3 / 400 / --muted)
         .ks-detail-label↔ th                (--fs-2 / 600 / --muted / uppercase)
         .ks-detail-value↔ td                (--fs-4 / 400 / --text)
       Жодного літерального px/кольору — усе з наявних токенів. */
.ks-desktop-table{display:none}
.ks-mobile-table{display:block;font-size:var(--fs-4)}
/* В2 · підказка носить НАЯВНИЙ клас .section-hint (стиль звідти); .ks-list-hint —
       лише маркер для ksSyncHints(), власної типографіки не має. */
.ks-item{border-bottom:1px solid var(--border-hair)}
.ks-item:last-child{border-bottom:none}
/* А4в · лівий відступ рядка і відступ шеврона від правого краю — ОДНЕ значення
       (--sp-q16). Праворуч у тексту більше (--sp-6), щоб він не заповзав під шеврон. */
.ks-row{display:flex;flex-direction:column;gap:var(--sp-2);position:relative;
      padding:var(--pad-16) var(--sp-6) var(--pad-16) var(--pad-16);
      cursor:pointer;min-height:44px;justify-content:center}
.ks-row:active{background:var(--surface)}
.ks-row-t1{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-3)}
/* Г3 · заголовок день-групи → плитка метрик мав 16px (--sp-q16), тоді як клас
       «заголовок/примітка → вміст» у шкалі заходу 3 = 12px (--sp-3). Блок просто не
       входив у ту вибірку. Значення зі шкали, нового не заводимо. */
.day-header{margin-bottom:var(--sp-3)}
/* Заскоуплене на таблицю правило .p-table .td-period{font-weight:var(--fw-2)} поза нею не
       діяло б — повторюємо РІВНО його. Решта класів клітинок (.td-drv/.td-gross/.c-rpm)
       мають ГЛОБАЛЬНІ правила, тож у списку працюють самі: свідомо їх не дублюємо,
       інакше /ceo отримав би 600 там, де його таблиця дає 400. */
.ks-mobile-table .td-period{font-weight:var(--fw-2)}
/* Дзеркало .drv-row .td-drv — виділення ідентифікатора в рядку, що ВЕДЕ ДАЛІ.
       Ті самі значення, та сама умова, лише інший носій умови (див. ks-row-act). */
.ks-row-act .td-drv{color:var(--text);font-weight:var(--fw-2)}
/* .ks-row-id ваги НЕ задає: її дає клас колонки (див. вище), рівно як у <td>. */
.ks-row-id{font-size:var(--fs-4);color:var(--text);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ks-row-metric{font-size:var(--fs-4);font-weight:var(--fw-2);color:var(--text);white-space:nowrap}
.ks-row-t2{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-3);font-size:var(--fs-3);font-weight:var(--fw-1);color:var(--muted)}
.ks-row-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ks-row-status{white-space:nowrap;flex:0 0 auto}
/* В5 · шеврон повертається за станом: › закритий, ⌄ (той самий гліф, повернутий
       на 90°) відкритий. Один елемент, два стани — без другого символу в розмітці. */
.ks-row-chevron{position:absolute;right:var(--pad-16);top:50%;font-size:var(--fs-6);color:var(--muted);
      transform:translateY(-50%);transform-origin:50% 50%;transition:transform var(--dur-2) var(--ease-out)}
.ks-row[aria-expanded="true"] .ks-row-chevron{transform:translateY(-50%) rotate(90deg)}
@media(prefers-reduced-motion:reduce){
.ks-row-chevron{transition:none}
}
/* §Б6/§В6 · картка метрик замість рядка списку (один рядок даних, або розгортати
       нічого): без курсора-вказівника, без шеврона, без нижньої лінії. */
.ks-row-static{cursor:default}
.ks-mobile-card .ks-item{border-bottom:none}
/* §Б5 · контрол сортування над списком. Класи всередині — НАЯВНІ (.tool-select,
       .per-step), тут лише розкладка рядка. */
.ks-sort-bar{display:flex;align-items:center;gap:var(--sp-2);
      padding:var(--sp-3) var(--pad-16);border-bottom:1px solid var(--border)}
/* Г2.3 · «СОРТУВАТИ ЗА» — теж роль «мітка»: був єдиним у сім'ї з вагою 400. */
.ks-sort-lbl{flex:0 0 auto;font-size:var(--fs-2);font-weight:var(--fw-2);text-transform:uppercase;
      letter-spacing:var(--ls-4);color:var(--muted)}
.ks-sort-sel{flex:1 1 0;min-width:0}
/* BRIEF-13 §4.6 · базис 0, не auto: після ратифікованого
       кеглю контролів 14 → 15 селект із базисом «за вмістом» переставав стискатись і
       виштовхував кнопку напрямку за екран на 430 (виміряно right=437 > 430). Лікується
       структурою, а не поверненням кеглю. */
.ks-sort-dir{font-size:var(--fs-5)}
/* §Б4/§7.1 · підсумок як ПІДВАЛ списку: фон шапки (--panel), той самий, що й у
       .tl-total/.trow-total десктопної таблиці. Не рядок списку: без шеврона й onclick. */
.ks-list-footer{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-3);
      background:var(--panel);border-top:1px solid var(--border);padding:var(--sp-3) var(--pad-16);
      font-weight:var(--fw-2);font-size:var(--fs-4)}
.ks-list-footer .ks-foot-l{text-transform:uppercase;letter-spacing:var(--ls-4);
      font-size:var(--fs-2);color:var(--muted);font-weight:var(--fw-2)}
.ks-list-footer .ks-foot-v{color:var(--accent);white-space:nowrap}
/* ═══ В5 · РОЗГОРНУТИЙ БЛОК — ІНЛАЙН, ПІД СВОЇМ РЯДКОМ ═══════════════════
       Замість окремого екрана з кнопкою «‹ Назад» (яку власник назвав безглуздою):
       блок розкривається на місці, сусідні рядки лишаються видимими, закриває той
       самий рядок, що відкривав. Кнопки «Назад» у розмітці більше немає взагалі.
       Анімація — наявна @keyframes ksFade (canon §6.5), з prefers-reduced-motion. */
.ks-detail{padding:0 var(--pad-16) var(--pad-16);animation:ksFade var(--dur-2) var(--ease-in-out)}
@media(prefers-reduced-motion:reduce){
.ks-detail{animation:none}
}
.ks-detail-row{display:flex;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-3) 0;
      border-bottom:1px solid var(--border-hair);min-height:44px;align-items:center}
.ks-detail-row:last-child{border-bottom:none}
.ks-detail-label{font-size:var(--fs-2);font-weight:var(--fw-2);color:var(--muted);
      text-transform:uppercase;letter-spacing:var(--ls-4);flex:0 0 auto}
.ks-detail-value{font-size:var(--fs-4);font-weight:var(--fw-1);color:var(--text);text-align:right;min-width:0}
}
/* П.9 · 5-й виняток до §2.0 ред.3 (підтверджено власником, M.4): повноширинна кнопка
     (width:100%) вироджує pill у капсулу — та сама природа винятку, що вже є для textarea
     сайту. Стосується ЛИШЕ кнопки переходу в розгорнутому рядку (8f/Б2) — інші
     повноширинні кнопки зі списку 0c (.btn логіну) НЕ чіпаються. */
.ks-detail-action{width:100%;border-radius:var(--r-3);min-height:44px;height:auto;margin-top:var(--sp-3)}
/* §4 · блок коригувань: рамка зелена, бонус зелений «+», штраф червоний «−». */
.adj-group{border-color:var(--accent-line)}
.adj-group .day-name{color:var(--accent)}
.adj-list{padding:var(--pad-2) 0}
.adj-line{display:flex;align-items:baseline;gap:var(--sp-3);padding:var(--pad-7) var(--pad-12)}
.adj-line+.adj-line{border-top:1px solid var(--border-hair)}
.adj-id{color:var(--muted);font-size:var(--fs-3);white-space:nowrap}
.adj-why{flex:1 1 auto;min-width:0;color:var(--text);word-break:break-word}
.adj-why-none{flex:1 1 auto}
.adj-amt{white-space:nowrap;font-weight:var(--fw-2)}
.adj-amt.pos{color:var(--text)}
.adj-amt.neg{color:var(--neg)}
@media(max-width:560px){
/* ── BRIEF-5 §5 · ДВА ГРАФІКИ В РЯД НА ПЛАНШЕТІ-ВЕРТИКАЛЬ ────────────────
   Було: .charts-2col схлопувалась в одну колонку вже на 860, тож на 834
   графік займав усю ширину, а їх ставало вдвічі більше по вертикалі.
   Стало: дві колонки тримаються до 560. На 834 це ~390px на графік — саме
   та ширина, під яку §5 задає глибину 12 тижнів (24 стовпці там дали б
   13px кожен, тобто частокіл без зазору). */
.charts-2col{grid-template-columns:1fr}
/* 🔴 §3 · ПАРА «ПІДПИС СЕКЦІЇ → ПІДЗАГОЛОВОК» = 8, не 12. На ≥561 комірка —
     сітка, і ритм усередині неї тримає сітка (перевірка пар туди не заходить);
     на ≤560 комірка стає потоком, і проміжок задає `> * + *`. Одне значення для
     однієї пари з таблиці §3; решта смуг лишається на 12 (subheading → block). */
.charts-2col>div>.section-label+.chart-sub{margin-top:var(--sp-2)}
}
@media(min-width:561px) and (max-width:900px){
/* §5 · планшет-вертикаль (561–900): графіки ПОВЕРТАЮТЬСЯ у два стовпці.
   Хвиля мобільної адаптації робила .charts-2col{display:flow-root} уже на
   ≤900 — саме тому на 834 графік займав усю ширину. Тут відновлюємо сітку
   для 561–900; ≤560 лишається як було (один стовпець, flow-root).
   aspect-ratio канви з блоку ≤900 не чіпаємо — це про пропорцію, не про
   кількість колонок. */
.charts-2col{display:grid;grid-template-columns:1fr 1fr}
.charts-2col>div{display:flex;flex-direction:column;height:100%}
/* BRIEF-6 §6 №4/№5 · КАРТКА МУСИТЬ ЗАПОВНИТИ КЛІТИНКУ. §5 повернув сітку і
     флекс-колонку комірки, але .chart-block лишився з ≤900-редакції
     (flex:0 0 auto;display:block) — тобто картка міряла себе за власним вмістом,
     і сусіди в ряду розходились: виміряно 348 проти 325 (/ceo Динаміка,
     /dispatcher Заробіток), 359 проти 325 (/client Компанія), 353 проти 313
     (/driver Показники) — рівно на різницю в кількості рядків виноски. */
.charts-2col>div>.chart-block,.charts-2col>.chart-block{flex:1 1 auto;display:flex;flex-direction:column;margin-bottom:0}
.charts-2col .chart-full{flex:1 1 auto}
}
/* ── BRIEF-9 §5 · СМУГА ЗАВАНТАЖЕННЯ (варіант B, ратифіковано) ────────────────
   Своя смуга над КОЖНИМ блоком, що вантажиться; глобальної смуги немає.
   Рух вимикається за prefers-reduced-motion — лишається статична смуга. */
.ks-loadbar{margin:0 0 var(--sp-3)}
.ks-loadbar-track{position:relative;overflow:hidden;height:3px;border-radius:var(--r-1);
  background:var(--border-hair)}
.ks-loadbar-track>i{left:0;position:absolute;top:0;height:100%;width:38%;border-radius:var(--r-1);
  background:var(--accent);animation:ksLoadSlide var(--dur-loop-slide) var(--ease-in-out) infinite}
/* §5.1 · підпис очікування читається як решта підписів секцій: кегль із драбини,
   колір --muted, верхній регістр і --ls-4. */
.ks-loadbar-text{margin-top:var(--sp-2);font-size:var(--fs-3);color:var(--muted);
  text-transform:uppercase;letter-spacing:var(--ls-4)}
@media(prefers-reduced-motion:reduce){
.ks-loadbar-track>i{left:0;animation:none;width:100%;opacity:.5}
}
/* §5 · ПІДЗАГОЛОВОК ГРАФІКА — окремий рядок між підписом секції й карткою.
   Порожній ТЕЖ тримає висоту рядка: інакше сусідні картки ряду знову розійдуться. */
.chart-sub{font-size:var(--fs-3);color:var(--muted);margin:0 var(--optical);line-height:var(--lh-2);min-height:1.35em}
}
.p-table tbody tr:last-child td,table.calc-week tbody tr:last-child td,table.tl-table tbody tr:last-child td{
  border-bottom:1px solid var(--border-hair)}
.p-table tbody tr.trow-total .dim,.p-table tbody tr.tl-total .dim,
table.calc-week tbody tr.tot .dim,table.tl-table tbody tr.tl-total .dim{color:var(--muted)}
@media(max-width:560px){
.filters::before{content:'';flex:0 0 100%;height:0;order:1}
.filters>*{order:0}
.gran-bar::before{content:'';flex:0 0 100%;height:0;order:1}
.gran-bar>*{order:0}
/* 🔴 BRIEF-13 §4.6 · СЕЛЕКТ СОРТУВАННЯ — НЕ ТУЛБАРНИЙ. Правило вище ловить
     будь-який .tool-select і дає йому flex:0 0 auto; у смузі сортування
     мобільного списку це означало «не стискатись», і після ратифікованого
     кеглю контролів 14 → 15 кнопка напрямку виїжджала за екран (right=437 при
     430). Явна пара «смуга → її селект» двозначності не лишає. */
.ks-sort-bar>.tool-select{flex:1 1 0;min-width:0;width:auto}
.per-step{width:38px;height:38px}
}
/* 🔴 §3.1 · від'ємні гроші — --neg, хоч би де вони лежали (D11, контракт §1.4).
     Правило на самому <span>, який ставить money(): власний колір вузла б'є
     успадкований від зеленого носія (.kpi.net .v / .td-net) без !important. */
.m-neg{color:var(--neg)}
[data-role="block"]+[data-role="card"]{margin-top:var(--sp-4)}
[data-role="block"]+[data-role="divider"]{margin-top:var(--sp-6)}
[data-role="block"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="block"]+[data-role="more"]{margin-top:var(--sp-3)}
[data-collapse]>*+[data-role="more"]{margin-top:var(--sp-3)}
[data-role="block"]+[data-role="row"]{margin-top:var(--sp-4)}
[data-role="block"]+[data-role="section-label"]{margin-top:var(--sp-6)}
[data-role="block"]+[data-role="toolbar"]{margin-top:var(--sp-4)}
[data-role="card"]+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="card"]+[data-role="card"]{margin-top:0}
[data-role="card"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="card"]+[data-role="more"]{margin-top:var(--sp-3)}
[data-role="card"]+[data-role="row"]{margin-top:var(--sp-4)}
[data-role="card"]+[data-role="section-label"]{margin-top:var(--sp-6)}
[data-role="divider"]+[data-role="block"]{margin-top:var(--sp-6)}
[data-role="divider"]+[data-role="section-label"]{margin-top:var(--sp-6)}
[data-role="footnote"]+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="footnote"]+[data-role="card"]{margin-top:var(--sp-4)}
[data-role="footnote"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="footnote"]+[data-role="row"]{margin-top:var(--sp-4)}
[data-role="footnote"]+[data-role="section-label"]{margin-top:var(--sp-6)}
[data-role="footnote"]+[data-role="toolbar"]{margin-top:var(--sp-4)}
[data-role="loader"]+[data-role="block"]{margin-top:var(--sp-3)}
[data-role="loader"]+[data-role="card"]{margin-top:var(--sp-3)}
[data-role="loader"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="loader"]+[data-role="row"]{margin-top:var(--sp-3)}
[data-role="more"]+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="more"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="more"]+[data-role="more"]{margin-top:var(--sp-2)}
[data-role="more"]+[data-role="row"]{margin-top:var(--sp-4)}
[data-role="more"]+[data-role="section-label"]{margin-top:var(--sp-6)}
[data-role="row"]+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="row"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="row"]+[data-role="more"]{margin-top:var(--sp-3)}
[data-role="row"]+[data-role="revealed"]{margin-top:var(--sp-2)}
[data-role="row"]+[data-role="section-label"]{margin-top:var(--sp-6)}
[data-role="section-label"]+[data-role="block"]{margin-top:var(--sp-3)}
[data-role="section-label"]+[data-role="card"]{margin-top:var(--sp-3)}
[data-role="section-label"]+[data-role="loader"]{margin-top:var(--sp-2)}
[data-role="section-label"]+[data-role="row"]{margin-top:var(--sp-3)}
[data-role="section-label"]+[data-role="subheading"]{margin-top:var(--sp-2)}
[data-role="section-label"]+[data-role="toolbar"]{margin-top:var(--sp-3)}
[data-role="subheading"]+[data-role="block"]{margin-top:var(--sp-3)}
[data-role="subheading"]+[data-role="card"]{margin-top:var(--sp-3)}
[data-role="subheading"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="subheading"]+[data-role="loader"]{margin-top:var(--sp-2)}
[data-role="subheading"]+[data-role="row"]{margin-top:var(--sp-3)}
[data-role="toolbar"]+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="toolbar"]+[data-role="card"]{margin-top:var(--sp-4)}
[data-role="toolbar"]+[data-role="footnote"]{margin-top:var(--sp-2)}
[data-role="toolbar"]+[data-role="row"]{margin-top:var(--sp-4)}
[data-role="toolbar"]+[data-role="toolbar"]{margin-top:var(--sp-2)}
/* 🔴 СЛОТ, ЯКИЙ БУВАЄ ПОРОЖНІМ, РОЗРИВАЄ `A + B`. Між тулбаром і першим підписом
   секції стоїть рендер-слот (#weekDigest), який на цій вкладці порожній: читач
   бачить пару «тулбар → підпис», а CSS-селектор `+` — ні, бо сусід у DOM є.
   Проміжок пропускається ЧЕРЕЗ такий слот. Це не виняток із таблиці — те саме
   значення пари 11, просто дотягнуте крізь порожній вузол. */
[data-role="toolbar"]+:not([data-role])+[data-role="section-label"]{margin-top:var(--sp-4)}
[data-role="toolbar"]+:not([data-role]):empty+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="toolbar"]+[data-role]:empty+[data-role="section-label"]{margin-top:var(--sp-4)}
[data-role="toolbar"]+[data-role]:empty+[data-role="block"]{margin-top:var(--sp-4)}
[data-role="section-label"]+[data-role]:empty+[data-role="block"]{margin-top:var(--sp-3)}
[data-role="block"]+[data-role]:empty+[data-role="section-label"]{margin-top:var(--sp-6)}
/* §4.6 · ПОЛОТНО ГРАФІКА МАЄ ВЛАСНУ МІНІМАЛЬНУ ВИСОТУ. Без неї картка графіка
   складається в смужку, у якій видно лише верхній підпис осі, а серії немає:
   Chart.js із maintainAspectRatio:false бере висоту від контейнера, і якщо той
   не має своєї — брати нема звідки. Мінімум із макета spacing-system §4.4. */
.chart-block{min-height:150px}
.chart-block>canvas{min-height:150px}
/* 🔴 blur тут не декор: панель кабінету лежить над фото-підкладкою героя, і
   --surface (.04) без розмиття дає ефективний контраст нижче 4.5:1 (C27). Той
   самий рецепт уже стоїть на .filters select / .tool-select — беремо його, а не
   вигадуємо другий. */
.ks-more-btn,.tl-more .tool-btn{width:auto;height:46px;background:var(--surface);color:var(--text);
  border:1px solid var(--border);box-shadow:none;
  -webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2)}
@media(hover:hover){
.ks-more-btn:hover,.tl-more .tool-btn:hover{background:var(--surface-2);color:var(--text);box-shadow:none}
}
@media(max-width:560px){
/* Мобільна сходинка та сама, що в контролів фільтра (§ тулбар ≤560: height 38px). */
.ks-more-btn,.tl-more .tool-btn{height:38px}
}
/* 2 · ОБГОРТКИ-КАРТКИ НЕ ІСНУЄ. Було: .tl-more — повноцінна картка (--surface +
   рамка + --r-3 + blur + падінг 16/20) навколо одного лічильника й однієї кнопки.
   Лишається рядок: «N із M» і кнопка, притиснуті вліво. */
.tl-more{background:none;border:none;border-radius:0;padding:0;
  -webkit-backdrop-filter:none;backdrop-filter:none;justify-content:flex-start}
/* 3 · «НАЗАД» — КАРТКА-КОНТРОЛ, А НЕ ПРИВИД. Прозорою вона не буває (§10.8).
   Скоуп — .drill-head: `ghost` лишається за «Скасувати» в модалці й формі, де
   вторинність і є задачею; тут же це навігація, і вона мусить читатись контролом. */
.drill-head .goal-btn.ghost{background:var(--surface);border:1px solid var(--border);color:var(--text);box-shadow:none;
  -webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2)}
@media(hover:hover){
.drill-head .goal-btn.ghost:hover{background:var(--surface-2);color:var(--text);box-shadow:none}
}
.charts-2col>div>*+*{margin-top:var(--sp-3)}
.field>*+*{margin-top:var(--sp-2)}
@media(max-width:560px){
.filters .per-group>select,.gran-bar .per-group>select{flex:1 1 auto;min-width:0}
.per-step{flex:0 0 38px;width:38px;height:38px}
}
@media (prefers-reduced-motion:reduce){
/* ══ BRIEF-16 §7 · C56 · ЗАПОБІЖНИК prefers-reduced-motion ═══════════════════
     Три іменні блоки вище вимикають рух точково — і саме тому кожна нова анімація
     повз них проходила: smoothModalIn, smoothBackdropIn, ksFade, skelShimmer,
     cspin/spin і ksLoadSlide лишались увімкненими у читача, який просив менше руху.
     Тут не «ще одна анімація», а її ВІДСУТНІСТЬ: тривалість у нуль і один цикл
     замість нескінченного. Точкові блоки лишаються — вони вимикають ще й
     transform/transition, чого цей загальний не робить. */
*,*::before,*::after{
      animation-duration:0s !important;
      animation-iteration-count:1 !important;
    }
}
/* ── BRIEF-17 §2.3 · КАРТКА ВІДМОВИ ДОСТУПУ (контракт §10.2) ────────────────
     Це один із ТРЬОХ порожніх станів, і виглядати він мусить інакше за «немає
     даних»: у нього є дія — піти у свій кабінет. По центру доступної висоти
     (§10.1), бо приліплений до верху блок під порожнім екраном читається як збій. */
.empty.ks-denied{display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:var(--sp-3);min-height:min(60vh,420px);text-align:center}
.ks-denied-title{font-size:var(--fs-7);font-weight:var(--fw-2);color:var(--text)}
.ks-denied-sub{font-size:var(--fs-5);color:var(--muted);max-width:46ch;line-height:var(--lh-3)}
.ks-denied-act .tool-btn{text-decoration:none;display:inline-flex;align-items:center}
/* ⚰ BRIEF-VISUAL-63D §2 · ВИРІВНЮВАННЯ ПО ВЕРХУ СКАСОВАНО 30.08.2026 —
     рішення власника, дослівно: «цифри з текстом в картках приклеєні до верхнього
     краю, а я хочу центрування».
     🔴 Правило, яке тут стояло, було ратифіковане й мало ВИМІРЯНУ причину: при
     justify-content:center значення в ряду роз'їжджались на 9px (/dispatcher →
     Заробіток) і 7px (/client → Компанія), бо картка з підрядком центрує вміст
     інакше, ніж картка без нього. Причину знято іншою правкою цієї ж хвилі:
     min-height картки піднято до 120px, тож усі картки ряду однакової висоти, а
     розпірка margin-top:auto, що штовхала підрядок донизу, більше не потрібна.
     Розбіжність базових ліній перевірено виміром у всіх чотирьох кабінетах —
     числа у звіті. Рядок контракту §10 «вміст вирівнюється по ВЕРХНЬОМУ краю»
     власник скасував; правку своєї копії DESIGN-SYSTEM.md робить він. */
.kpi, .kpis .kpi, .kpi-grid .kpi{justify-content:center}
/* 🔴 ТОКЕН ПОВЕРХУ — `--fs-2`, І ЦЕ ВИПРАВЛЕНО ВИМІРОМ. Перша редакція взяла
     `--fs-1` (9px), тобто 24.30px на два рядки. Виміряно на /dispatcher → Водії,
     430: підпис, який ПЕРЕНІССЯ насправді, має 27.00px — отже рядок підпису йде
     на `--fs-2` (10px × --lh-2 = 13.5px), а не на `--fs-1`. Різниця 2.70px між
     справжнім переносом і поверхом ділилась навпіл і давала рівно ті 1.34px, на
     яких C67 і червоніла. Тепер поверх — той самий вираз, що й слот необовʼязкового
     рядка нижче, тобто число в файлі одне, а не два. */
.kpis > .kpi .l, .kpi-grid > .kpi .l,
  .kpis > .kpi .k, .kpi-grid > .kpi .k{
    min-height:calc(2 * var(--fs-2) * var(--lh-2))}
/* Усі носії необовʼязкового рядка — ОДИН слот: однакова висота І однаковий
     верхній відступ. 🔴 Відступ у слоті обовʼязковий: перша редакція зрівняла лише
     `min-height`, а `.kpi-delta` несла ще й власний `margin-top:var(--sp-1)`, тоді
     як `.pnote` і `.s` — ні. Чотири зайві пікселі на одному з трьох носіїв — і
     розкид значень у ряду не впав, а ВИРІС з 10 до 42. Слот міряється разом із
     проміжком.
     ⚠ Слот вирівнює носіїв МІЖ СОБОЮ і більше нікого. Картці БЕЗ підрядка порожній
     резерв не додається: рішення власника 31.08.2026 «все робимо по центру»
     (BRIEF-63G §0) скасувало вимогу «значення ряду на одній лінії» разом із
     критерієм `C67`, і весь механізм резерву — клас на картці плюс класифікатор у
     `vendor/cabinet-tables.js` — знято ЦІЛКОМ, а не вимкнено. Надгробок і причина
     («класифікатор жив у `requestAnimationFrame`, а в невидимій вкладці той не
     спрацьовує, тож мовчазне неспрацювання було не відрізнити від «тут не треба»)
     — у тому ж файлі. */
.kpis > .kpi > .s, .kpis > .kpi > .kpi-delta, .kpis > .kpi > .pnote, .kpis > .kpi > .kpi-sub,
  .kpi-grid > .kpi > .s, .kpi-grid > .kpi > .kpi-delta, .kpi-grid > .kpi > .pnote, .kpi-grid > .kpi > .kpi-sub{
    min-height:calc(2 * var(--fs-2) * var(--lh-2));margin-top:var(--sp-1)}
.error-box .tool-btn{width:auto;background:transparent;color:var(--text);
    border:1px solid var(--accent-border)}
@media(hover:hover){
.error-box .tool-btn:hover{background:var(--accent-wash);color:var(--text);
      border-color:var(--accent);box-shadow:none;transform:none}
}
/* Службова назва дії лишається в розмітці лише як title — на екрані її немає. */
.ph-tag{display:none}
.kpis .kpi.net .v, .kpi-grid .kpi.net .v{color:var(--pos);font-weight:var(--fw-3)}
/* 🔴 §4 · T1 · СМУГА ВСЕРЕДИНІ КАРТКИ ЗНИКЛА. Тепер це група дій у рядку підпису
     секції: підпис ліворуч, кнопки праворуч через auto-margin. Власного падінга
     вона більше не має — відступ дає сам рядок підпису. */
.tbl-actions{display:flex;gap:var(--sp-2);margin-left:auto;flex-wrap:wrap;text-transform:none;letter-spacing:normal}
/* 🔴 ВЛАСНОГО margin-bottom РЯДОК НЕ НЕСЕ. Перша редакція §4 дописала сюди
     `margin-bottom:var(--sp-2)`, і це коштувало трьох перевірок одразу: C44
     («ритмом володіє контейнер, не елемент») × 57, C29 («зазор підпис→картка 8px,
     очікується 12») × 44 і C8 («проміжок 8px поза шкалою {12,20,32}») × 49.
     Проміжок до картки задає ПАРА «підпис → блок», як і в усіх інших підписів
     секцій; свій margin тут лише ламав спільний ритм. */
.section-label.sect-row{display:flex;align-items:center;gap:var(--sp-3)}
/* Таблиця без власного підпису (так у /client) отримує рядок ЛИШЕ з діями —
     верхній відступ той самий, що в підпису, тож ритм не збивається. */
.section-label.tbl-actions-own{min-height:32px}
@media(max-width:560px){
/* ≤560 · кнопки йдуть під підписом повним рядом, три по 1fr; підписи лишаються. */
.section-label.sect-row{flex-wrap:wrap}
.tbl-actions{width:100%;margin-left:0;display:grid;grid-template-columns:repeat(3,1fr)}
.tbl-actions .tbl-act{width:100%;justify-content:center}
}
.tbl-act{height:32px;padding:0 var(--sp-3);border-radius:var(--r-pill);background:none;border:var(--bd);color:var(--muted);font-family:inherit;font-size:var(--fs-3);font-weight:var(--fw-2);letter-spacing:var(--ls-7);cursor:pointer;white-space:nowrap;transition:background-color var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out)}
@media(hover:hover){
.tbl-act:hover{background:var(--surface);color:var(--text)}
}
.tbl-act:active{transform:translateY(1px)}
@media print{
.tbl-actions{display:none!important}
}

/* ══ 🔴 BRIEF-VISUAL-67 §3.2 крок 3 · ЛІКУЄМО ШИРИНОЮ, А НЕ ВИСОТОЮ ═══════════
 * Перший варіант цієї правки піднімав ПІДЛОГУ ВИСОТИ карток (136px у смузі
 * 561–1100). Він давав C66 = 0 і був НЕПРАВИЛЬНИЙ — це показав не смак, а сусідня
 * перевірка: C28 («порожнеча всередині НАБОРУ») почервоніла в семи місцях, бо
 * вміст найнаповненішої плитки лишався 50px у картці 104px (×2.1 при стелі ×2).
 * Тобто картка переставала бути широкою й ставала порожньою — той самий дефект
 * з іншого боку.
 *
 * 🔴 АРИФМЕТИКА, ЯКА ЦЕ ВИРІШУЄ. Дві стелі одночасно:
 *     C66:  H ≥ W / 3,0            (картка не ширша за три висоти)
 *     C28:  H ≤ 2 × вміст + падінг (картка не порожня всередині)
 *   Для набору k7 на 834 це W = 397, вміст 50, падінг 32 → потрібно H ≥ 132,3 і
 *   H ≤ 132. Вікно порожнє — на ТРИ ДЕСЯТИХ ПІКСЕЛЯ. Отже висотою цей випадок не
 *   лікується взагалі, і будь-яке «підняти ще трохи» ламало б інший критерій.
 *   Лишається ширина: вужча картка знижує C66 і НЕ додає порожнечі.
 *
 * ⚠ Тому тут лишається рівно одна підлога — для `.record-card` на широкому екрані,
 *   де вона вміст НЕ розріджує (C28 на ній зелена: вміст ~65px у картці 88px). */
 * ⚠ ПІДЛОГИ ВИСОТИ ТУТ НЕМАЄ ЖОДНОЇ, і це теж вимір, а не смак: спроба дати
 *   `.record-card` підлогу 120px на широкому екрані ПРОТЕКЛА в сусідні плитки —
 *   у `/driver → Показники` обидва набори живуть в ОДНІЙ сітці (`display:contents`,
 *   ратифіковано BRIEF-6 §6 №4), рядки рівні (`grid-auto-rows:1fr`), тож підлога
 *   рекорда підняла й плитку «Огляду», чий вміст 33px, — і C28 почервоніла на ній.
 *   Ширина такого сусідства не має: вона діє рівно на той носій, якому задана. */


/* ══════════════════════════════════════════════════════════════════════════════
   🔴 BRIEF-DEMO-01 §2 · КОМПОЗИЦІЯ КАБІНЕТУ — ПЕРЕНЕСЕНО З ІНЛАЙНУ /ceo
   ──────────────────────────────────────────────────────────────────────────────
   ЧОМУ. `/results` зібрали «на vendor» і дістали голу сторінку: у vendor були
   токени, стилі, рушій таблиць і форматер — але НЕ БУЛО КОМПОЗИЦІЇ. Сітка карток
   (.kpis + ладдери k4/k6/k7), картки рекордів, сегментований перемикач, тулбар
   періоду й сітка графіків лежали інлайном у ceo/index.html.

   ⚠ ПЕРЕДУМОВА БРИФУ (§8.2) СПРАВДИЛАСЬ ЛИШЕ НАПОЛОВИНУ. Частина родин §2.1 у
     vendor УЖЕ БУЛА: `.tbl-actions`/`.tbl-act`/`.act-ic`, `.per-step`,
     `.charts-2col`, `.section-label`/`.section-hint`, `.chart-block`/
     `.chart-note`/`.chart-sub`, `.tool-select`, `.kpi`, `.kpi-delta`.

   🔴 ТРИ ВИНЯТКИ, І ВСІ ТРИ КУПЛЕНІ ЗЛІПКОМ, А НЕ МІРКУВАННЯМ. Кожна редакція
   виносу ламала ЧУЖИЙ кабінет, і щоразу одного класу: правило /ceo, доки жило
   інлайном, до сусіда не доходило, а у vendor — почало.
     (1) 186 розбіжностей · `/client` «Компанія» 834px: картка 260,67 → 533,33px.
         Спан-хвости ЗАГАЛЬНОГО вигляду не переїжджають. Правило /ceo виключає
         лише `.k7`; /client свідомо виключає ще `.k6` і `.k8` («3 не ділить 8»).
         Переїжджає лише хвіст із ПОЗИТИВНИМ кваліфікатором (`.kpis.k7>:last-child`):
         такий не може зачепити чужий набір за побудовою. Ті, що спираються на
         ЗАПЕРЕЧЕННЯ, лишились інлайном — заперечення перелічує ЧУЖІ набори, а їх
         у кожного кабінету свій список.
     (2) 178 розбіжностей · `/driver` 430px: підпис `.kpi.work .l` 400 → 600.
         Копія з МІШАНОГО правила не експортує типографіку `.kpi`: інші кабінети
         ≤900-надбудови /ceo не мали ніколи, у них `.kpi` обслуговує сам vendor.
     (3) 262 розбіжності · `/client` `.tool-select`: зникла каретка селекта
         (background-image → none). ТЕ, ЩО У VENDOR УЖЕ Є, НЕ ПЕРЕНОСИМО ЩЕ РАЗ.
         Зіткнення (контекст, селектор) між виносом і старим vendor виявилось
         РІВНО ОДНЕ — `.tool-select` на верхньому рівні. Правило несло не
         оголошення, а ПОЗИЦІЮ серед сусідніх `.tool-select`, і в /client вона
         інша. `/results` бере базовий рецепт із того `.tool-select`, що у vendor
         був і до хвилі; /ceo лишає свої надбудови інлайном, як і було.

   🔴 ПРАВИЛО ПОДІЛУ — МЕХАНІЧНЕ: селектор із `#` лишається інлайном; усі
   селектори наші → правило переїжджає; частина наша → копіюється лише те, чий
   корінь не `.kpi`/`.kpis`, а правило лишається інлайном ЦІЛИМ.

   ⚠ ПІСЛЯ ВИНОСУ ТРИ КАБІНЕТИ СТАЛИ НОСІЯМИ ДУБЛІВ — і це зловив НЕ я, а гейт
     `visual-63 · V43` («інлайн не дублює спільний файл»), який до хвилі був
     зелений. Копії цих правил жили в `/driver`, `/client`, `/dispatcher` і
     раніше; дублями вони стали в мить, коли ті самі правила зʼявились у vendor.
     Дублі прибрано з трьох кабінетів — рівно ті, що збігаються ДОСЛІВНО
     (контекст | селектор | оголошення, розібрані CSSOM, як їх і рахує V43).

   ДОКАЗ: `smoke/style-snapshot.mjs` до/після, 106 вью × 160 294 вузли — 0
   розбіжностей у /ceo, /driver, /client, /dispatcher. Контрфакт: знято ладдер
   `.kpis.k7` на ≤1100 → 111 розбіжностей, і діф називає саме `.kpis.k7`.
   ⚠ Після правки vendor/ — `make vendor-hash` (D13).
   ══════════════════════════════════════════════════════════════════════════════ */
.record-card,
.chart-block{
    transition:transform var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out)}
@media(hover:hover){
  .record-card:hover{
      border-color:var(--accent-line);box-shadow:var(--elev-2)}
}
@media(hover:hover) and (prefers-reduced-motion:no-preference){
  .record-card:hover,
.chart-block:hover{
      transform:translateY(-2px)}
}
/* ── BRIEF-2 §3/§4 · Сегментований перемикач розрізу (.seg) — канон §2.13 ──
     НЕ .tab: вкладка (D1) — оранжева заливка + --glow-tab, перемикач навмисно тихіший,
     щоб не конкурувати з активною вкладкою в тому самому полі зору.
     Радіус 12px (--r-3), як у табів: між табами й перемикачем стоять картки
     метрик на 12px, і pill дав би три різні радіуси підряд на одному екрані.
     Сегмент — 10px (--r-2): наявна в репо пара вкладеності (капсула табів
     12px / сегмент 10px, §9.1 канону), нового токена не заводимо. */
.seg{display:inline-flex;gap:var(--sp-1);padding:var(--sp-1);background:var(--panel);
    border:1px solid var(--border);border-radius:var(--r-3);margin-bottom:var(--sp-6)}
/* 🔴 .seg — inline-flex, а margin'и inline-рівневих елементів НЕ схлопуються з
     сусідніми. Без цього рядка 32 від .seg і 32 від .section-label дають 64, а не 32:
     саме так і виникали виміряні 52px (20 + 32). Межу секції тримає ОДНА сторона. */
.seg+.section-label{margin-top:0}
.seg-btn{display:inline-flex;align-items:center;justify-content:center;height:38px;padding:0 var(--sp-4);border-radius:var(--r-2);
    background:none;border:1px solid transparent;color:var(--muted);font-family:inherit;
    font-size:var(--fs-4);font-weight:var(--fw-2);letter-spacing:var(--ls-5);white-space:nowrap;cursor:pointer;
    transition:background var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out)}
.seg-btn.active{background:var(--text);border-color:transparent;color:var(--bg)}
@media(hover:hover){
  .seg-btn:not(.active):hover{color:var(--text);background:var(--surface)}
}
@media(max-width:560px){
  .seg{display:flex;width:100%}
  .seg-btn{flex:1;justify-content:center}
}
.tool-select:focus{border-color:var(--accent-line);box-shadow:var(--ring)}
/* 🔴 §3 · P1 · ШИРИНА ЗА ПОТОЧНИМ ВМІСТОМ, А НЕ ЗА НАЙДОВШОЮ ОПЦІЄЮ.
     Прибрати кваліфікатор зі списку було НЕ ДОСИТЬ, і це вимір, а не здогад:
     `<select>` за побудовою міряє ВСІ свої опції й бере найширшу, тож контрол і далі
     стрибав би від довжини найдовшого періоду («Січень 2026» проти «Т34»). Проба
     показала це числом: після виносу кваліфікатора 120px, а з дописаною довгою
     опцією — 399px.
     `field-sizing:content` (Chromium 123+) розмірює контрол по ОБРАНІЙ опції — рівно
     те, що просить P1. Браузер без підтримки просто ігнорує рядок і лишається на
     старій поведінці; щоб і там контрол не був вужчим за звичайний період, поруч
     стоїть `min-width` — 104px, число взяте з макета (.ctl.per), не вигадане. */
.per-group select{field-sizing:content;min-width:104px;max-width:100%}
/* §7.16 · група періоду забирає вільне місце рядка (flex:1 1 auto), а звужується — сам select
     усередині; саме тому й він тепер flex:1 1 auto, а не 0 1 auto. Гранулярність (.tool-select
     поза .per-group) лишається flex:0 1 auto — рости має ЛИШЕ селектор періоду. */
.per-group{display:inline-flex;align-items:center;gap:var(--sp-2);flex-wrap:nowrap;flex:0 1 auto;margin-left:var(--sp-1)}
/* TRIPS KPI GRID — 3 cols in the left half (desktop), full-width responsive when stacked */
.kpis{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-3);align-items:stretch;align-content:stretch;grid-auto-rows:1fr;margin-bottom:var(--sp-4)}
.records-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-3);grid-auto-rows:1fr;margin-bottom:var(--sp-4)}
/* §7.17 · картка рекорду — рядок: іконка ЗЛІВА від тексту, а не над ним. Так дві картки
     лишаються поруч (2-up) навіть на 430px, бо кожна стає нижчою й вужчою за вмістом. */
.record-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-3);padding:var(--pad-16);box-shadow:var(--elev-1);-webkit-backdrop-filter:var(--blur-2);backdrop-filter:var(--blur-2);min-width:0;display:flex;gap:var(--sp-3);align-items:flex-start}
/* 🔴 §10.4 (ратифіковано 24.08.2026) · ІКОНКА НОСИТЬ КОЛІР ГОЛОВНОГО ЧИСЛА СВОЄЇ
     КАРТКИ. Було два рецепти в одному ряду: кубок оранжевий, знак долара — сірий
     (--text), а число картки — третього кольору. Тепер токен ОДИН і на іконку, і на
     .rc-val, тож розійтись їм ніяк: змінюється значення — змінюються обидва.
     Капсули-підкладки під іконкою немає й не заводиться. */
.rc-icon{flex:0 0 20px;height:20px;margin-top:var(--optical);margin-bottom:0;display:flex;align-items:center;color:var(--accent)}
.rc-icon svg{width:20px;height:20px}
/* §7.17 · текстова колонка картки — щоб іконка стояла ПОРУЧ зі стовпчиком, а не з першим рядком */
.rc-body{display:flex;flex-direction:column;min-width:0}
/* R1 · inline line-icons in the main site's convention (currentColor, round caps) */
.rc-label{font-size:var(--fs-1);color:var(--muted);text-transform:uppercase;letter-spacing:var(--ls-4)}
.rc-val{font-family:'Arimo',sans-serif;font-size:var(--fs-5);font-weight:var(--fw-2);color:var(--accent);word-break:break-word}
/* §7.17 · overflow-wrap:anywhere замість word-break:break-all — рве лише коли рядок
     справді не влазить, а не посеред кожного слова */
.rc-sub{font-size:var(--fs-3);color:var(--muted);overflow-wrap:anywhere}
/* BRIEF-6 §2 (ред. 20.08) · шкала {12·20·32} з наявних токенів */
.charts-2x2{grid-auto-rows:1fr}
/* §1.1 · EQUAL-HEIGHT cards in every 2-col row. The grid cell already stretches (grid default);
     force the VISIBLE card (.chart-block) to fill that cell so a longer/shorter chart-note can never
     leave one card taller than its row-mate. .chart-full absorbs the slack so the chart fills too. */
.records-grid{align-items:stretch}
@media(max-width:1100px){
  .kpis{grid-template-columns:repeat(4,1fr)}
}
@media(max-width:860px){
  .kpis{grid-template-columns:repeat(3,1fr)}
  .records-grid{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:560px){
  .kpis{grid-template-columns:repeat(2,1fr)}
  .kpis{align-items:stretch}
}
/* §7.16 · рядок [гранулярність][період][дії] — одна лінія (перенос лише ≤560px, блок у кінці style-блока) */
.gran-bar{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:nowrap;margin-bottom:var(--sp-4)}
/* В9 · блок кнопок дій у ряду панелі періоду. Механізм — auto-margin.
   §7.16 · тепер обгортку носить і ОДИНОЧНА кнопка «+ Витрата» у profitBar: інлайн-стиль
   style="margin-left:auto" звідти прибрано, бо інлайн б'є ≤560px-правило й не давав
   кнопці розтягнутись на власний рядок. Один носій механізму на всі випадки. */
.gran-actions{display:flex;align-items:center;gap:var(--sp-3);margin-left:auto}
/* Overview: 8 metrics — 2 rows × 4 on desktop, 4 rows × 2 on mobile */
.chart-full{position:relative;width:100%;height:300px;margin-top:var(--sp-3)}
.chart-full canvas{width:100%!important;height:100%!important}
@media(max-width:860px){
  .chart-full{height:230px}
}
.records-grid.r3{grid-template-columns:repeat(3,1fr)}
@media(max-width:767px){
  .records-grid.r3{grid-template-columns:1fr}
}
.kpi .kpi-delta{margin-top:var(--sp-1)}
/* §7.15 · сходинка колонок мусить ДІЛИТИ набір: карток тут 4, тож рунг 860→3 прибрано
   (3 не ділить 4 і давав ряд 3+1). Лишається 4 → ≤560px 2. */
.kpis.k4{grid-template-columns:repeat(4,1fr)}
@media(max-width:560px){
  .kpis.k4{grid-template-columns:repeat(2,1fr)}
}
.kpis.k6{grid-template-columns:repeat(6,1fr)}
@media(max-width:1100px){
  .kpis.k6{grid-template-columns:repeat(4,1fr)}
}
@media(max-width:860px){
  .kpis.k6{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:560px){
  .kpis.k6{grid-template-columns:repeat(2,1fr)}
}
/* §7.15 · рунг 860→3 прибрано: 3 не ділить 14 (виходило 4 ряди по 3 + хвіст 2).
   Лишається 7 → ≤1100px 4 → ≤560px 2; хвіст 14 mod 4 = 2 добирає tail-span (див. .kpis вище). */
.kpis.k7{grid-template-columns:repeat(7,1fr);grid-auto-rows:1fr}
@media(min-width:561px) and (max-width:1100px){
  .kpis.k7{grid-template-columns:repeat(3,1fr)}
  .kpis.k7>:last-child{grid-column:span 2}
}
@media(max-width:560px){
  .kpis.k7{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:560px){
  .kpis.k7{grid-template-columns:repeat(2,1fr)}
}
/* KPI delta on the compact .kpi tiles (Companies) — reuse the digest colours */
.kpi .kpi-delta{margin-top:var(--sp-1)}
/* Companies "records" — two cards side by side (best period · top company).
   §7.17 · рунг ≤560px→1 колонка ПРИБРАНО: дві картки лишаються поруч на ВСІХ ширинах —
   іконка тепер стоїть збоку від тексту (.rc-body), тож картка влазить у півширини 430px. */
.records-grid.r2{grid-template-columns:repeat(2,1fr)}
@media(min-width:561px){
  .records-grid,.records-grid.r2,.records-grid.r3{grid-template-columns:repeat(auto-fit,minmax(180px,230px))}
}
/* §2.1 · фінальна сума всередині картки KPI (картка одна з чотирьох, тому
   колір ставиться на значення, а не на всю сітку). */
.kpi .v .kpi-final{color:var(--pos);font-weight:var(--fw-3)}
@media print{
  .gran-bar,
.gran-actions,
.chart-block{display:none!important}
  .record-card{background:var(--print-bg)!important;border:1px solid var(--print-rule)!important;box-shadow:none!important;-webkit-backdrop-filter:none!important;backdrop-filter:none!important}
  .record-card .rc-label,
.section-label,
.section-hint{color:var(--print-muted)!important}
  .record-card .rc-val{color:var(--print-ink)!important}
}
@media(max-width:900px){
  .section-hint{margin:0 var(--optical) var(--sp-3)}
  .records-grid,
.charts-2col{margin-bottom:var(--sp-4)}
  .chart-full{height:auto!important;aspect-ratio:1.3}
  .chart-block>canvas{width:100%!important;aspect-ratio:1.3;height:auto!important}
  .rc-label{font-size:var(--fs-2);font-weight:var(--fw-2);letter-spacing:var(--ls-4)}
}
@media(max-width:560px){
  .gran-bar{flex-wrap:wrap}
  .gran-bar>.tool-select{flex:0 1 auto}
  .gran-bar>.per-group{flex:1 1 0}
  .gran-actions{margin-left:0;width:100%;flex-basis:100%}
  .per-group{flex:1 1 0;min-width:0}
  .per-group>select,.per-group>.tool-select{flex:1 1 auto;min-width:0}
}
@media(max-width:560px){
  .gran-bar{flex-wrap:wrap;justify-content:flex-start;gap:var(--sp-2)}
  .gran-bar .per-group{order:2;margin-left:0;flex:0 0 auto}
  .gran-bar .gran-actions{order:3}
  .gran-bar select,
.tool-select{
    flex:0 0 auto;min-width:0;max-width:100%;width:auto}
  .per-group>select,.per-group>.tool-select{flex:0 0 auto;min-width:0;width:auto}
  .gran-bar select,
.tool-select,
.per-group>select{height:38px}
}
@media(max-width:560px){
  .gran-bar>select{flex:1 1 0;min-width:0;width:auto}
  .gran-bar .per-group{display:flex;flex:1 1 100%;min-width:0;gap:var(--sp-2)}
  .gran-bar{gap:var(--sp-2)}
}
/* 🔴 BRIEF-VISUAL-63D §6.1 · ЗАЛИВКА Й РАМКА ЗНЯТІ, ЗЕЛЕНЕ ЛИШЕ ЧИСЛО.
     Макет 63D тримає підсумок на ЗВИЧАЙНІЙ поверхні картки (`.kpi` :117), а
     `.kpi.net` у ньому перевизначає РІВНО дві речі — кегль і колір числа (:130-131).
     Один рецепт на продукт лишається: те саме знято в решті трьох кабінетів.
     ⚠ Звичайна картка в продукті стоїть на `--border` (`.kpi` :645), у макеті —
     на `--border-hair`. Зрівняно ПІДСУМОК ІЗ ЗВИЧАЙНОЮ КАРТКОЮ цього кабінету,
     а не перетокенізовано рамку всіх карток продукту: друге — інша, незамовлена
     правка, яка зачепила б кожну картку в чотирьох кабінетах. */
.kpis .kpi.net .v .kpi-final{color:inherit;font-weight:inherit}


/* 🔴 BRIEF-DEMO-02 §2.6 (Д6) · SUBGRID — ЦЕ ПАРА, І БЕЗ БАТЬКА ВОНА ШКОДИТЬ.
   Дитина (`.charts-2col>div`) жила у vendor, батько (`.charts-2col{grid-auto-rows:auto}`)
   лишався інлайном у ceo/index.html. Без батьківської половини діє
   `.charts-2x2{grid-auto-rows:1fr}` — шість РІВНИХ треків замість треків по
   вмісту. Виміряно на /results «Динаміка»: комірка 670×942px при вмісті 862px.

   🔴 ПОЗИЦІЯ ЦЬОГО БЛОКА — В КІНЦІ ФАЙЛА, І ЦЕ НЕ ОФОРМЛЕННЯ. `.charts-2col` і
   `.charts-2x2` мають ОДНАКОВУ специфічність (0,1,0) і обидва стоять на тому
   самому вузлі (`class="charts-2col charts-2x2"`), тож виграє той, хто нижче.
   Перша спроба поставила пару поруч із дитиною — і `.charts-2x2{grid-auto-rows:1fr}`
   із блоку DEMO-01 нижче переміг: комірка лишилась 942px. Інлайн /ceo вигравав
   саме тим, що був останнім; тут ту саму позицію відтворює кінець файла.

   ⚠ `@media(min-width:561px)` — НЕ зайве. На ≤560 батько має display:flow-root,
     тобто гридом не є; `grid-template-rows:subgrid` у дитини стає невалідним і
     деградує до `none`, а дитина лишається display:grid і роздає треки сама — у
     /ceo це виганяло 133px графіка за нижній бордер картки. Переносити без цього
     запиту (як пропонує сніпет §2.6 брифу) означало б полагодити /results і
     зламати /ceo на 430. */
@media(min-width:561px){
@supports (grid-template-rows: subgrid){
.charts-2col{grid-auto-rows:auto}
.charts-2col>div{display:grid;grid-template-rows:subgrid;grid-row:span 3}
}
}

/* 🔴 BRIEF-DEMO-02 §2.5 (Д5) · ДРУГА ПОЛОВИНА ПАРИ `.p-table th` / `.p-table td`.
   `th` жив у vendor, `td` лишався інлайном у ceo/index.html — і сторінка, що бере
   таблицю з vendor і не має власної копії, діставала шапку з відступами й тіло
   БЕЗ НИХ. Виміряно на /results: `th` → padding 16px 20px, `td` → padding 0px,
   border-bottom 0px. Рядки злипались, роздільників не було.

   🔴 ПОЗИЦІЯ — В КІНЦІ ФАЙЛА, І ЦЕ ВИМІР. Поруч із `th` воно змінювало
   `border-bottom-color` у `/client` → P&L → `tr.pnl-edit > td.pnl-edit-cell`
   (rgba(248,248,248,.08) → rgb(248,248,248)) на чотирьох ширинах: інлайнова копія
   /client стояла ПІЗНІШЕ за vendor і вигравала нічию, а вставка в середину файла
   переставила порядок серед рівних. У кінці файла копія відтворює ту саму
   позицію, яку правило мало інлайном, — і чужі кабінети лишаються недоторканими.
   ⚠ `.p-table tr:last-child td` має вищу специфічність (0,1,2 проти 0,1,1), тож
     «останній рядок без роздільника» від цього переїзду не залежить узагалі. */
.p-table td{padding:var(--pad-16) var(--sp-4);border-bottom:1px solid var(--border-hair);color:var(--text);white-space:nowrap;vertical-align:middle}

/* 🔴 Д5 · КОМПАКТНІ ВІДСТУПИ МУСЯТЬ СТОЯТИ ПІСЛЯ БАЗОВОГО `.p-table td`.
   Знайдено зліпком під час V43, і це дефект ЦІЄЇ Ж ХВИЛІ, а не старий.
   §2 переніс базовий `.p-table td{padding:16px 20px}` у КІНЕЦЬ файла (щоб не
   переставити каскад чужим кабінетам), а компактний override для ≤860 лишився
   на рядку 475 — тобто ВИЩЕ. Специфічність у них однакова (0,1,1), отже на
   вузьких виграв базовий, і клітинки діставали 16/20 замість 12/14.
   У driver/client/dispatcher це маскували їхні власні інлайнові копії, що стояли
   в правильному порядку; у /ceo, з якого копії зняв DEMO-01, дефект уже живий.
   Виміряно: driver@430 TR.tl-total>TD.num padding 12px/14px → 16px/20px.
   Тому override переїжджає СЮДИ, нижче за базове правило. */
@media(max-width:860px){
.p-table th,.p-table td{padding:var(--sp-3) var(--pad-14)}
}

/* ══ 🔴 ОБХІД 14.09.2026 · ДВІ ВАДИ ШАПКИ НА ТЕЛЕФОНІ ════════════════════════
 * Обидві знайдені не гейтом, а виміром намальованого: проба, що порівнює
 * ПРЯМОКУТНИКИ, їх не бачила — текст витікав за свій прямокутник і малювався
 * поверх сусіда. Урок записаний: rect ≠ чорнило.
 *
 * 1 · ЛОГОТИП МАЛЮВАВСЯ ПОВЕРХ АВАТАРА. `.header .logo` має `min-width:0`
 *     (потрібне для флексу) і `overflow:visible`, тож при тисняві він
 *     стискався НИЖЧЕ вмісту, а текст лишався намальованим на повну.
 *     Виміряно: потрібно 118px, дістається 69px на 375. Накладання — на
 *     360 · 375 · 390 · 414 у чотирьох кабінетах; це iPhone SE/mini й більшість
 *     Android. На 430 (ратифікована ширина) тисняви ще немає.
 *     Лікування — ратифікований прийом адаптивного лого: нижче 430 лишається
 *     сам знак, слова ховаються. Бренд на екрані лишається, зіткнення немає.
 *     `overflow:hidden` — запобіжник: ніяка майбутня тиснява вже не намалює
 *     текст поза власною коробкою.
 *
 * 2 · ПІДПИСИ ВКЛАДОК ОБРІЗАЛИСЬ УСЕРЕДИНІ ВЛАСНОЇ КНОПКИ. `.tab{flex:1}`
 *     ділить ряд порівну незалежно від довжини слова, а `.tab-lbl{min-width:0}`
 *     дозволяє слову стиснутись до обрізу. Виміряно на 430: «Breakdown» −15px,
 *     «Dynamics» −7px, «Performance» −5px; на 375 «Performance» −24px.
 *     Прокрутка ряду цього не рятує — обрізана сама кнопка.
 *     Нижче 560 вкладка міряється вмістом, а ряд і далі прокручується
 *     (`.tabs` вже має overflow-x:auto). Рівний ряд на широкому лишається. */
.header .logo{overflow:hidden}
@media(max-width:429px){
  .header .ks-logo-words{display:none}
}
@media(max-width:560px){
  .tabs{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .tabs::-webkit-scrollbar{display:none}
  .tabs .tab{flex:0 0 auto}
  .tab .tab-lbl{min-width:auto;white-space:nowrap}
}
