* { box-sizing: border-box; }

body {
    font-family: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background: #0e1116;
    color: #e6ebf2;
    margin: 0;
    min-height: 100vh;
    min-height: 100dvh;
}

/* Типове посилання. Без цього правила будь-який <a> поза стилізованим блоком
   малюється браузером: синій, фіолетовий після відвідування, підкреслений. */
a { color: #8fa8ff; text-decoration: none; }
a:hover { text-decoration: underline; }

body.narrow {
    display: flex;
    align-items: center;
    justify-content: center;
}

body.wide .container {
    max-width: 1100px;
    padding: 24px;
    margin: 0 auto;
}

body.fullscreen { display: block; }
body.fullscreen .container {
    max-width: none;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    padding: 0;
    display: flex;
    flex-direction: column;
}
body.fullscreen main { flex: 1; min-height: 0; }

.container {
    width: 100%;
    max-width: 420px;
    padding: 24px;
}

header h1 {
    text-align: center;
    margin: 0 0 24px;
    font-weight: 600;
    letter-spacing: 0.5px;
    color: #eef2f7;
}

/* ── Dropdown меню ─────────────────────────────────────────── */
.dropdown {
    position: relative;
    display: inline-block;
}
.dropdown-toggle {
    background: none;
    color: #8fa8ff;
    padding: 0;
    margin: 0;
    border: none;
    font-size: 14px;
    cursor: pointer;
    font-family: inherit;
    display: flex;
    align-items: center;
    gap: 6px;
}
.dropdown-toggle:hover { text-decoration: underline; }
.dropdown-toggle::after {
    content: "⌄";
    font-size: 12px;
    transition: transform 0.2s;
}
.dropdown.active .dropdown-toggle::after {
    transform: rotate(180deg);
}
.dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    background: #151b23;
    border: 1px solid #28313d;
    border-radius: 8px;
    min-width: 160px;
    padding: 8px 0;
    margin-top: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    z-index: 1000;
    display: none;
}
.dropdown.active .dropdown-menu {
    display: block;
}
.mode-badge {
    margin: 0;
    padding: 3px 10px 3px 8px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.5px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: filter .15s;
    width: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    line-height: 1;
}
.mode-badge::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    flex: none;
    box-shadow: 0 0 6px currentColor;
}
.mode-badge:hover { filter: brightness(1.15); }
.mode-badge:disabled { opacity: 0.6; cursor: progress; }
.mode-production .mode-badge::before, .mode-badge.mode-production::before { animation: mode-pulse 2s ease-in-out infinite; }
@keyframes mode-pulse {
    0%, 100% { box-shadow: 0 0 6px currentColor; }
    50%      { box-shadow: 0 0 12px currentColor; }
}
.mode-production {
    background: rgba(22, 163, 74, 0.15);
    color: #4ade80;
    border-color: rgba(22, 163, 74, 0.4);
}
.mode-dev {
    background: rgba(245, 158, 11, 0.15);
    color: #fbbf24;
    border-color: rgba(245, 158, 11, 0.4);
}
.inline-logout { margin: 0; display: inline; }
.inline-logout button.link {
    background: none;
    color: #f87171;
    padding: 0;
    width: auto;
    border: 0;
    font-size: 14px;
    margin: 0;
    cursor: pointer;
}

.card {
    background: #151b23;
    border: 1px solid #28313d;
    border-radius: 12px;
    padding: 28px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}

.card h2 {
    margin: 0 0 20px;
    font-weight: 500;
}

label {
    display: block;
    margin-bottom: 16px;
    font-size: 14px;
    color: #8a96a6;
}

input[type="text"], input[type="password"], input[type="number"], input[type="email"], select {
    margin-top: 6px;
    padding: 10px 12px;
    background: #0e1116;
    border: 1px solid #28313d;
    border-radius: 8px;
    color: #e6ebf2;
    font-size: 15px;
}

/* ШИРИНА полів — окремим правилом і з `:not([class*="u-w-"])`.
   Аудит 07.09 P1-4: атрибутний селектор `input[type="number"]` важить (0,1,1),
   а клас-утиліта `.u-w-80px` — лише (0,1,0). Тож підключення utilities.css
   ОСТАННІМ нічого не міняло: 64 поля у 8 шаблонах діставали 100%/auto замість
   заданої класом ширини (числове поле кадрування виміряно 232px замість 80px —
   і на 320px сторінка video_detail їхала вбік). Знімаємо вагу з елементного
   правила, а не піднімаємо її в утилітах: інакше капкан повернеться з наступним
   селектором. `select` лишається без `:not` — його вага (0,0,1) і так нижча.
   Решта декларацій групи вище лишається на ВСІХ полях: `:not` тут стосується
   виключно ширини. */
input[type="text"]:not([class*="u-w-"]),
input[type="password"]:not([class*="u-w-"]),
input[type="email"]:not([class*="u-w-"]),
select { width: 100%; }

input[type="number"]:not([class*="u-w-"]) { width: auto; }

input:focus { outline: none; border-color: #6d8dff; }

button, .button-link {
    display: inline-block;
    padding: 11px 16px;
    background: linear-gradient(135deg, #6d8dff, #5570e8);
    color: white;
    border: none;
    border-radius: 9px;
    font-size: 15px;
    font-weight: 500;
    cursor: pointer;
    margin-top: 8px;
    text-decoration: none;
}

button:hover, .button-link:hover { background: linear-gradient(135deg, #7c99ff, #6280f2); }

button.secondary { background: #3a4656; }
button.secondary:hover { background: #28313d; }

button.link {
    background: none;
    color: #8fa8ff;
    padding: 0;
    margin: 0;
    width: auto;
    border: 0;
    font-size: 13px;
    cursor: pointer;
}
button.link.danger { color: #f87171; }

.muted { color: #8a96a6; font-size: 13px; }
.muted a { color: #8fa8ff; text-decoration: none; }

.flashes { list-style: none; padding: 0; margin: 0 0 16px; }
.flash { padding: 10px 14px; border-radius: 8px; margin-bottom: 8px; font-size: 14px; }
.flash-error { background: #7f1d1d; color: #fecaca; border: 1px solid #991b1b; }
.flash-success { background: #14532d; color: #bbf7d0; border: 1px solid #166534; }

/* ── Модуль повідомлень: дзвіночок, toast-и, модалки ─────────────────── */
.notif-bell { position: relative; display: inline-flex; align-items: center; }
.notif-badge {
    position: absolute; top: -8px; right: -10px;
    min-width: 17px; height: 17px; padding: 0 4px;
    border-radius: 9px; background: #dc2626; color: #fff;
    font-size: 11px; line-height: 17px; text-align: center; font-weight: 600;
    display: none;
}
.notif-badge.show { display: block; }

/* Лічильник відкритих знахідок безпеки на іконці «радар» у бічній панелі.
   Свій клас, а не .notif-badge: сповіщення шукають свій бейдж через
   querySelector(".notif-badge") і забрали б чужий. */
.sec-badge {
    position: absolute; top: -8px; right: -10px;
    min-width: 17px; height: 17px; padding: 0 4px;
    border-radius: 9px; background: #b45309; color: #fff;
    font-size: 11px; line-height: 17px; text-align: center; font-weight: 600;
    display: none;
}
.sec-badge.show { display: block; }
.sec-badge.is-critical { background: #dc2626; }

/* Лічильник відкритих звітів про помилки на іконці «жук» у бічній панелі.
   Видимість — лише через .u-d-none (Sky.setShown із живих лічильників), тому
   без власного display:none/.show, на відміну від .sec-badge. */
.bug-badge {
    position: absolute; top: -8px; right: -10px;
    min-width: 17px; height: 17px; padding: 0 4px;
    border-radius: 9px; background: #2563eb; color: #fff;
    font-size: 11px; line-height: 17px; text-align: center; font-weight: 600;
    display: block;
}

.toast-stack {
    position: fixed; top: 16px; right: 16px; z-index: 9999;
    display: flex; flex-direction: column; gap: 10px;
    max-width: 360px; pointer-events: none;
}
.toast {
    pointer-events: auto;
    background: #151b23; color: #e6ebf2;
    border: 1px solid #28313d; border-left-width: 4px;
    border-radius: 8px; padding: 12px 14px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
    font-size: 14px; opacity: 0; transform: translateX(20px);
    transition: opacity .25s ease, transform .25s ease;
}
.toast.show { opacity: 1; transform: translateX(0); }
.toast .toast-title { font-weight: 600; margin-bottom: 3px; }
.toast--info { border-left-color: #8fa8ff; }
.toast--success { border-left-color: #34d399; }
.toast--warning { border-left-color: #f59e0b; }
.toast--error { border-left-color: #ef4444; }

.modal-backdrop {
    position: fixed; inset: 0; z-index: 10000;
    background: rgba(2, 6, 23, 0.7);
    display: flex; align-items: center; justify-content: center; padding: 20px;
}
.modal-card {
    background: #0e1116; color: #e6ebf2;
    border: 1px solid #28313d; border-top-width: 4px;
    border-radius: 12px; padding: 22px 24px;
    max-width: 520px; width: 100%;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
.modal-card.level-info { border-top-color: #8fa8ff; }
.modal-card.level-success { border-top-color: #34d399; }
.modal-card.level-warning { border-top-color: #f59e0b; }
.modal-card.level-error { border-top-color: #ef4444; }
.modal-card h3 { margin: 0 0 12px; font-size: 18px; }
.modal-card .modal-body { white-space: pre-wrap; line-height: 1.5; font-size: 15px; }
.modal-card .modal-meta { color: #8a96a6; font-size: 12px; margin-top: 14px; }
.modal-card .modal-actions { margin-top: 18px; display: flex; justify-content: flex-end; gap: 10px; }
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 9px 16px; border-radius: 8px; font-size: 14px; cursor: pointer;
    background: #28313d; color: #e6ebf2; border: 1px solid #3a4656; text-decoration: none;
}
.btn:hover { background: #3f4d63; }
.btn.primary { background: #6d8dff; border-color: #6d8dff; color: #fff; }
.btn.primary:hover { background: #5570e8; }
.btn.danger { background: #ef4444; border-color: #ef4444; color: #fff; }
.btn.danger:hover { background: #dc2626; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Модалка незворотного видалення тренування (/training) */
.modal-body.del-impact { white-space: normal; }
.del-impact .del-group { border-radius: 8px; padding: 10px 12px; margin: 12px 0; }
.del-impact .del-danger { background: rgba(239, 68, 68, 0.08); border: 1px solid rgba(239, 68, 68, 0.35); }
.del-impact .del-affect { background: rgba(245, 158, 11, 0.08); border: 1px solid rgba(245, 158, 11, 0.30); }
.del-impact .del-head { font-weight: 600; margin-bottom: 6px; }
.del-impact ul { margin: 4px 0 0; padding-left: 20px; }
.del-impact ul ul { margin: 4px 0; }
.del-impact li { margin: 2px 0; }
.del-impact .del-blocked { color: #fca5a5; font-weight: 600; }
.del-impact .del-confirm-label { margin: 14px 0 6px; }
.del-impact .del-confirm-input {
    width: 100%; padding: 8px 10px; border-radius: 8px;
    background: #10161e; color: #e6ebf2; border: 1px solid #3a4656; font-size: 14px;
}
.toast .toast-action {
    display: inline-block; margin-top: 8px; font-size: 13px; font-weight: 600;
    color: #8fa8ff; text-decoration: none;
}
.toast .toast-action:hover { text-decoration: underline; }

/* закріплення відео (на сторінці відео, для адміна/менеджера) */
.assign-box {
    border: 1px solid #242e3a; border-radius: 10px;
    padding: 12px 14px; margin: 12px 0; background: #111827;
}
.assign-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap; margin-bottom: 10px; font-weight: 600;
}
.assign-head .small { font-weight: 400; }
.assign-controls { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.assign-controls select { width: auto; min-width: 240px; margin: 0; }

/* Бейджі датасетів, до яких закріплене відео (на сторінці відео). */
.ds-badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 8px; background: #151b23; border: 1px solid #28313d;
    border-radius: 6px; font-size: 13px;
}
.ds-badge a { text-decoration: none; color: #8fa8ff; }
.ds-badge a:hover { text-decoration: underline; }
.ds-remove {
    background: none; border: none; color: #f87171; cursor: pointer;
    font-size: 13px; line-height: 1; padding: 0 2px;
}
.ds-remove:hover { color: #ef4444; }

/* інбокс */
.notif-page { max-width: 760px; margin: 0 auto; }
.notif-list { list-style: none; padding: 0; margin: 0; }
.notif-item {
    border: 1px solid #242e3a; border-left-width: 4px;
    border-radius: 10px; padding: 14px 16px; margin-bottom: 10px; background: #111827;
}
.notif-item.level-info { border-left-color: #8fa8ff; }
.notif-item.level-success { border-left-color: #34d399; }
.notif-item.level-warning { border-left-color: #f59e0b; }
.notif-item.level-error { border-left-color: #ef4444; }
.notif-item.unread { background: #18233a; }
.notif-item-head { display: flex; align-items: center; gap: 10px; }
.notif-item .notif-title { font-weight: 600; font-size: 15px; }
.notif-item .notif-body { margin-top: 4px; line-height: 1.5; white-space: pre-wrap; }
.notif-item .notif-meta {
    color: #8a96a6; font-size: 12px; margin-top: 10px;
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}

.notif-pager {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; margin-top: 16px;
}

/* композер повідомлень */
.compose-form fieldset {
    border: 1px solid #242e3a; border-radius: 10px;
    padding: 12px 16px 16px; margin: 0 0 18px;
}
.compose-form legend { padding: 0 6px; color: #8a96a6; font-size: 13px; }
.compose-form .radio-row {
    display: flex; align-items: center; gap: 8px;
    margin: 8px 0; font-size: 14px; color: #e6ebf2; cursor: pointer;
}
.compose-form .radio-row input { width: auto; margin: 0; }
.compose-form select.indent { margin: 0 0 8px 26px; width: calc(100% - 26px); }
.compose-form select[multiple] { height: auto; }
.compose-form .dim { opacity: .45; }
.compose-form textarea {
    width: 100%; margin-top: 6px; padding: 10px 12px;
    background: #0e1116; border: 1px solid #28313d; border-radius: 8px;
    color: #e6ebf2; font-size: 15px; font-family: inherit; resize: vertical;
}
.compose-form textarea:focus { outline: none; border-color: #6d8dff; }
.compose-row { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 14px; }
.compose-field { flex: 1; min-width: 200px; margin-bottom: 14px; }
.compose-field > label { display: block; color: #8a96a6; font-size: 13px; }
.compose-field input, .compose-field select { margin-top: 6px; }
.compose-actions { margin-top: 6px; }

/* breadcrumb */
.breadcrumb {
    list-style: none;
    margin: 0 0 16px;
    padding: 8px 14px;
    background: #151b23;
    border: 1px solid #242e3a;
    border-radius: 8px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 13px;
    align-items: center;
}
.breadcrumb li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: #8a96a6;
}
.breadcrumb li + li::before {
    content: "›";
    color: #3a4656;
    margin: 0 2px;
}
.breadcrumb a { color: #8fa8ff; text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb .current { color: #e6ebf2; font-weight: 500; }
body.fullscreen .breadcrumb {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    margin: 0;
    background: #10161e;
}

/* dashboard */
.dash-hero {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px;
    background: linear-gradient(135deg, #151b23 0%, #0e1116 100%);
    border: 1px solid #28313d;
    border-radius: 14px;
    padding: 24px 28px;
    margin-bottom: 20px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
.dash-hero-text h2 { margin: 0 0 4px; font-size: 24px; }
.dash-hero-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.button-link.primary { background: #6d8dff; }
.button-link.primary:hover { background: #5570e8; }

.stat-label { color: #8a96a6; font-size: 13px; }

.dash-cols {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr));
    gap: 16px;
    margin-bottom: 20px;
}
.dash-col { padding: 20px 22px; }
/* /test-model master-detail: вузька колонка списку + гнучка деталь.
   Перекриває рівні колонки .dash-cols; min-width:0 + overflow-x не дають
   широкій таблиці історії розпирати сторінку (CSS-grid blowout). */
.tm-cols { grid-template-columns: minmax(min(220px, 100%), 300px) 1fr; align-items: start; }
.tm-cols > .dash-col { min-width: 0; }
#model-detail { overflow-x: auto; }
@media (max-width: 720px) { .tm-cols { grid-template-columns: 1fr; } }
.card-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 14px;
}
.card-head h3 { margin: 0; font-size: 16px; font-weight: 500; }
.card-head a.muted { font-size: 13px; }

.logout-bottom { text-align: center; margin-top: 12px; }
.logout-bottom button { width: auto; min-width: 120px; }

/* videos list */
.upload-form { display: flex; align-items: end; gap: 12px; margin-bottom: 12px; }
.upload-form label { flex: 1; margin-bottom: 0; }
.dropzone {
    flex: 1;
    border: 2px dashed #3a4656;
    border-radius: 10px;
    padding: 24px;
    text-align: center;
    color: #8a96a6;
    cursor: pointer;
    transition: border-color .15s, background .15s;
    margin-bottom: 0;
    background: #10161e;
}
.dropzone:hover, .dropzone.hover {
    border-color: #6d8dff;
    background: rgba(59, 130, 246, 0.08);
    color: #c6d0de;
}
.dropzone.error {
    border-color: #ef4444;
    background: rgba(239, 68, 68, 0.08);
    color: #fecaca;
}
.dropzone input[type="file"] { display: none; }

#upload-progress {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    padding: 10px 14px;
    background: #10161e;
    border: 1px solid #242e3a;
    border-radius: 8px;
}
#upload-progress progress { flex: none; width: 240px; }
#upload-text { font-weight: 500; }
#upload-info { font-size: 12px; }
.videos-table { width: 100%; border-collapse: collapse; margin-top: 12px; }
.videos-table th, .videos-table td { text-align: left; padding: 10px; border-bottom: 1px solid #28313d; }
.videos-table th { color: #8a96a6; font-weight: 500; font-size: 13px; }
.badge { padding: 3px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 700; background: #232c38; }
.badge-ready { background: #14532d; color: #bbf7d0; }
.badge-extracting { background: #1e3a8a; color: #c9d6ff; }
.badge-failed { background: #7f1d1d; color: #fecaca; }
.badge-uploaded { background: #3a4656; }
.inline { display: inline-block; margin: 0; }

/* ---- Videos list page ("Ваші відео") polish ---- */
/* White section heading */
.card:has(#upload-form) > h2 { color: #ffffff; }

/* Filename / frame links — light text, padded pill, soft light hover */
.card:has(#upload-form) .videos-table td a {
    display: inline-block;
    color: #e8edf3;
    font-weight: 500;
    text-decoration: none;
    padding: 3px 9px;
    border-radius: 7px;
    transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.card:has(#upload-form) .videos-table td a:hover {
    background: rgba(186, 199, 218, 0.16);
    color: #ffffff;
    box-shadow: inset 0 0 0 1px rgba(186, 199, 218, 0.22);
}
.card:has(#upload-form) .videos-table td a:active {
    background: rgba(186, 199, 218, 0.26);
}
.card:has(#upload-form) .videos-table td a:focus-visible {
    outline: 2px solid #8fa8ff;
    outline-offset: 1px;
}

/* video detail */
.video-player {
    background: #000;
    border-radius: 10px;
    overflow: hidden;
    margin: 0 0 20px;
    max-height: 60vh;
    display: flex;
    justify-content: center;
}
.video-player video {
    width: 100%;
    max-height: 60vh;
    display: block;
    background: #000;
}

.extract-form { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 12px 0; }
.extract-form label { display: inline-flex; align-items: center; gap: 6px; margin: 0; }

/* ── grouped toolbar (video detail) ── */
.toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 14px;
    margin: 18px 0 6px;
}
.toolbar-group {
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px;
    background: #0e1116;
    border: 1px solid #242e3a;
    border-radius: 12px;
}
.toolbar-group[data-label]::before {
    content: attr(data-label);
    position: absolute;
    top: -9px;
    left: 12px;
    padding: 0 6px;
    background: #0e1116;
    color: #71809a;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    border-radius: 4px;
    pointer-events: none;
}
.tbtn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 14px;
    background: #151b23;
    color: #e6ebf2;
    border: 1px solid #28313d;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.1;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    margin: 0;
    transition: background .12s, border-color .12s, transform .05s, box-shadow .12s;
}
.tbtn:hover { background: #273449; border-color: #6d8dff; box-shadow: 0 2px 10px rgba(59,130,246,.15); }
.tbtn:active { transform: translateY(1px); }
.tbtn:disabled { opacity: .5; cursor: not-allowed; box-shadow: none; transform: none; }
.tbtn .tico { font-size: 16px; line-height: 1; }
.tbtn.primary { background: #5570e8; border-color: #5570e8; color: #fff; }
.tbtn.primary:hover { background: #4a63d8; border-color: #4a63d8; }
.tbtn.danger { background: #7f1d1d; border-color: #991b1b; color: #fecaca; }
.tbtn.danger:hover { background: #991b1b; border-color: #ef4444; box-shadow: 0 2px 10px rgba(239,68,68,.2); }
.toolbar .export-group select {
    margin: 0;
    background: #151b23;
    color: #e6ebf2;
    border: 1px solid #28313d;
    border-radius: 8px;
    padding: 9px 10px;
    font-size: 14px;
    cursor: pointer;
}
.toolbar-status {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    min-height: 18px;
    margin: 2px 0 6px;
}
.toolbar-status:empty { display: none; }
.thumbnail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 8px;
    margin-top: 16px;
}
.thumb {
    display: block;
    background: #0e1116;
    border: 1px solid #28313d;
    border-radius: 6px;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    text-align: center;
}
.thumb img { width: 100%; height: 90px; object-fit: cover; display: block; }
.thumb span { display: block; padding: 4px; font-size: 11px; color: #8a96a6; }

#extract-progress, #export-progress { margin: 12px 0; display: flex; gap: 12px; align-items: center; }
progress { width: 240px; }

/* frames grid (dedicated page) */
.frames-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 12px;
    margin: 16px 0;
}
.frame-card {
    background: #10161e;
    border: 1px solid #242e3a;
    border-radius: 8px;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transition: transform .12s, border-color .12s;
}
.frame-card:hover { border-color: #6d8dff; transform: translateY(-1px); }
.frame-card img { width: 100%; aspect-ratio: 16/10; object-fit: cover; display: block; background: #000; }
.frame-meta {
    display: flex;
    justify-content: space-between;
    padding: 6px 10px;
    font-size: 12px;
    color: #8a96a6;
}
.frame-num { font-weight: 600; color: #e6ebf2; }

/* frame mass-selection */
.frame-card { position: relative; }
.frame-checkbox { display: none; }
body.frames-select-mode .frames-grid .frame-card { cursor: pointer; }
body.frames-select-mode .frame-checkbox {
    display: block;
    position: absolute;
    top: 8px;
    left: 8px;
    width: 22px;
    height: 22px;
    border-radius: 5px;
    border: 2px solid #c6d0de;
    background: rgba(15, 23, 42, 0.7);
    z-index: 2;
    pointer-events: none;
}
body.frames-select-mode .frame-card.selected { border-color: #6d8dff; }
body.frames-select-mode .frame-card.selected img { opacity: 0.65; }
body.frames-select-mode .frame-card.selected .frame-checkbox {
    background: #6d8dff;
    border-color: #6d8dff;
}
body.frames-select-mode .frame-card.selected .frame-checkbox::after {
    content: "✓";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
}

.pager { display: flex; gap: 12px; align-items: center; justify-content: center; margin: 20px 0 0; }

/* annotation editor */
.editor-shell {
    display: grid;
    grid-template-columns: 240px 1fr 280px;
    gap: 0;
    height: 100vh;
    height: 100dvh;
    background: #0e1116;
}
.editor-side {
    background: #111827;
    border-right: 1px solid #242e3a;
    padding: 16px;
    overflow-y: auto;
}
.editor-side.right { border-right: 0; border-left: 1px solid #242e3a; }
.editor-side h3 { margin: 0 0 8px; font-size: 13px; color: #8a96a6; text-transform: uppercase; letter-spacing: 1px; }
#class-list, #annotation-list { list-style: none; padding: 0; margin: 0 0 16px; }
#class-list li, #annotation-list li {
    padding: 6px 8px;
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    border-radius: 6px;
    font-size: 13px;
}
/* Рядок анотації має багато елементів (клас-селект, pending, автор, кнопки) —
   у вузькій правій панелі вони не вміщались і «наповзали»/обрізались. Дозволяємо
   перенос на новий рядок і даємо селекту змогу стискатись. */
#annotation-list li, #annotation-list summary { flex-wrap: wrap; }
#annotation-list .anno-class-sel { min-width: 0; flex: 1 1 96px; }
#annotation-list summary > span[style*="flex:1"],
#annotation-list summary > span[style*="flex: 1"] { min-width: 0; }
#class-list li.active { background: #242e3a; }
#class-list li:hover { background: #242e3a; }
#class-list li.is-mask { background: repeating-linear-gradient(45deg, transparent, transparent 4px, #242e3a30 4px, #242e3a30 6px); }

/* AI panel in annotation editor */
.ai-panel {
    background: linear-gradient(135deg, rgba(59,130,246,0.10), rgba(16,185,129,0.10));
    border: 1px solid #4a63d8;
    border-radius: 8px;
    padding: 10px;
    margin-bottom: 12px;
}
.ai-panel select {
    width: 100%;
    padding: 6px 8px;
    background: #10161e;
    color: #e6ebf2;
    border: 1px solid #242e3a;
    border-radius: 6px;
    font-size: 13px;
}
.ai-panel button {
    margin: 0;
    padding: 8px 10px;
    font-size: 13px;
}
.ai-panel #ai-result { word-break: break-word; }

/* camera live view */
.camera-viewer {
    position: relative;
    background: #000;
    border-radius: 8px;
    overflow: hidden;
    min-height: 240px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.camera-viewer img, .camera-viewer canvas { width: 100%; max-height: 70vh; object-fit: contain; display: block; }
.camera-placeholder { padding: 60px 20px; text-align: center; color: #8a96a6; }

/* повноекранний режим live-перегляду */
.camera-viewer:fullscreen { border-radius: 0; width: 100vw; height: 100vh; min-height: 0; }
.camera-viewer:fullscreen img, .camera-viewer:fullscreen canvas { width: 100%; height: 100%; max-height: none; object-fit: contain; }
.camera-viewer:-webkit-full-screen { border-radius: 0; width: 100vw; height: 100vh; min-height: 0; }
.camera-viewer:-webkit-full-screen img, .camera-viewer:-webkit-full-screen canvas { width: 100%; height: 100%; max-height: none; object-fit: contain; }
/* кнопка виходу поверх кадру в повноекранному режимі */
.camera-viewer #cam-fs-exit { display: none; }
.camera-viewer:fullscreen #cam-fs-exit,
.camera-viewer:-webkit-full-screen #cam-fs-exit {
    display: block; position: absolute; top: 14px; right: 14px; z-index: 5;
    background: rgba(15, 20, 30, .65); color: #e5e7eb; border: 1px solid #334;
    border-radius: 8px; padding: 7px 12px; font-size: .9rem; cursor: pointer;
}
.camera-viewer:fullscreen #cam-fs-exit:hover,
.camera-viewer:-webkit-full-screen #cam-fs-exit:hover { background: rgba(30, 40, 55, .85); }

/* live host metrics */
.host-metrics-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: 12px;
    margin-top: 8px;
}
.metric-card {
    background: #10161e;
    border: 1px solid #242e3a;
    border-radius: 8px;
    padding: 12px 14px;
}
.metric-label { font-size: 11px; color: #8a96a6; text-transform: uppercase; letter-spacing: 0.5px; }
.metric-value { font-size: 24px; font-weight: 600; color: #eef2f7; line-height: 1.2; margin: 2px 0 6px; }
.metric-bar { height: 6px; background: #242e3a; border-radius: 3px; overflow: hidden; }
.metric-bar-fill { height: 100%; transition: width .3s, background .3s; background: #16a34a; }
#gpu-cards { grid-column: 1 / -1; padding: 0; background: transparent; border: 0; }
.metric-card-inner {
    background: #10161e;
    border: 1px solid #242e3a;
    border-radius: 8px;
    padding: 12px 14px;
    margin-bottom: 8px;
}
.gpu-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    margin-top: 6px;
}
.gpu-stats .metric-value { font-size: 18px; }

/* training presets */
.preset-btn {
    background: #242e3a;
    color: #e6ebf2;
    border: 1px solid #28313d;
    padding: 6px 12px;
    border-radius: 6px;
    font-size: 13px;
    cursor: pointer;
    margin: 0;
    transition: background .12s, border-color .12s;
}
.preset-btn:hover {
    background: #28313d;
    border-color: #3a4656;
}
.preset-btn.active {
    background: #4a63d8;
    border-color: #6d8dff;
    color: #eef2f7;
}
.preset-hint { color: #8fa8ff; }

/* prediction review cards */
.pred-card { position: relative; transition: outline .15s; }
.pred-card.reviewed-correct { outline: 2px solid #16a34a; }
.pred-card.reviewed-fp { outline: 2px solid #dc2626; opacity: 0.7; }
.pred-actions {
    display: flex;
    gap: 4px;
    justify-content: center;
    padding: 4px 0;
    background: #10161e;
    border-top: 1px solid #242e3a;
}
.pred-actions button {
    margin: 0;
    padding: 2px 10px;
    font-size: 14px;
    font-weight: 600;
}

.mask-badge {
    background: #7c2d12;
    color: #fed7aa;
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 4px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.dot { width: 12px; height: 12px; border-radius: 50%; flex: none; }
/* Кольорові кружечки класів: колір приходить ДАНИМИ з сервера (data-css →
   --dot-bg / --swatch-bg через core/style-bind.js), а розмір і форма — тут.
   Фолбек обовʼязковий: без нього кружечок зникає, якщо змінна не доїхала. */
.u-swatch { background: var(--swatch-bg, #6d8dff); }
.u-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%;
         background: var(--dot-bg, #6d8dff); }
.hot { color: #6b7280; font-size: 11px; width: 18px; }
.class-form { display: grid; grid-template-columns: 1fr auto auto; gap: 6px; }
.class-form input[type="text"] { margin: 0; padding: 6px 8px; }
.class-form input[type="color"] { width: 32px; height: 32px; padding: 0; border: 0; background: none; }
.class-form button { margin: 0; padding: 6px 10px; font-size: 13px; }

.editor-main { display: flex; flex-direction: column; min-width: 0; }
/* Мінікарта прибита до кута РОБОЧОЇ ОБЛАСТІ, а не до вмісту скрол-контейнера:
   інакше на зумі вона їхала разом із зображенням і закривала огляд. */
.editor-main { position: relative; }
.minimap {
    position: absolute;
    z-index: 12;
    background: #0e1116;
    border: 1px solid #3a4656;
    border-radius: 6px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, .5);
    overflow: hidden;
    opacity: .42;
    transition: opacity .15s;
}
/* Напівпрозора, поки не потрібна: наведення (або перетягування) робить її повною. */
.minimap:hover, .minimap.mm-active { opacity: 1; }
.minimap-bar {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 2px 3px 2px 6px;
    background: #151b23;
    border-bottom: 1px solid #242e3a;
    cursor: grab;
    user-select: none;
    touch-action: none;
}
.minimap.mm-dragging .minimap-bar { cursor: grabbing; }
.minimap-title {
    flex: 1;
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: #71809a;
}
.minimap-btn {
    margin: 0;
    padding: 1px 5px;
    background: none;
    border: 0;
    border-radius: 4px;
    color: #93a1b3;
    font-size: 11px;
    line-height: 1.2;
    cursor: pointer;
}
.minimap-btn:hover { background: #28313d; color: #e6ebf2; }
.minimap-canvas { display: block; cursor: crosshair; }
.minimap-chip {
    position: absolute;
    z-index: 12;
    width: 28px;
    height: 28px;
    margin: 0;
    padding: 0;
    background: #151b23;
    border: 1px solid #3a4656;
    border-radius: 50%;
    color: #e6ebf2;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    opacity: .45;
    transition: opacity .15s;
}
.minimap-chip:hover { opacity: 1; }
/* Кути: клас керує позицією і для мінікарти, і для «згорнутого» кружечка. */
.mm-br { right: 12px; bottom: 12px; top: auto; left: auto; }
.mm-bl { left: 12px; bottom: 12px; top: auto; right: auto; }
.mm-tr { right: 12px; top: 12px; bottom: auto; left: auto; }
.mm-tl { left: 12px; top: 12px; bottom: auto; right: auto; }

/* ── Toolbar (grouped) ───────────────────────────────────────────────────
   Два ряди: верхній — щоденне (кадр, етап, клас+буфер, pending),
   нижній — інструменти / видалення / масштаб. Кожна група має тихий
   підпис, розділена вертикальною лінією і переносяться цілком.
   Поля діапазонів живуть у поповерах, тому ряди не «стрибають». */
.editor-toolbar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    background: #10161e;
    border-bottom: 1px solid #242e3a;
}
.tb-row {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    row-gap: 8px;
    column-gap: 0;
    padding: 7px 12px;
}
.tb-row + .tb-row {
    border-top: 1px solid #131c2b;
    background: #0a101c;   /* другий ряд трохи глибший — візуально «вторинний» */
}
.tb-group {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
    padding: 0 14px;
    border-right: 1px solid #151b23;
    min-width: 0;
}
.tb-group:last-child { border-right: 0; }
.tb-row > .tb-group:first-child { padding-left: 0; }
/* Групи йдуть підряд, без притискання до правого краю. `margin-left: auto`
   тут давало на широкому екрані діру в 273px перед «масштабом» і 884px перед
   «pending» — а ряд ще й вилазив за свою ширину (1609 при 1380), через що
   група «екран» зривалась на власний рядок. Порожнеча між кнопками не несе
   змісту: групи вже розділені бордюром і власним падінгом. */
.tb-group-pending, .tb-group-zoom { border-right: 0; }

/* Підпис групи — тихий, не конкурує з кнопками */
.tb-group-label {
    font-size: 10px;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: #71809a;
    white-space: nowrap;
    user-select: none;
}
.tb-controls {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    min-width: 0;
}

/* Якір для поповерів (кнопка + спливаюча панель) */
.tb-anchor { position: relative; display: inline-flex; align-items: center; gap: 6px; }
.tb-popover {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 30;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 210px;
    padding: 10px;
    background: #0e1116;
    border: 1px solid #28313d;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
}
.tb-popover-title {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.7px;
    color: #71809a;
}
.tb-popover-row { display: flex; align-items: center; gap: 6px; }
.tb-popover .tb-input { flex: 1; width: auto; }
.tb-popover button { align-self: stretch; }
.tb-check {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 12px;
    color: #c6d0de;
    cursor: pointer;
}
.tb-check input { margin: 0; }

/* Числовий вивід дрейфу — фіксована зона, щоб ряд не смикався */
.tb-readout {
    font-family: ui-monospace, monospace;
    white-space: nowrap;
    color: #8a96a6;
}

/* Кнопки */
.editor-toolbar button.tb-btn {
    background: #242e3a;
    color: #e6ebf2;
    padding: 6px 10px;
    margin: 0;
    border: 1px solid transparent;
    border-radius: 6px;
    white-space: nowrap;
    font-size: 13px;
    line-height: 1.2;
    transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.editor-toolbar button.tb-btn:hover { background: #28313d; }
.editor-toolbar button.tb-btn-ghost {
    background: transparent;
    border-color: #28313d;
}
.editor-toolbar button.tb-btn-ghost:hover { background: #242e3a; }
.editor-toolbar button.tb-btn-icon { padding: 4px 8px; }
.editor-toolbar button.tb-btn-danger {
    background: transparent;
    color: #ef4444;
    border-color: #7f1d1d;
}
.editor-toolbar button.tb-btn-danger:hover { background: #2a0d0d; }
.editor-toolbar button.tb-btn-confirm {
    background: #ec4899;
    color: #fff;
    border-color: #db2777;
}
.editor-toolbar button.tb-btn-confirm:hover { background: #db2777; }
/* Armed: кадр A інтерполяції зафіксовано, чекаємо на кадр B. */
.editor-toolbar button.tb-btn.armed {
    background: #f59e0b;
    color: #242e3a;
    border-color: #d97706;
    box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.4);
}
.editor-toolbar button.tb-btn-reject {
    background: transparent;
    color: #c6d0de;
    border-color: #3a4656;
}
.editor-toolbar button.tb-btn-reject:hover { background: #242e3a; }

/* Індикатор кадру */
.tb-indicator {
    color: #c6d0de;
    font-variant-numeric: tabular-nums;
    font-size: 13px;
    min-width: 130px;
    text-align: center;
}

/* Input для переходу за номером */
.tb-input {
    width: 70px;
    background: #0e1116;
    color: #c6d0de;
    border: 1px solid #28313d;
    border-radius: 4px;
    padding: 4px 6px;
    font-size: 13px;
}

.tb-input-wide { width: 170px; }

/* Активний тумблер (поповер відкрито / режим увімкнено) */
.editor-toolbar button.tb-btn.active {
    background: #4a63d8;
    border-color: #6d8dff;
    color: #eef2f7;
}

/* Zoom group */
.tb-group-zoom .tb-controls { gap: 8px; }
.tb-group-zoom input[type="range"] { width: 160px; }
.tb-zoom-value {
    min-width: 42px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Pending badge */
.tb-pending-badge {
    color: #ec4899;
    font-size: 13px;
    white-space: nowrap;
}

.active-class-pill {
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 13px;
    color: white;
    background: #3a4656;
}

.canvas-wrapper {
    flex: 1;
    background: #020617;
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    overflow: hidden;
    padding: 16px;
}
#annot-canvas {
    background: #000;
    cursor: crosshair;
    box-shadow: 0 0 0 1px #242e3a;
    /* margin:auto центрує canvas коли є вільне місце, але колапсує в 0 при overflow —
       тоді canvas прилипає до start, а scrollTop=0 = верх canvas (без letterbox-смуги
       над зображенням). */
    margin: auto;
}

/* dataset/training/models additions */
.form-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.form-row input, .form-row select { padding: 6px 8px; background: #10161e; color: #e6ebf2; border: 1px solid #242e3a; border-radius: 6px; }
.form-row label { display: flex; gap: 6px; align-items: center; font-size: 13px; color: #8a96a6; }
.form-stack { display: flex; flex-direction: column; gap: 8px; }
.form-stack input, .form-stack select { padding: 6px 8px; background: #10161e; color: #e6ebf2; border: 1px solid #242e3a; border-radius: 6px; }
.checkbox-row { display: flex; gap: 8px; align-items: center; font-size: 13px; color: #8a96a6; }
/* Обгортка таблиці: горизонтальна прокрутка на БУДЬ-ЯКІЙ ширині.
   Раніше прокрутка вмикалась лише в медіа ≤700px, тому в діапазоні ~740–1050px
   (вузьке вікно на десктопі або зум браузера) широка таблиця — напр. камер із
   колонкою власника — вилазила за межі картки й розпирала сторінку.
   width:100% на таблиці лишає її розтягнутою на широких екранах, а на вузьких
   таблиця сідає до min-content і прокручується всередині обгортки. */
.table-scroll { max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain;
                -webkit-overflow-scrolling: touch; }

.data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.data-table th, .data-table td { padding: 8px 10px; border-bottom: 1px solid #242e3a; vertical-align: middle; text-align: left; }
.data-table th { color: #71809a; font-weight: 700; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; }
.data-table tr:hover { background: #10161e; }

/* Посилання й дії всередині data-table.
   Раніше на .data-table не було жодного правила для <a>, тож звичайні посилання
   («→ деталі») малювались браузерним дефолтом: синє з підкресленням, фіолетове
   після відвідування. Плюс кнопки-«лінки» мають margin:0 і злипались/переносились
   у вузькій останній колонці. */
.data-table a { color: #8fa8ff; text-decoration: none; }
.data-table a:hover { text-decoration: underline; }
.data-table a:visited { color: #8fa8ff; }
.data-table td:last-child > a,
.data-table td:last-child > button.link {
    display: inline-block;
    vertical-align: middle;
    white-space: nowrap;
    margin-right: 12px;
}
.data-table td:last-child > a:last-child,
.data-table td:last-child > button.link:last-child { margin-right: 0; }
/* Браузер стискає останню колонку до мінімуму (колонок 11), тож навіть пара
   «деталі + видалити» ламалась на два ряди. Мінімальна ширина лишає типовий
   рядок в один ряд, а рідкісні три дії складає стовпчиком — без гориз. скролу. */
.data-table td:last-child { min-width: 165px; }

/* ── Камери: таблиця «Усі камери» ─────────────────────────────────────────
   Спокійніший, вирівняний вигляд: чипи власника/моделі, компактне джерело
   (relay-підшлях), крапка-статус замість кричущих бейджів, кнопка live. */
.cam-table td, .cam-table th { padding: 12px 14px; }
.cam-table tbody tr { transition: background .12s; }
.cam-id { color: #71809a; font-weight: 600; font-variant-numeric: tabular-nums; }
.cam-name-link { font-weight: 600; color: #e6ebf2; }
.cam-name-link:hover { color: #8fa8ff; }
.cam-owner { display: inline-block; padding: 2px 10px; border-radius: 999px;
    background: #151b23; color: #8a96a6; font-size: 12px; white-space: nowrap; }
.cam-src { display: inline-flex; align-items: center; gap: 8px; max-width: 240px; }
.cam-src-tag { color: #71809a; font-size: 11px; white-space: nowrap; }
.cam-src code { display: inline-block; max-width: 150px; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; vertical-align: bottom; font-size: 12px; color: #7dd3fc;
    background: #10161e; border: 1px solid #242e3a; border-radius: 6px; padding: 2px 8px; }
.cam-state { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: #c6d0de; }
.cam-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: #71809a; }
.cam-dot.live { background: #34d399; box-shadow: 0 0 0 3px rgba(34,197,94,.18); animation: cam-pulse 1.8s infinite; }
.cam-dot.error { background: #f59e0b; box-shadow: 0 0 0 3px rgba(245,158,11,.15); }
.cam-dot.stopped { background: #71809a; }
@keyframes cam-pulse { 0%,100% { opacity: 1; } 50% { opacity: .4; } }
.cam-note { color: #71809a; font-size: 11.5px; margin-top: 4px; max-width: 240px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Колонка дій «live / 🗑» приклеєна до правого краю: коли таблиця камер не
   влазить і прокручується всередині .table-scroll, головні кнопки лишаються
   на видноті, а не ховаються за горизонтальним скролом. Фон = фон картки
   (і фон ховера рядка), інакше під клітинкою просвічували б інші колонки. */
.cam-actions-cell { white-space: nowrap; text-align: right;
                    position: sticky; right: 0; z-index: 1; background: #151b23; }
.cam-table thead th:last-child { position: sticky; right: 0; z-index: 2; background: #151b23; }
.cam-table tbody tr:hover .cam-actions-cell { background: #10161e; }
.cam-actions-cell::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0;
                            width: 12px; transform: translateX(-100%);
                            background: linear-gradient(to right, rgba(21, 27, 35, 0), #151b23);
                            pointer-events: none; }
.cam-live-btn { display: inline-flex; align-items: center; gap: 5px; padding: 5px 13px;
    border-radius: 7px; background: #4a63d8; color: #fff; font-size: 13px; font-weight: 500;
    text-decoration: none; transition: background .12s; }
.cam-live-btn:hover { background: #5570e8; color: #fff; }
.cam-del-btn { margin-left: 8px; padding: 5px 9px; border: 1px solid #3f2530; border-radius: 7px;
    background: transparent; color: #f87171; font-size: 13px; cursor: pointer; transition: all .12s; }
.cam-del-btn:hover { background: #7f1d1d; border-color: #7f1d1d; color: #fecaca; }
.cam-del-btn:disabled { opacity: .5; cursor: default; }

.thumb-mini { width: 64px; height: 36px; object-fit: cover; border-radius: 4px; background: #000; cursor: pointer; transition: outline .12s; }
.thumb-mini:hover { outline: 2px solid #6d8dff; }
.row-link { color: inherit; text-decoration: none; }
.row-link:hover { color: #8fa8ff; text-decoration: underline; }
.small { font-size: 11px; }
.card.danger { border: 1px solid #7f1d1d; }
.run-row { display: flex; gap: 12px; align-items: center; }
.run-row progress { flex: 1; height: 12px; }
.split-select { padding: 4px 6px; background: #10161e; color: #e6ebf2; border: 1px solid #242e3a; border-radius: 4px; }
.class-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.class-list li { display: flex; align-items: center; gap: 8px; padding: 4px 0; }
.badge-pending, .badge-building, .badge-running { background: #1e3a8a; color: #c9d6ff; }
.badge-ready, .badge-done { background: #14532d; color: #bbf7d0; }
.badge-failed, .badge-cancelled { background: #7f1d1d; color: #fecaca; }

.note-block {
    margin: 8px 0 12px;
    padding: 10px 14px;
    background: rgba(59, 130, 246, 0.08);
    border-left: 3px solid #6d8dff;
    border-radius: 6px;
    font-size: 13px;
    line-height: 1.5;
    color: #c6d0de;
}
.note-block strong { color: #e6ebf2; }

button.secondary.danger { background: #7f1d1d; color: #fecaca; }
button.secondary.danger:hover { background: #991b1b; }
#mem-table th { position: sticky; top: 0; background: #151b23; z-index: 1; }
#mem-table td { padding: 6px 10px; }
#mem-table button.link { padding: 2px 6px; }
#mem-pager { margin: 12px 0; }
#mem-pager a { cursor: pointer; }
#membership-status { margin-top: 8px; }

/* --- Per-user activity / hourly-pay panel (admin dashboard) --- */
.section-title { margin: 22px 0 10px; color: #e6ebf2; font-size: 18px; }
.pay-panel {
    border-top: 1px solid #28313d;
    margin-top: 12px;
    padding-top: 14px;
}
.pay-rate { gap: 10px; align-items: center; margin-bottom: 14px; }
.pay-rate label { color: #8a96a6; font-size: 14px; }
.pay-rate input {
    background: #0e1116; border: 1px solid #28313d; border-radius: 8px;
    color: #eef2f7; padding: 6px 8px; margin-left: 6px;
}
.pay-grid { margin-bottom: 4px; }
.pay-headline { border-color: #5570e8; }

/* --- Video analysis timeline (pre-extraction drone analysis) --- */
#analyze-timeline {
    position: relative; height: 28px;
    background: linear-gradient(#0e1116, #151b23);
    border: 1px solid #28313d; border-radius: 5px; cursor: crosshair;
}
/* Мітки — суто візуальні: НЕ перехоплюють кліки, щоб клік завжди влучав у
   доріжку й перемотував у ТОЧНУ позицію курсора (а не на початок сегмента). */
.tl-marker {
    position: absolute; top: 0; bottom: 0; width: 3px; margin-left: -1px;
    background: #8a96a6; opacity: 0.8; pointer-events: none;
}
.tl-marker.drone { background: #34d399; width: 4px; box-shadow: 0 0 6px #34d399; opacity: 0.95; z-index: 2; }

/* Сегмент, у якому Є витягнутий кадр → його можна відкрити подвійним кліком.
   Заливку НЕ чіпаємо: колір смуги вже означає впевненість детекції, і другий
   сенс у тому самому каналі зробив би шкалу нечитаною. Позначаємо облямівкою:
   світла риска зверху та знизу видно на будь-якій заливці. */
.tl-marker.has-frame {
    border-top: 2px solid #e2e8f0;
    border-bottom: 2px solid #e2e8f0;
    z-index: 3;
}

/* Курсор поточної позиції на таймлайні аналізу. */
.tl-playhead {
    position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px;
    background: #eef2f7; box-shadow: 0 0 5px rgba(248,250,252,0.9);
    pointer-events: none; z-index: 4;
}
/* Hover indicator — line + time bubble at the cursor, for precise seeking. */
.tl-hover {
    position: absolute; top: 0; bottom: 0; width: 1px; margin-left: -1px;
    background: rgba(248,250,252,0.5); pointer-events: none; z-index: 3;
}
.tl-hovertime {
    position: absolute; top: -22px; transform: translateX(-50%);
    background: #10161e; border: 1px solid #28313d; border-radius: 4px;
    padding: 1px 6px; font-size: 12px; color: #e6ebf2; white-space: nowrap;
    pointer-events: none; z-index: 5;
}

/* Selection bands for "densify frames" — drawn over the timeline when the
   user is picking segments to extract every frame from. */
#analyze-timeline.selecting { cursor: cell; }
.tl-select {
    position: absolute; top: 0; bottom: 0; z-index: 3;
    background: rgba(96,165,250,0.30); border-left: 1px solid #8fa8ff;
    border-right: 1px solid #8fa8ff; pointer-events: none;
}
#analyze-timeline.selecting .tl-select { pointer-events: auto; cursor: pointer; }
#analyze-timeline.selecting .tl-select:hover { background: rgba(239,68,68,0.35); }
.tl-select.live { background: rgba(96,165,250,0.45); pointer-events: none; }
#densify-select-toggle.active { background: #5570e8; color: #eef2f7; border-color: #5570e8; }

/* --- Virtual-folder Finder (shared: videos page + dataset selector) --- */
.folder-crumb { text-decoration: none; padding: 2px 6px; border-radius: 4px; }
.folder-card { transition: border-color .12s; }
.folder-card:hover { border-color: #3a4656; }
.drop-hover { outline: 2px dashed #8fa8ff; outline-offset: 2px; background: #15324a !important; }
#mem-table tr.video-row[draggable] { cursor: grab; }
#mem-table tr.video-row[draggable]:active { cursor: grabbing; }

/* ── Механізм «Знайшли помилку — повідомте» ──────────────────────────── */
#bug-fab {
    position: fixed; right: 16px; bottom: 16px; z-index: 900;
    background: #7f1d1d; color: #fecaca; border: 1px solid #b91c1c;
    border-radius: 24px; padding: 10px 16px; font-size: 14px; cursor: pointer;
    box-shadow: 0 4px 14px rgba(0,0,0,0.4);
}
#bug-fab:hover { background: #991b1b; }

.bug-modal-backdrop {
    position: fixed; inset: 0; z-index: 1000; background: rgba(2,6,23,0.7);
    display: flex; align-items: center; justify-content: center; padding: 16px;
}
.bug-modal {
    background: #0e1116; border: 1px solid #28313d; border-radius: 12px;
    width: 100%; max-width: 560px; padding: 18px 20px; max-height: 90vh; overflow: auto;
}
.bug-modal-head { display: flex; justify-content: space-between; align-items: center; }
.bug-modal-head h3 { margin: 0; }
.bug-modal-x { background: none; border: none; color: #8a96a6; font-size: 24px; cursor: pointer; }
.bug-field { display: block; margin: 12px 0; }
.bug-field > span { display: block; color: #8a96a6; font-size: 13px; margin-bottom: 4px; }
.bug-field input, .bug-field textarea { width: 100%; box-sizing: border-box; }

.bug-reply-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.bug-thumbs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.bug-thumb { position: relative; }
.bug-thumb img { height: 72px; border-radius: 6px; border: 1px solid #28313d; display: block; }
.bug-thumb-x {
    position: absolute; top: -8px; right: -8px; width: 20px; height: 20px;
    border-radius: 50%; background: #7f1d1d; color: #fff; border: none; cursor: pointer; line-height: 1;
}

.bug-crop-overlay {
    position: fixed; inset: 0; z-index: 1100; background: rgba(2,6,23,0.92);
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
}
.bug-crop-hint { color: #e6ebf2; font-size: 14px; }
.bug-crop-stage { position: relative; line-height: 0; }
.bug-crop-stage canvas { border: 1px solid #3a4656; cursor: crosshair; max-width: 92vw; max-height: 78vh; }
.bug-crop-sel { position: fixed; display: none; border: 2px solid #8fa8ff; background: rgba(56,189,248,0.15); pointer-events: none; z-index: 1101; }
.bug-crop-bar { display: flex; gap: 10px; }

.bug-filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.bug-item-title { font-weight: 600; color: #e8edf3; }

.bug-status-bar { display: flex; align-items: center; gap: 12px; }
.bug-thread { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
.bug-msg { background: #151b23; border: 1px solid #28313d; border-radius: 10px; padding: 10px 14px; max-width: 85%; }
.bug-msg.mine { align-self: flex-end; }
.bug-msg.staff { border-color: #4a63d8; }
.bug-msg-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; flex-wrap: wrap; }
.bug-msg-head .small { margin-left: auto; white-space: nowrap; }
.bug-msg-body { overflow-wrap: anywhere; }
.bug-msg-body { white-space: pre-wrap; color: #e6ebf2; }
.bug-shots { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.bug-shot-thumb { height: 110px; border-radius: 6px; border: 1px solid #28313d; display: block; }
.bug-reply { border-top: 1px solid #28313d; padding-top: 12px; }
.bug-reply textarea { width: 100%; box-sizing: border-box; }

/* ── Стилізовані сторінки помилок (404 / 403 / 500) ──────────────────── */
.error-page {
    max-width: 560px; margin: 8vh auto; text-align: center; padding: 32px 24px;
    background: #151b23; border: 1px solid #28313d; border-radius: 16px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
}
.error-emoji { font-size: 56px; line-height: 1; margin-bottom: 6px; }
.error-code {
    font-size: 92px; font-weight: 800; line-height: 1;
    background: linear-gradient(180deg, #8fa8ff, #5570e8);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    letter-spacing: 2px;
}
.error-title { margin: 8px 0 6px; font-size: 22px; color: #e8edf3; }
.error-msg { font-size: 15px; max-width: 420px; margin: 0 auto 22px; }
.error-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

.users-table td { padding-top: 10px; padding-bottom: 10px; vertical-align: middle; }
.users-table .col-id { width: 44px; }
.users-table .col-role { width: 160px; }
.users-table .col-status { width: 1%; white-space: nowrap; }
.users-table .col-hours { width: 1%; white-space: nowrap; text-align: right; }
.users-table .col-actions { width: 1%; white-space: nowrap; }
.users-table th.col-hours { text-align: right; }
/* Компактний select ролі — на всю ширину вузької колонки, без роздування */
.users-table select {
    margin: 0;
    width: 100%;
    padding: 6px 8px;
    font-size: 13px;
}

/* Другорядний рядок у комірці (дата реєстрації, деталі активності) */
.cell-sub { display: block; margin-top: 2px; line-height: 1.35; }

.user-name { color: #8fa8ff; text-decoration: none; font-weight: 500; }
.user-name:hover { text-decoration: underline; }
.tag-you {
    margin-left: 8px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    background: #151b23;
    color: #8a96a6;
    border: 1px solid #28313d;
}

.status-active   { background: #14532d; color: #bbf7d0; }
.status-pending  { background: #78350f; color: #fde68a; }
.status-disabled { background: #28313d; color: #8a96a6; }
.status-locked   { background: #7f1d1d; color: #fecaca; }

/* Години: цифри однакової ширини, щоб колонка читалась стовпчиком */
.hours-total {
    font-size: 15px;
    font-weight: 600;
    color: #e6ebf2;
    font-variant-numeric: tabular-nums;
}
.hours-unit { font-size: 12px; color: #8a96a6; margin-left: 3px; }
.hours-empty { font-size: 15px; }

/* Акаунт чекає активації: акцент смугою зліва, а не заливкою всього рядка */
.row-pending > td:first-child { box-shadow: inset 3px 0 0 #f59e0b; }
.row-pending { background: rgba(245, 158, 11, .05); }
.row-pending:hover { background: rgba(245, 158, 11, .09); }

/* Дії */
.row-actions { display: flex; gap: 6px; align-items: center; justify-content: flex-end; }
.row-actions .inline-form { display: inline-flex; margin: 0; }
.row-actions .tbtn { padding: 5px 12px; font-size: 12px; }
.tbtn.ghost {
    background: transparent;
    border-color: #28313d;
    color: #8a96a6;
    padding: 5px 10px;
    line-height: 1;
}
.tbtn.ghost:hover { background: #151b23; color: #e6ebf2; }

/* Меню «⋯» на нативному <details> — без залежностей і працює без JS */
.row-menu { position: relative; display: inline-block; }
.row-menu > summary { list-style: none; cursor: pointer; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu[open] > summary { background: #151b23; color: #e6ebf2; border-color: #6d8dff; }
.row-menu-panel {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 30;
    min-width: 210px;
    padding: 6px;
    background: #0e1116;
    border: 1px solid #28313d;
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
}
.row-menu-panel form { margin: 0; }
.menu-item {
    display: block;
    width: 100%;
    margin: 0;
    padding: 8px 10px;
    background: none;
    border: 0;
    border-radius: 6px;
    color: #e6ebf2;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}
.menu-item:hover { background: #151b23; }
/* Незворотна дія притишена, поки на неї не навели */
.menu-item.danger { color: #f87171; }
.menu-item.danger:hover { background: #7f1d1d; color: #fecaca; }

/* Бейдж ролі (шапка, картка користувача, лічильник анотацій) */
.role-badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 12px;
    line-height: 1.6;
    white-space: nowrap;
    background: #151b23;
    border: 1px solid #28313d;
    color: #c6d0de;
}

/* --- Список датасетів ------------------------------------------------------ */
.ds-form-hint { margin: -4px 0 10px; }

/* --- Форма «Додати камеру» -------------------------------------------------
   Сітка, а не один flex-рядок: у рядку RTSP-поле стискалось до кількох пікселів
   (width:100% без flex-basis). Назва і URL — верхній ряд (URL удвічі ширший, бо
   довший за змістом), модель і пороги — нижній. На вузькому екрані все в колонку. */
.cam-form {
    display: grid;
    grid-template-columns: minmax(min(180px, 100%), 1fr) minmax(min(280px, 100%), 2fr);
    gap: 18px 20px;
    align-items: start;
}
.cam-field { min-width: 0; }              /* інакше grid-колонка не дає полю стискатись */
.cam-field label {
    display: block;
    margin: 0 0 6px;
    font-size: 13px;
    font-weight: 500;
    color: #c6d0de;
}
.cam-field input[type="text"],
.cam-field input[type="number"],
.cam-field select { margin-top: 0; width: 100%; }
.cam-field-url input { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; }
.cam-hint { display: block; margin-top: 6px; font-size: 12px; color: #8a96a6; line-height: 1.45; }
.cam-req {
    margin-left: 6px; padding: 1px 6px; border-radius: 4px;
    background: rgba(220, 38, 38, 0.15); color: #fca5a5;
    font-size: 11px; font-weight: 500;
}
.cam-sample {
    cursor: pointer; border-bottom: 1px dashed #71809a;
    padding: 1px 3px; border-radius: 3px;
}
.cam-sample:hover, .cam-sample:focus { background: #28313d; color: #e6ebf2; outline: none; }

/* Пороги: два вузькі поля поруч, а не на всю ширину колонки */
.cam-thr-row { display: flex; gap: 12px; }
.cam-thr { display: inline-flex; align-items: center; gap: 6px; }
.cam-thr-key { font-size: 13px; color: #8a96a6; cursor: help; border-bottom: 1px dotted #3a4656; }
.cam-thr input { width: 84px; }
/* Без обраної моделі пороги ні на що не впливають — гасимо, але лишаємо видимими */
.cam-field-thr.is-off { opacity: 0.45; }
.cam-field-thr.is-off input { cursor: not-allowed; }

.cam-actions {
    grid-column: 1 / -1;
    display: flex; align-items: center; gap: 14px;
    padding-top: 4px; border-top: 1px solid #28313d;
}
.cam-actions button { margin-top: 12px; }
.cam-actions .muted { margin-top: 12px; }

@media (max-width: 720px) {
    .cam-form { grid-template-columns: 1fr; gap: 16px; }
}

/* Банер «зміни не застосовані» в картці камери. Бурштиновий = потребує дії
   людини (на відміну від червоного «зламалось»): потік живий, просто крутиться
   зі старою моделлю/адресою. */
.stale-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 14px;
    padding: 10px 14px;
    background: rgba(245, 158, 11, .10);
    border: 1px solid #78350f;
    border-left: 3px solid #f59e0b;
    border-radius: 8px;
    font-size: 13px;
    line-height: 1.5;
    color: #fde68a;
}
.stale-banner .stale-icon { flex: 0 0 auto; font-size: 15px; }
.stale-banner .stale-text { flex: 1 1 auto; }
.stale-banner .tbtn { flex: 0 0 auto; }

/* ── Повноекранна розмітка ───────────────────────────────────────────────────
   Бічні панелі геть, canvas на весь екран. Тулбар — плаваюча напівпрозора
   накладка зверху: сама ховається за таймером бездіяльності й повертається, коли
   курсор торкається верху (клас .revealed від JS + :hover/:focus-within тримають
   її, поки нею користуються). У fs тулбар компактніший, ніж у звичайному режимі. */
.editor-shell.editor-fs { grid-template-columns: 1fr; }
.editor-shell.editor-fs .editor-side { display: none; }
.editor-shell.editor-fs .canvas-wrapper { padding: 0; }

.editor-shell.editor-fs .editor-toolbar {
    position: fixed;
    top: 0;
    left: 50%;                                   /* по центру й по ширині вмісту, */
    right: auto;                                 /* а не на весь екран — без порожнечі */
    width: max-content;
    max-width: calc(100vw - 16px);
    z-index: 60;
    transform: translate(-50%, -100%);
    transition: transform .2s cubic-bezier(.4, 0, .2, 1), opacity .2s ease;
    opacity: 0;
    background: rgba(9, 14, 24, .82);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(59, 130, 246, .25);
    border-top: 0;
    border-radius: 0 0 14px 14px;
    box-shadow: 0 12px 36px rgba(0, 0, 0, .55);
}
/* Тримає панель тільки клас від JS або живий фокус у ПОЛІ вводу.
   :focus-within тут була пасткою: вхід у fs — це клік по кнопці всередині
   тулбара, фокус лишався на ній і панель не ховалася ніколи. */
.editor-shell.editor-fs .editor-toolbar.revealed,
.editor-shell.editor-fs .editor-toolbar:has(input:focus),
.editor-shell.editor-fs .editor-toolbar:has(select:focus),
.editor-shell.editor-fs .editor-toolbar:has(textarea:focus) {
    transform: translate(-50%, 0);
    opacity: 1;
}
/* Компактні центровані ряди; групи пакуються впритул (без margin-left:auto,
   що й давав велику пусту прогалину посередині) */
.editor-shell.editor-fs .tb-row { padding: 5px 14px; row-gap: 6px; justify-content: center; }
.editor-shell.editor-fs .tb-row + .tb-row { background: rgba(6, 11, 20, .55); }
.editor-shell.editor-fs .tb-group { gap: 2px; padding: 0 12px; }
.editor-shell.editor-fs .tb-group-pending,
.editor-shell.editor-fs .tb-group-zoom {
    margin-left: 0;
    padding: 0 12px;
    border-right: 1px solid #151b23;   /* повертаємо роздільник — вони вже не скраю */
}
.editor-shell.editor-fs .tb-group:last-child { border-right: 0; }
.editor-shell.editor-fs .editor-toolbar button.tb-btn { padding: 5px 9px; }

/* Активна кнопка «на весь екран» */
.editor-toolbar button.tb-btn-ghost.active {
    background: #1e3a8a;
    border-color: #6d8dff;
    color: #dbe4ff;
}

/* Язичок-нагадування: видно лише у fs, коли панель схована (керує JS).
   Тонка, ненавʼязлива смужка-«ручка» по центру верху. */
.fs-handle {
    display: none;
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    z-index: 59;
    padding: 4px 18px 5px;
    background: rgba(9, 14, 24, .82);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(59, 130, 246, .25);
    border-top: 0;
    border-radius: 0 0 10px 10px;
    color: #8a96a6;
    font-size: 12px;
    letter-spacing: .3px;
    cursor: pointer;
    box-shadow: 0 6px 16px rgba(0, 0, 0, .45);
    user-select: none;
    transition: color .12s ease, border-color .12s ease;
}
.fs-handle:hover { color: #e6ebf2; border-color: #6d8dff; }
/* На вході у fs панель не виїжджає (щоб не закривати кадр), тож язичок мусить
   сам себе показати — коротке «дихання» замість спливання всієї панелі. */
.fs-handle.pulse { animation: fs-handle-pulse 800ms ease-in-out 2; }
@keyframes fs-handle-pulse {
    0%, 100% { color: #8a96a6; border-color: rgba(59, 130, 246, .25); box-shadow: 0 6px 16px rgba(0, 0, 0, .45); }
    50% { color: #e6ebf2; border-color: #6d8dff; box-shadow: 0 6px 22px rgba(59, 130, 246, .45); }
}
@media (prefers-reduced-motion: reduce) {
    .fs-handle.pulse { animation: none; color: #e6ebf2; border-color: #6d8dff; }
}

/* ── Оболонка «Графіт»: бічна навігація (редизайн 2026-08, затверджений канвас) ── */
.app-shell { display: flex; min-height: 100vh; min-height: 100dvh; }
body.narrow .app-shell { width: 100%; align-items: center; justify-content: center; }
.app-sidebar { width: 218px; flex-shrink: 0; background: #10151c; border-right: 1px solid #28313d;
    display: flex; flex-direction: column; gap: 18px; padding: 18px 12px;
    position: sticky; top: 0; height: 100vh; height: 100dvh;
    /* overflow: visible — ОБОВʼЯЗКОВО. Було `overflow-y: auto`, а CSS не вміє
       «прокрутка по вертикалі, видимість по горизонталі»: браузер робить
       `overflow-x` теж auto, і підказки кнопок обрізались по краю сайдбара.
       Прокрутку віддано самій навігації (.sb-nav) — вона тут єдина, що росте. */
    overflow: visible; }
body.fullscreen .app-sidebar { display: none; }
.app-main { flex: 1; min-width: 0; }
.app-main > .container { max-width: 1160px; margin: 0 auto; padding: 22px 26px; }
body.fullscreen .app-main > .container { max-width: none; padding: 0; height: 100vh; height: 100dvh; display: flex; flex-direction: column; }
.sb-logo { display: flex; align-items: center; gap: 10px; padding: 0 8px; text-decoration: none; color: #e8edf3; }
.sb-logo-mark { width: 30px; height: 30px; border-radius: 8px; background: linear-gradient(135deg, #6d8dff, #4a63d8);
    display: flex; align-items: center; justify-content: center; }
.sb-logo-text { font-weight: 800; letter-spacing: .14em; font-size: 15px; }
.sb-nav { display: flex; flex-direction: column; gap: 3px;
    flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.sb-item { display: flex; align-items: center; gap: 11px; padding: 9px 12px; border-radius: 9px;
    color: #97a3b4; font-size: 13.5px; font-weight: 600; text-decoration: none; }
.sb-item:hover { background: #161d27; color: #c6d0de; }
.sb-item.active { background: rgba(109,141,255,.14); color: #dbe4ff; }
.sb-item svg { flex-shrink: 0; stroke: #71809a; }
.sb-item.active svg { stroke: #c3cdff; }
/* Живий бейдж «скільки камер стрімить зараз» у пункті меню «Камери».
   Пульсуюча крапка + лічильник; ховається, коли живих камер немає. */
.sb-live { margin-left: auto; display: inline-flex; align-items: center; gap: 5px;
    font-size: 11px; font-weight: 700; color: #86efac; background: #052e16;
    border: 1px solid #14532d; border-radius: 999px; padding: 1px 7px 1px 5px; }
.sb-live-dot { width: 6px; height: 6px; border-radius: 50%; background: #22c55e;
    box-shadow: 0 0 0 0 rgba(34,197,94,.7); animation: sb-live-pulse 1.8s infinite; }
/* Джерело відпало (воркер живий, іде реконект) — бурштиновий, а не «все добре». */
.sb-live.warn { color: #fcd34d; background: #2a1f05; border-color: #78350f; }
.sb-live.warn .sb-live-dot { background: #f59e0b; animation: none; }
@keyframes sb-live-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(34,197,94,.6); }
    70%  { box-shadow: 0 0 0 5px rgba(34,197,94,0); }
    100% { box-shadow: 0 0 0 0 rgba(34,197,94,0); }
}
@media (prefers-reduced-motion: reduce) { .sb-live-dot { animation: none; } }
.sb-bottom { margin-top: auto; border-top: 1px solid #28313d; padding-top: 12px;
    display: flex; flex-direction: column; gap: 9px; }
.sb-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 0 6px; }
.sb-user { display: flex; align-items: center; gap: 10px; padding: 4px 6px; }
.sb-avatar { width: 30px; height: 30px; border-radius: 50%; background: #26314a; color: #b9c6e3;
    display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; flex-shrink: 0; }
.sb-user-name { font-size: 12.5px; font-weight: 700; color: #e8edf3; text-decoration: none;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 120px; display: block; }
.sb-user-role { font-size: 11px; color: #71809a; }
.sb-user form { margin-left: auto; }
@media (max-width: 860px) {
    .app-sidebar { width: 62px; padding: 14px 8px; }
    .sb-logo-text, .sb-item span, .sb-user > div { display: none; }
    .sb-item { justify-content: center; padding: 9px; }
    .sb-live { margin-left: 0; padding: 1px 5px; }
    .sb-live span { display: none; }
}

/* «Графіт»: моно-цифри у метриках */
.mono, .data-table td .num { font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace; }

/* ═══ «Графіт» — бібліотека компонентів (редизайн 2026-08, канвас-референс) ═══
   Використовуйте ці класи замість інлайн-стилів на всіх сторінках. */
.g-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 900px) { .g-stats { grid-template-columns: repeat(2, 1fr); } }
.g-stat { background: #151b23; border: 1px solid #28313d; border-radius: 12px; padding: 16px;
    display: flex; gap: 12px; align-items: flex-start; }
.g-stat-icon { width: 36px; height: 36px; border-radius: 10px; background: rgba(109,141,255,.1);
    display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.g-stat-icon svg { stroke: #8fa8ff; }
.g-stat-label { font-size: 12px; color: #8a96a6; font-weight: 600; }
.g-stat-value { font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 23px;
    font-weight: 600; margin: 3px 0 2px; color: #e8edf3;
    white-space: nowrap; font-variant-numeric: tabular-nums; }  /* число завжди в один рядок */
.g-stat-sub { font-size: 11.5px; color: #71809a; }
.g-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 700;
    padding: 3px 10px; border-radius: 999px; background: rgba(138,150,166,.12); color: #8a96a6; }
.g-pill.ok   { background: rgba(52,211,153,.12);  color: #34d399; }
.g-pill.warn { background: rgba(245,176,76,.13);  color: #f5b04c; }
.g-pill.bad  { background: rgba(248,113,113,.12); color: #f87171; }
.g-pill.acc  { background: rgba(109,141,255,.14); color: #8fa8ff; }
.g-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: #c6d0de;
    background: #161f2a; border: 1px solid #263140; border-radius: 999px; padding: 3px 10px; }
.g-chip b { color: #e8edf3; font-weight: 700; }
.g-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
.g-progress { position: relative; height: 8px; border-radius: 999px; background: #232c38; overflow: hidden; }
.g-progress > i { position: absolute; inset: 0 auto 0 0; border-radius: 999px; display: block;
    width: var(--pct, 0%);
    background: linear-gradient(90deg, #5570e8, #34d399); transition: width .5s ease; }
.g-progress.active > i::after { content: ''; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.22), transparent);
    animation: g-shine 1.6s linear infinite; }
@keyframes g-shine { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.g-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* `flex-wrap: wrap` — аудит 07.09 P2-2: заголовок картки + кнопка-посилання +
   кнопка згортання стояли в НЕРОЗРИВНИЙ рядок, і на 320px сторінка
   /admin/threats їхала вбік (scrollWidth 416 при innerWidth 320). Мобільний
   блок ≤600px має `.card-head { flex-wrap: wrap }`, але `.g-card-title` до
   нього не входив. Перенос тут не шкодить і на широкому екрані: рядок
   переноситься лише тоді, коли інакше не влазить. */
.g-card-title { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin: 0 0 14px;
    font-size: 14.5px; font-weight: 800; color: #e8edf3; }
.g-card-title .spacer { margin-left: auto; }
.g-empty { text-align: center; padding: 34px 18px; color: #71809a; font-size: 13px; }
.g-empty svg { display: block; margin: 0 auto 10px; stroke: #3a4656; }
.g-row-thumb { width: 52px; height: 32px; border-radius: 6px; flex-shrink: 0;
    background: linear-gradient(135deg, #2a3648, #1a222e); }
.g-kv { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; padding: 4px 0; }
.g-kv .k { color: #8a96a6; } .g-kv .v { font-weight: 700; color: #e8edf3; text-align: right; }
.g-ico { display: inline-flex; vertical-align: -3px; }
.g-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.g-grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; }
@media (max-width: 900px) { .g-grid-2, .g-grid-3 { grid-template-columns: 1fr; } }

/* «Графіт»: авторизація */
.auth-card { width: 380px; max-width: 100%; padding: 34px 32px; border-radius: 16px; }
.auth-logo { display: flex; align-items: center; justify-content: center; gap: 10px; color: #e8edf3; }
.auth-sub { text-align: center; font-size: 12.5px; color: #71809a; margin: 8px 0 22px; }
.auth-links { display: flex; justify-content: space-between; font-size: 12px; margin-top: 14px; }
body.narrow { background: radial-gradient(800px 500px at 65% 20%, rgba(109,141,255,.09), transparent), #0e1116; }

/* «Графіт»: форми і дрібна поліровка */
input[type=text], input[type=password], input[type=email], input[type=number], input[type=search], select, textarea {
    background: #10161e; border: 1px solid #28313d; color: #e8edf3; border-radius: 9px; }
input:focus, select:focus, textarea:focus { outline: none; border-color: #6d8dff; box-shadow: 0 0 0 3px rgba(109,141,255,.15); }
::placeholder { color: #5f6c7d; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #29323f; border-radius: 6px; border: 2px solid #0e1116; }
::-webkit-scrollbar-thumb:hover { background: #3a4656; }
::-webkit-scrollbar-track { background: transparent; }
.card { border-radius: 12px; }
h2 { font-weight: 800; letter-spacing: -0.01em; }
.dash-hero-text h2 { font-weight: 800; }

/* ═══ Сайдбар: нижній блок — інструменти, режим, користувач ═══════════════
   Єдина система іконок-кнопок: SVG 17px у квадраті 34×34, підказка на ховер,
   без підкреслень (це кнопки, не текстові посилання). */
.sb-bottom { margin-top: auto; border-top: 1px solid #28313d; padding-top: 14px;
    display: flex; flex-direction: column; gap: 10px; }
.sb-tools { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    gap: 3px; padding: 0 2px; }
/* Кнопки тут — ЗАВЖДИ в один рядок: скільки б їх не дали дозволи, колонки
   ділять ширину порівну, а сама кнопка не роздувається понад 34px. */
.sb-tools .sb-tool { width: 100%; max-width: 34px; margin: 0 auto; }
.sb-tool {
    position: relative; display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; padding: 0; margin: 0; border-radius: 9px;
    background: transparent; border: 1px solid transparent; color: #71809a;
    text-decoration: none; cursor: pointer; font-size: 0;
    transition: background .14s ease, color .14s ease, border-color .14s ease, transform .14s ease;
}
.sb-tool svg { stroke: currentColor; width: 17px; height: 17px; }
.sb-tool:hover { background: #1a2230; border-color: #28313d; color: #c6d0de; transform: translateY(-1px); }
.sb-tool:active { transform: translateY(0) scale(.94); }
.sb-tool:focus-visible { outline: none; border-color: #6d8dff; box-shadow: 0 0 0 3px rgba(109,141,255,.18); }
.sb-tool--restart:hover svg { animation: sb-spin .7s ease-in-out; }
.sb-tool--logout:hover { color: #f0a8a8; background: rgba(248,113,113,.1); border-color: rgba(248,113,113,.28); }
@keyframes sb-spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }

/* Підказка: власний тултіп замість системного title (миттєвий, у стилі теми).
   НАД елементом, а не збоку. Збоку вона лягала просто поверх сусідніх кнопок:
   усі підказки в застосунку висять на елементах, що стоять У РЯД — панель
   інструментів сайдбара (сітка 5 колонок), режим+рестарт, лічильник у таблиці. */
[data-tip] { position: relative; }
[data-tip]::after {
    content: attr(data-tip); position: absolute; left: 50%; bottom: calc(100% + 9px);
    transform: translateX(-50%) translateY(4px); white-space: nowrap;
    background: #1b232e; color: #e8edf3; border: 1px solid #303a48; border-radius: 7px;
    padding: 5px 9px; font-size: 11.5px; font-weight: 600; line-height: 1; letter-spacing: 0;
    opacity: 0; pointer-events: none; z-index: 200;
    /* Показ із затримкою, зникнення миттєве: інакше при веденні курсора вздовж
       ряду підказки спалахують одна за одною і ряд «блимає». */
    transition: opacity .12s ease 0s, transform .12s ease 0s;
    box-shadow: 0 8px 22px rgba(0, 0, 0, .42);
}
/* Стрілка до елемента-власника. ``::before`` у .mode-badge (крапка режиму) і
   .sb-item (рейка активного пункту) вже зайнятий — їх виключаємо. */
[data-tip]:not(.mode-badge):not(.sb-item)::before {
    content: ''; position: absolute; left: 50%; bottom: calc(100% + 5px);
    width: 8px; height: 8px; background: #1b232e;
    border-right: 1px solid #303a48; border-bottom: 1px solid #303a48;
    transform: translateX(-50%) translateY(4px) rotate(45deg);
    opacity: 0; pointer-events: none; z-index: 201;
    transition: opacity .12s ease 0s, transform .12s ease 0s;
}
[data-tip]:hover::after, [data-tip]:focus-visible::after {
    opacity: 1; transform: translateX(-50%) translateY(0); transition-delay: .35s;
}
[data-tip]:not(.mode-badge):not(.sb-item):hover::before,
[data-tip]:not(.mode-badge):not(.sb-item):focus-visible::before {
    opacity: 1; transform: translateX(-50%) translateY(0) rotate(45deg); transition-delay: .35s;
}
/* Сайдбар стоїть біля самого лівого краю екрана, тож центрована підказка на
   його кнопках вилазить за межі вікна і обрізається: кнопка 34px у першій
   колонці сітки інструментів має центр лише за ~18px від краю.
   Тому ВСІ підказки нижнього блоку сайдбара вирівнюємо по лівому краю самого
   елемента — праворуч місця вдосталь (сайдбар навмисно overflow: visible,
   підказка спокійно лягає поверх контенту).
   Правило свідомо загальне, а не «перша кнопка ряду»: інструментів більше, ніж
   колонок у сітці, вони переносяться на наступний рядок, і в першій колонці
   опиняється будь-який з них (на вузькому екрані сітка взагалі в одну колонку —
   тоді ліворуч стоять усі). */
.sb-bottom [data-tip]::after { left: 0; transform: translateX(0) translateY(4px); }
.sb-bottom [data-tip]:hover::after,
.sb-bottom [data-tip]:focus-visible::after { transform: translateX(0) translateY(0); }
/* Стрілка лишається під центром кнопки 34×34, а не під центром підказки. */
.sb-bottom [data-tip]:not(.mode-badge)::before { left: 17px; }
@media (prefers-reduced-motion: reduce) {
    [data-tip]::after, [data-tip]::before { transition: opacity .01s linear; }
    [data-tip]::after { transform: translateX(-50%); }
    [data-tip]:not(.mode-badge):not(.sb-item)::before { transform: translateX(-50%) rotate(45deg); }
    .sb-bottom [data-tip]::after { transform: none; }
    .sb-bottom [data-tip]:not(.mode-badge)::before { transform: translateX(-50%) rotate(45deg); }
}

/* Режим + рестарт — окремий рядок, щоб не змішувались з іконками */
.sb-mode { display: flex; align-items: center; gap: 6px; padding: 0 4px; }
.sb-mode .mode-badge {
    flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    height: 32px; margin: 0; padding: 0 12px; border-radius: 9px;
    font-size: 11.5px; font-weight: 800; letter-spacing: .1em;
    background: #151b23; border: 1px solid #28313d; color: #8a96a6; cursor: pointer;
    transition: background .14s, border-color .14s, color .14s;
}
.sb-mode .mode-badge::before { content: none; }
.sb-mode .mode-badge .mode-dot { width: 7px; height: 7px; border-radius: 50%; background: #71809a; flex-shrink: 0; }
.sb-mode .mode-badge.mode-production { color: #7ee0b0; border-color: rgba(52,211,153,.32); background: rgba(52,211,153,.09); }
.sb-mode .mode-badge.mode-production .mode-dot { background: #34d399; box-shadow: 0 0 0 0 rgba(52,211,153,.5); animation: sb-pulse 2.4s ease-out infinite; }
.sb-mode .mode-badge.mode-development { color: #f5c07c; border-color: rgba(245,176,76,.32); background: rgba(245,176,76,.09); }
.sb-mode .mode-badge.mode-development .mode-dot { background: #f5b04c; }
.sb-mode .mode-badge:hover { filter: none; border-color: #3a4656; background: #1a2230; }
.sb-mode .mode-badge:disabled { opacity: .55; cursor: progress; }
@keyframes sb-pulse {
    0% { box-shadow: 0 0 0 0 rgba(52,211,153,.45); }
    70% { box-shadow: 0 0 0 6px rgba(52,211,153,0); }
    100% { box-shadow: 0 0 0 0 rgba(52,211,153,0); }
}

/* Дзвіночок: лічильник поверх іконки */
.sb-tool.notif-bell .notif-badge {
    position: absolute; top: 1px; right: 1px; min-width: 15px; height: 15px; padding: 0 4px;
    display: none; align-items: center; justify-content: center; box-sizing: border-box;
    border-radius: 999px; background: #dc2626; color: #fff; border: 2px solid #10151c;
    font-size: 9.5px; font-weight: 800; line-height: 1; font-family: 'Manrope', sans-serif;
}
.sb-tool.notif-bell .notif-badge.show { display: inline-flex; }
.sb-tool.is-busy svg { animation: sb-spin 1s linear infinite; }
.sb-tool.is-busy { color: #8fa8ff; background: rgba(109,141,255,.1); }

/* Рядок користувача */
.sb-user { display: flex; align-items: center; gap: 10px; padding: 8px 6px 2px; border-top: 1px solid #1d2530; }
.sb-user-meta { min-width: 0; flex: 1; }
.sb-avatar { width: 32px; height: 32px; border-radius: 10px; background: #26314a; color: #b9c6e3;
    display: flex; align-items: center; justify-content: center; font-size: 11.5px; font-weight: 800; flex-shrink: 0; }
.sb-user-name { display: block; font-size: 12.5px; font-weight: 700; color: #e8edf3; text-decoration: none;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sb-user-name:hover { color: #8fa8ff; }
.sb-user-role { font-size: 11px; color: #71809a; }
.sb-user .inline-logout { margin: 0; display: flex; }
.sb-user .inline-logout button { margin: 0; background: transparent; }

/* Згорнутий сайдбар (вузький екран) — інструменти в колонку, тултіпи лишаються */
@media (max-width: 860px) {
    .sb-tools { grid-auto-flow: row; grid-auto-columns: auto; grid-template-columns: 1fr; }
    .sb-mode { flex-direction: column; }
    .sb-mode .mode-badge { width: 100%; padding: 0 6px; font-size: 10px; letter-spacing: .04em; }
    .sb-user { flex-direction: column; gap: 6px; }
}

/* Панель: розподіл місця на диску */
.disk-bar { display: flex; height: 12px; border-radius: 999px; overflow: hidden; background: #232c38; margin: 2px 0 14px; }
.disk-seg { display: block; height: 100%; width: var(--pct, 0%); transition: width .5s ease; }
/* Сегменти без власного класу-кольору мали інлайн-градієнт у шаблоні. */
.disk-seg--datasets { background: linear-gradient(180deg, #a78bfa, #7c5cd6); }
.disk-seg--trainings { background: linear-gradient(180deg, #7dd3fc, #38a8d8); }
.disk-seg--recordings { background: linear-gradient(180deg, #f472b6, #d1508f); }
.disk-seg--other { background: linear-gradient(180deg, #94a3b8, #6b7a8c); }
.disk-seg--videos { background: linear-gradient(180deg, #7c99ff, #5570e8); }
.disk-seg--frames { background: linear-gradient(180deg, #4ade9f, #2bb583); }
.disk-seg--analysis { background: linear-gradient(180deg, #f7bd6a, #e09a34); }
.disk-legend { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.disk-item { display: flex; gap: 10px; align-items: flex-start; background: #10161e;
    border: 1px solid #232c38; border-radius: 10px; padding: 11px 13px; }
.disk-item .g-dot { margin-top: 5px; flex-shrink: 0; }
.disk-k { font-size: 12px; color: #8a96a6; font-weight: 600; }
.disk-v { font-size: 18px; font-weight: 600; color: #e8edf3; margin: 2px 0 1px; }
.disk-s { font-size: 11px; color: #71809a; }
.disk-note { margin-top: 12px; font-size: 12.5px; color: #8a96a6; }
.disk-note b { color: #e8edf3; }
@media (max-width: 900px) { .disk-legend { grid-template-columns: 1fr; } }

/* ── Носії: скільки лишилось місця (сигнал тривоги, а не просто цифра) ──── */
.disk-mounts { display: grid; gap: 10px; margin: 2px 0 16px; }
.disk-mount { display: grid; grid-template-columns: minmax(120px, 1fr) minmax(90px, 2fr) auto;
    gap: 4px 14px; align-items: center; background: #10161e; border: 1px solid #1c2430;
    border-radius: 10px; padding: 10px 13px; }
.disk-mount-name { font-size: 13px; font-weight: 600; color: #e8edf3; }
.disk-mount-name span { display: block; font-size: 11px; font-weight: 500; color: #71809a; }
.disk-mount-track { position: relative; height: 8px; border-radius: 999px; background: #232c38; overflow: hidden; }
.disk-mount-fill { position: absolute; inset: 0 auto 0 0; border-radius: 999px;
                   width: var(--pct, 0%); transition: width .5s ease; }
.disk-mount-scale { display: flex; justify-content: space-between; gap: 10px; margin-top: 5px;
    font-size: 11px; color: #71809a; white-space: nowrap; }
.disk-mount-scale b { color: #b9c4d2; font-weight: 600; }
.disk-mount-free { font-size: 12px; color: #8a96a6; text-align: right; white-space: nowrap; }
.disk-mount-free b { display: block; font-size: 15px; color: #e8edf3; }
.disk-mount--ok .disk-mount-fill { background: linear-gradient(180deg, #4ade9f, #2bb583); }
.disk-mount--warn .disk-mount-fill { background: linear-gradient(180deg, #f7bd6a, #e09a34); }
.disk-mount--warn { border-color: #6b4a12; }
.disk-mount--critical .disk-mount-fill { background: linear-gradient(180deg, #f28b7a, #d9503a); }
.disk-mount--critical { border-color: #7f2d1d; background: #1a1113; }
/* Похідні дані, які система відбудує сама → їх можна звільнити без втрат */
.disk-seg--cache { background: repeating-linear-gradient(135deg, #5b6c7a 0 6px, #46515f 6px 12px); }
.disk-reclaim { margin-top: 12px; display: flex; gap: 10px; align-items: flex-start;
    background: #16213a; border: 1px solid #263449; border-radius: 10px; padding: 10px 13px;
    font-size: 12.5px; color: #c6d0de; }
.disk-reclaim b { color: #e8edf3; }
.disk-reclaim--warn { background: #2a1f05; border-color: #6b4a12; color: #f7d9a0; }
@media (max-width: 700px) { .disk-mount { grid-template-columns: 1fr; } .disk-mount-free { text-align: left; } }

/* Сайдбар: пункти навігації — плавний ховер + акцентна риска активного */
.sb-item { position: relative; transition: background .14s ease, color .14s ease, padding-left .14s ease; }
.sb-item::before { content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    width: 3px; height: 0; border-radius: 0 3px 3px 0; background: #6d8dff; transition: height .18s ease; }
.sb-item:hover { padding-left: 14px; }
.sb-item.active::before { height: 18px; }
.sb-item svg { transition: stroke .14s ease, transform .14s ease; }
.sb-item:hover svg { transform: scale(1.08); }
.sb-logo { transition: opacity .14s ease; }
.sb-logo:hover { opacity: .85; }
.sb-logo-mark { transition: transform .2s ease, box-shadow .2s ease; }
.sb-logo:hover .sb-logo-mark { transform: rotate(-8deg) scale(1.05); box-shadow: 0 6px 18px rgba(109,141,255,.35); }

/* Камери: сортування + колонка «Ефір» ─────────────────────────────────────── */
/* На вузькому екрані рядок сортування переносився не весь: підказка «спершу ті,
   хто щойно був в ефірі» не мала куди стиснутись і виштовхувала сторінку. */
.cam-sortbar { display: flex; align-items: center; flex-wrap: wrap; gap: 9px; margin: 4px 0 12px; }
.cam-sort-label { font-size: 12px; color: #71809a; font-weight: 600; }
select.cam-sort {
    width: auto; margin: 0; height: 32px; padding: 0 26px 0 10px;
    font-size: 12.5px; font-weight: 700; color: #c6d0de;
    background: #10161e; border: 1px solid #28313d; border-radius: 8px; cursor: pointer;
    transition: border-color .12s, background .12s;
}
select.cam-sort:hover { border-color: #3a4656; background: #161f2a; }
.cam-sort-hint { font-size: 11.5px; color: #5f6c7d; min-width: 0; flex: 1 1 auto; }
.cam-air-cell { white-space: nowrap; }
.cam-air-now {
    display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 700;
    color: #34d399; background: rgba(52,211,153,.1); border-radius: 999px; padding: 3px 9px;
}
.cam-air-now svg { stroke: #34d399; }
.cam-air-when { font-size: 12.5px; color: #a8b4c4; }
.cam-air-count {
    display: inline-block; margin-left: 8px; font-size: 11px; font-weight: 700;
    color: #8fa8ff; background: rgba(109,141,255,.12); border-radius: 999px; padding: 2px 8px;
}
/* Лічильник у таблиці камер користується типовою підказкою (над елементом). */
.cam-air-count[data-tip]:hover::after { transform: translateX(-50%) translateY(0); }

/* ═══ Селекти: єдиний тематичний вигляд по всьому застосунку ═══════════════
   Нативна стрілка ОС виглядає чужорідно в темній темі — замінюємо власним
   шевроном (SVG data-URI) і лишаємо місце під нього справа. Спеціалізовані
   селекти (.vsel, .vstat-prio, .fs-row-folder у таблиці) мають власні правила
   і сюди не потрапляють — див. їхні блоки. */
select {
    -webkit-appearance: none; appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='12'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%238a96a6'%20stroke-width='2.2'%20stroke-linecap='round'%20stroke-linejoin='round'><path%20d='m6%209%206%206%206-6'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
    padding-right: 30px;
    cursor: pointer;
    transition: border-color .14s ease, background-color .14s ease;
}
select:hover { border-color: #3a4656; }
select:disabled { opacity: .5; cursor: not-allowed; }
select option { background: #151b23; color: #e8edf3; }
select option:checked { background: #1f2937; }
/* Селекти в компактних тулбарах: шеврон ближче до краю */
.fs-toolbar select, select.cam-sort, .toolbar select { background-position: right 8px center; }
/* Мультиселект/розгорнутий список — без шеврона (він там недоречний) */
select[multiple], select[size]:not([size="1"]) { background-image: none; padding-right: 10px; }

/* Прихований селект пріоритету: без власного фону/шеврона (він накриває крапку) */
.vstat-prio select { background-image: none; padding: 0; -webkit-appearance: none; appearance: none; }

/* ══════════════════════════════════════════════════════════════════════════
   АДАПТИВ: телефон, планшет, тач (2026-08-20)
   ─────────────────────────────────────────────────────────────────────────
   Правило: усе нижче вмикається лише на вузькому екрані або на тач-пристрої.
   Десктоп (>900px, миша) не змінюється жодним рядком цього блоку.
   Брейкпоінти: 900 — планшет і повноекранні редактори (розмітка, ГІС);
                700 — таблиці переходять у власний горизонтальний скрол;
                600 — телефон: сайдбар стає шухлядою, зʼявляється верхня панель;
                420 — дрібні екрани (iPhone SE тощо).
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Глобальна гігієна ──────────────────────────────────────────────────── */
html {
    -webkit-text-size-adjust: 100%;       /* iOS не роздуває шрифт у ландшафті */
    text-size-adjust: 100%;
}
img, video { max-width: 100%; }

/* Плаваючі елементи поважають «чубчик» і жестову смугу */
#bug-fab { right: calc(16px + env(safe-area-inset-right)); bottom: calc(16px + env(safe-area-inset-bottom)); }
.toast-stack { top: calc(16px + env(safe-area-inset-top)); right: calc(16px + env(safe-area-inset-right));
    max-width: min(360px, calc(100vw - 24px)); }

/* ── Верхня панель телефону (бургер + логотип). За замовчуванням прихована ─ */
.mobile-topbar { display: none; }
.nav-scrim { display: none; }
.tb-group-mobile { display: none; }     /* перемикачі панелей редактора — лише ≤900px */
/* Полотна, на яких малюють: жест належить застосунку, а не браузеру.
   Без цього палець на канві скролив/зумив сторінку замість малювання рамки. */
#annot-canvas, #tile-canvas, .bug-crop-stage canvas { touch-action: none; }
.editor-scrim { display: none; }

/* ══ ≤900px: повноекранні редактори — бічні панелі стають шухлядами ═══════ */
@media (max-width: 900px) {

    /* ── Редактор розмітки ── */
    .editor-shell { grid-template-columns: 1fr; }
    .editor-shell .editor-side {
        position: fixed; top: 0; bottom: 0; z-index: 70;
        width: min(320px, 86vw);
        box-shadow: 0 0 40px rgba(0, 0, 0, .6);
        transition: transform .22s cubic-bezier(.4, 0, .2, 1);
        padding-bottom: calc(24px + env(safe-area-inset-bottom));
    }
    .editor-shell .editor-side.left  { left: 0;  transform: translateX(-102%); }
    .editor-shell .editor-side.right { right: 0; transform: translateX(102%); border-left: 1px solid #242e3a; }
    .editor-shell.side-left-open  .editor-side.left  { transform: none; }
    .editor-shell.side-right-open .editor-side.right { transform: none; }
    /* Затемнення під відкритою шухлядою — клік по ньому закриває */
    .editor-scrim { display: none; position: fixed; inset: 0; z-index: 69; background: rgba(2, 6, 23, .55); }
    .editor-shell.side-left-open .editor-scrim,
    .editor-shell.side-right-open .editor-scrim { display: block; }
    /* Кнопки-перемикачі шухляд — лише тут (на десктопі панелі й так видно) */
    .tb-group-mobile { display: flex; }
    .canvas-wrapper { padding: 6px; }
    .editor-toolbar { position: relative; z-index: 40; }

    /* ── ГІС-редактор: панель керування знизу, а не збоку ── */
    .gis-editor { flex-direction: column; }
    .gis-editor .controls {
        width: 100%; min-height: 0; max-height: 46vh; border-left: 0;
        border-top: 1px solid #28313d;
        padding-bottom: calc(24px + env(safe-area-inset-bottom));
    }
    .gis-editor .map-container { flex: 1 1 54%; min-height: 240px; }
}

/* ══ ≤700px: таблиці скролять усередині себе, а не розпирають сторінку ════ */
@media (max-width: 700px) {
    table {
        display: block;
        width: 100%;
        max-width: 100%;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    /* Таблиця в обгортці .table-scroll лишається таблицею: прокручує обгортка,
       інакше було б два вкладені скролери й «злипання» колонок. */
    .table-scroll > table { display: table; overflow-x: visible; }
    /* Клітинки не мають ламатись у стовпчик з однієї літери */
    table th, table td { white-space: nowrap; }
    table td .cam-src code { white-space: normal; }
    /* Липка шапка всередині блочної таблиці не працює — прибираємо, щоб не лізла */
    #mem-table th { position: static; }

    code,.mono,.cam-src code,.sb-user-name { overflow-wrap: anywhere; }
}

/* ══ Оболонка-шухляда: телефон, а також будь-який ВУЗЬКИЙ ТАЧ-екран ═══════
   Іконкова рейка ≤860px спирається на тултіпи-ховер, яких на тачі немає,
   тож на планшеті/телефоні в ландшафті меню теж має бути шухлядою. */
@media (max-width: 600px), (max-width: 900px) and (pointer: coarse) {

    /* ── Оболонка: сайдбар їде в шухляду, зверху зʼявляється панель ── */
    .mobile-topbar {
        display: flex; align-items: center; gap: 10px;
        position: sticky; top: 0; z-index: 800;
        height: 52px; flex: 0 0 auto;
        padding: 0 12px; padding-top: env(safe-area-inset-top);
        background: #10151c; border-bottom: 1px solid #28313d;
    }
    .mt-burger {
        width: 40px; height: 40px; padding: 0; margin: 0; flex: 0 0 auto;
        display: inline-flex; align-items: center; justify-content: center;
        background: transparent; border: 1px solid #28313d; border-radius: 10px; color: #c6d0de;
    }
    .mt-burger svg { stroke: currentColor; fill: none; }
    .mt-title {
        font-weight: 800; font-size: 14px; letter-spacing: .12em; color: #e8edf3;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .mt-spacer { margin-left: auto; }
    .mt-avatar {
        width: 32px; height: 32px; border-radius: 50%; background: #26314a; color: #b9c6e3;
        display: inline-flex; align-items: center; justify-content: center;
        font-size: 11.5px; font-weight: 700; text-decoration: none; flex: 0 0 auto;
    }

    .app-shell { display: block; }
    .app-main { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }

    .app-sidebar {
        position: fixed; top: 0; bottom: 0; left: 0; z-index: 1200;
        width: min(268px, 84vw); height: 100vh; height: 100dvh;
        padding: 16px 12px calc(16px + env(safe-area-inset-bottom));
        transform: translateX(-102%);
        transition: transform .22s cubic-bezier(.4, 0, .2, 1);
        box-shadow: 0 0 40px rgba(0, 0, 0, .6);
    }
    body.nav-open .app-sidebar { transform: none; }
    body.nav-open { overflow: hidden; }
    .nav-scrim { display: block; position: fixed; inset: 0; z-index: 1100;
        background: rgba(2, 6, 23, .55); opacity: 0; pointer-events: none; transition: opacity .2s ease; }
    body.nav-open .nav-scrim { opacity: 1; pointer-events: auto; }

    /* У шухляді знову є місце — повертаємо підписи, згорнуті правилом ≤860px */
    .app-sidebar .sb-logo-text { display: inline; }
    .app-sidebar .sb-item span { display: inline; }
    .app-sidebar .sb-item { justify-content: flex-start; padding: 11px 10px; }
    .app-sidebar .sb-live { margin-left: auto; padding: 1px 7px; }
    .app-sidebar .sb-live span { display: inline; }
    .app-sidebar .sb-user > div { display: block; }
    .app-sidebar .sb-tools { grid-auto-flow: column; grid-auto-columns: 1fr; grid-template-columns: none; }
    .app-sidebar .sb-mode { flex-direction: row; }
    .app-sidebar .sb-user { flex-direction: row; align-items: center; }

    /* Повноекранні сторінки враховують висоту верхньої панелі */
    body.fullscreen .app-main > .container { height: calc(100dvh - 52px - env(safe-area-inset-top)); }
    /* Шухляди редактора починаються ПІД верхньою панеллю, інакше вона накриває
       їхній заголовок (topbar має вищий z-index — і має його зберегти). */
    .editor-shell .editor-side { top: calc(52px + env(safe-area-inset-top)); }
    .editor-scrim { top: calc(52px + env(safe-area-inset-top)); }
}

/* ══ ≤600px: телефон ══════════════════════════════════════════════════════ */
@media (max-width: 600px) {

    /* ── Контейнер: менше повітря, більше контенту ── */
    .app-main > .container { padding: 14px 12px calc(28px + env(safe-area-inset-bottom)); }
    .container { padding: 16px 12px; }
    .card { padding: 14px 14px; }

    /* ── Типографіка: дрібне на телефоні нечитабельне ── */
    h1 { font-size: 24px; }
    h2 { font-size: 20px; }
    .g-stat-value { font-size: 20px; }
    .muted.small, .small { font-size: 12.5px; }

    /* ── Форми: 16px — поріг, нижче якого Safari сам зумить сторінку ── */
    input[type="text"], input[type="password"], input[type="email"], input[type="number"],
    input[type="search"], input[type="date"], input[type="datetime-local"],
    select, textarea { font-size: 16px; }
    /* Жоден елемент керування не ширший за екран, навіть усередині <label>,
       якому браузер рахує ширину за max-content вкладеного поля. */
    input, select, textarea, button, .button-link, label { max-width: 100%; }
    label > select, label > input, label > textarea { width: 100%; }
    /* Ряди «чекбокс + кілька полів» в одному <label> (кадрування, дедуп) не
       переносились і розпирали сторінку — на телефоні дозволяємо перенос. */
    label:has(> input[type="checkbox"]) {
        display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px;
    }
    /* `:not([class*="u-w-"])` — аудит 07.09 P1-4: без нього вага (0,2,3) глушила
       клас-утиліту ширини (0,1,0) на полях усередині такого ряду. */
    label:has(> input[type="checkbox"]) > input:not([class*="u-w-"]),
    label:has(> input[type="checkbox"]) > select:not([class*="u-w-"]) { width: auto; }
    label:has(> input[type="checkbox"]) > input,
    label:has(> input[type="checkbox"]) > select { flex: 0 1 auto; }
    label:has(> input[type="checkbox"]) > input[type="checkbox"] { flex: 0 0 auto; }
    .gis-page-header,.card-head { flex-wrap: wrap; }

    .assign-controls select,.compose-field,.tb-input-wide,.fs-toolbar input[type="search"],.cam-thr input,.form-row input,.form-row select { min-width: 0; max-width: 100%; }
    .assign-controls select { width: 100%; }

    /* Завантаження відео: зона перетягування на всю ширину, кнопка під нею */
    .upload-form { flex-wrap: wrap; }
    .upload-form label.dropzone { flex: 1 1 100%; padding: 18px 14px; }
    .upload-form #upload-btn { width: 100%; }

    /* ── Сітки й ряди в одну колонку ── */
    .g-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .g-grid-2, .g-grid-3, .dash-cols, .tm-cols, .cam-form, .class-form,
    .disk-legend, .camd-grid-main { grid-template-columns: 1fr; }
    .class-form { grid-template-columns: 1fr auto auto; }
    .card-head { flex-wrap: wrap; gap: 8px; }
    .toolbar, .form-row, .camd-actions, .cam-actions { flex-wrap: wrap; }
    .pager { flex-wrap: wrap; }
    .breadcrumb { flex-wrap: wrap; }

    /* ── Редактор розмітки: панель інструментів не має зʼїдати весь екран ──
       На вузькому екрані два ряди тулбара, переносячись, займали пів-телефона й
       витісняли полотно. Замість переносу — горизонтальна прокрутка кожного ряду:
       усі кнопки лишаються на місці, висота — рівно два ряди. */
    .editor-toolbar .tb-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        -webkit-overflow-scrolling: touch;
        padding: 6px 10px;
    }
    .editor-toolbar .tb-group { flex: 0 0 auto; padding: 0 10px; }
    .editor-toolbar .tb-group-pending,
    .editor-toolbar .tb-group-zoom { margin-left: 0; padding-right: 10px; }
    .tb-group-zoom input[type="range"] { width: 110px; }
    /* Хлібні крихти в повноекранних редакторах на телефоні — зайва висота */
    body.fullscreen .breadcrumb { display: none; }

    /* ── Модалки й тости на всю ширину ── */
    .modal-backdrop { padding: 12px; align-items: flex-end; }
    .modal-card { max-width: 100%; padding: 18px 16px; max-height: 86dvh; overflow-y: auto; }
    .toast-stack { left: 12px; right: 12px; max-width: none; }
    #bug-fab { padding: 9px 13px; font-size: 13px; }
}

/* ══ ≤420px: найвужчі екрани ══════════════════════════════════════════════ */
@media (max-width: 420px) {
    .g-stats { grid-template-columns: 1fr; }
    .app-main > .container { padding: 12px 10px calc(24px + env(safe-area-inset-bottom)); }
    .auth-card { padding: 26px 18px; }
    .class-form { grid-template-columns: 1fr auto; }
    .class-form button { grid-column: 1 / -1; }
}

/* ══ Тач-пристрої (незалежно від ширини) ══════════════════════════════════ */
@media (pointer: coarse) {
    /* Палець не влучає у 20-30px. Мінімум — 40px по короткій стороні. */
    button, .button-link, .tb-btn, .sb-tool, .mode-btn, .layer-btn { min-height: 40px; }
    .editor-toolbar button.tb-btn { min-height: 38px; padding: 7px 11px; }
    .editor-toolbar button.tb-btn-icon { min-width: 38px; }
    .sb-tool { width: 40px; height: 40px; }
    .sb-item { padding: 12px 10px; }
    .bug-thumb-x { width: 28px; height: 28px; }
    .data-table th, .data-table td { padding: 11px 10px; }
    #class-list li, #annotation-list li { padding: 9px 8px; }
    .thumb, .frame-card { -webkit-tap-highlight-color: rgba(109, 141, 255, .25); }

    /* Тултіпи-підказки на ховер тут не існують — не показуємо привидів */
    [data-tip]::after { display: none; }

}

/* ── Бекапи: машина часу (/admin/backups) ──────────────────────────────────
   Сторінка відповідає на три різні питання одними й тими самими даними, тому
   вкладки, а не три сторінки: носій і вибране покоління спільні для всіх трьох
   поглядів, і перемикання не має скидати контекст. */
.btn.sm { padding: 5px 11px; font-size: 12.5px; border-radius: 6px; }
.bk-device-pick { display: flex; align-items: center; gap: 8px; }
/* `min()` — аудит 07.09 P2-2: голий `min-width: 240px` не скасовувався в
   мобільному блоці, і /admin/backups на 320px давав scrollWidth 366. З `min()`
   правило самодостатнє: на вузькому екрані мінімум стискається до ширини
   контейнера, окремий брейкпоінт не потрібен. */
.bk-device-pick select { min-width: min(240px, 100%); }

.bk-tabs { display: flex; gap: 4px; margin: 18px 0 14px; border-bottom: 1px solid #28313d; }
.bk-tab { background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
    padding: 10px 16px; font: inherit; font-size: 14px; font-weight: 700; color: #8a96a6;
    cursor: pointer; border-radius: 8px 8px 0 0; }
.bk-tab:hover { color: #c6d0de; background: #151b23; }
.bk-tab.is-active { color: #dbe4ff; border-bottom-color: #6d8dff; }
.bk-panel > .card { margin-bottom: 18px; }

/* Шкала поколінь: час іде зліва направо, поточний вибір — більша крапка. */
.bk-rail { display: flex; align-items: flex-start; gap: 8px; overflow-x: auto; padding: 4px 2px 2px; }
.bk-node { position: relative; flex: 1 0 92px; display: flex; flex-direction: column; align-items: center;
    gap: 7px; background: none; border: none; padding: 6px 4px 8px; cursor: pointer; font: inherit;
    border-radius: 10px; }
.bk-node:hover { background: #10161e; }
.bk-node::before { content: ''; position: absolute; top: 27px; left: -50%; width: 100%; height: 2px;
    background: #242e3a; }
.bk-node:first-child::before { display: none; }
.bk-node-date { font-size: 12px; font-weight: 600; color: #8a96a6; }
.bk-node-dot { width: 13px; height: 13px; border-radius: 50%; background: #1b232e;
    border: 2px solid #3a4656; position: relative; z-index: 1; }
.bk-node-time { font-size: 11px; color: #71809a; }
.bk-node-delta { font-size: 12px; font-weight: 700; color: #8a96a6; }
.bk-node.is-active .bk-node-date { color: #dbe4ff; font-weight: 700; }
.bk-node.is-active .bk-node-dot { width: 17px; height: 17px; background: #6d8dff; border-color: #0e1116;
    box-shadow: 0 0 0 3px rgba(109,141,255,.35); }
.bk-node.is-broken .bk-node-dot { border-color: #7f1d1d; }
.bk-node.is-broken .bk-node-delta { color: #fecaca; }

.bk-moment { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; margin-top: 20px;
    padding: 14px 18px; background: #10161e; border: 1px solid #242e3a; border-radius: 10px; }
.bk-moment-date { font-size: 18px; font-weight: 800; color: #e8edf3; margin-top: 3px; }
.bk-moment-stats { display: flex; gap: 24px; flex-wrap: wrap; }
.bk-moment-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.bk-label { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: #71809a; font-weight: 700; }
.bk-num { font-size: 15px; font-weight: 700; margin-top: 3px; }
.bk-num--added, td.bk-num--added { color: #34d399; }
.bk-num--changed, td.bk-num--changed { color: #f59e0b; }
.bk-num--removed, td.bk-num--removed { color: #f87171; }

.bk-split { display: grid; grid-template-columns: 420px minmax(0, 1fr); gap: 18px; align-items: start; }
.bk-split--log { grid-template-columns: 380px minmax(0, 1fr); }

/* Дерево файлів на вибраний момент. */
.bk-crumbs { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-bottom: 10px; }
.bk-crumb { background: none; border: none; padding: 2px 4px; font: inherit; font-size: 12.5px;
    color: #8fa8ff; cursor: pointer; border-radius: 5px; }
.bk-crumb:hover { background: #10161e; }
.bk-crumb-sep { color: #3a4656; font-size: 12px; }
.bk-row { display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 8px; border: none;
    background: none; font: inherit; font-size: 13.5px; color: #c6d0de; cursor: pointer;
    border-radius: 7px; text-align: left; }
.bk-row:hover { background: #10161e; color: #e6ebf2; }
.bk-row-icon { display: flex; color: #71809a; flex-shrink: 0; }
.bk-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bk-row-size { flex-shrink: 0; }
.bk-chip { padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 700; flex-shrink: 0; }
.bk-dot--added, .bk-chip.bk-dot--added { background: #14532d; color: #bbf7d0; }
.bk-dot--changed, .bk-chip.bk-dot--changed { background: #78350f; color: #fde68a; }
.bk-dot--same, .bk-chip.bk-dot--same { background: #232c38; color: #8a96a6; }
.bk-dot--absent, .bk-chip.bk-dot--absent { background: #1b232e; color: #71809a; }

/* Картка файла та стрічка його версій. */
.bk-file-head { display: flex; align-items: flex-start; gap: 12px; padding-bottom: 14px;
    border-bottom: 1px solid #242e3a; margin-bottom: 14px; }
.bk-file-head .bk-row-icon { color: #8fa8ff; }
.bk-file-name { font-size: 16px; font-weight: 800; color: #e8edf3; }
.bk-file-path { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #71809a; margin-top: 3px;
    word-break: break-all; }
.bk-ribbon { display: flex; align-items: center; gap: 7px; margin: 4px 0 6px; flex-wrap: wrap; }
.bk-ribbon .bk-dot { width: 11px; height: 11px; border-radius: 50%; padding: 0; }
.bk-versions { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.bk-version { display: flex; align-items: center; gap: 14px; padding: 11px 14px; border-radius: 10px;
    border: 1px solid #28313d; background: #10161e; flex-wrap: wrap; }
.bk-version.is-current { border-color: rgba(109,141,255,.45); background: rgba(109,141,255,.10); }
.bk-version-when { font-size: 13.5px; font-weight: 700; color: #e6ebf2; min-width: 150px; }
.bk-version-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* Журнал змін. */
.bk-log-item { display: block; width: 100%; text-align: left; border: 1px solid #28313d; background: #10161e;
    border-radius: 10px; padding: 12px 14px; margin-bottom: 8px; cursor: pointer; font: inherit; color: inherit; }
.bk-log-item:hover { border-color: #3a4656; }
.bk-log-item.is-active { border-color: rgba(109,141,255,.45); background: rgba(109,141,255,.10); }
.bk-log-when { font-size: 14px; font-weight: 700; color: #e6ebf2; display: flex; align-items: center; gap: 8px; }
.bk-log-stats { display: flex; gap: 14px; margin-top: 9px; font-size: 12.5px; font-weight: 700; }
.bk-log-delta { margin-left: auto; color: #c6d0de; }
.bk-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-top: 14px; }
.bk-card { background: #10161e; border: 1px solid #242e3a; border-radius: 10px; padding: 12px 14px; }
.bk-card-num { font-size: 20px; font-weight: 800; margin-top: 4px; color: #8a96a6; }
.data-table tr.bk-quiet td { color: #71809a; }

.bk-searchbar { display: flex; gap: 10px; flex-wrap: wrap; }
.bk-searchbar .tb-input { flex: 1; min-width: min(260px, 100%); }   /* аудит 07.09 P2-2 */

/* Новий бекап: профілі й носії — рядки, клікабельні цілком. */
.bk-profiles { display: flex; flex-direction: column; gap: 8px; }
.bk-profile { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid #2c3646;
    border-radius: 8px; background: #10161e; cursor: pointer; }
.bk-profile:hover { border-color: #3a4656; }
.bk-profile.is-required { cursor: default; }
.bk-profile-name { flex: 1; font-size: 13.5px; }
.bk-target { display: flex; align-items: center; gap: 12px; padding: 11px 12px; border: 1px solid #2c3646;
    border-radius: 8px; background: #10161e; margin-bottom: 8px; cursor: pointer; }
.bk-target:hover { border-color: #3a4656; }
.bk-target input[disabled] { cursor: not-allowed; }
.bk-target-main { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.bk-target-actions { display: flex; gap: 6px; flex-shrink: 0; }
.bk-verdict { font-size: 12.5px; }
.bk-verdict--ok { color: #34d399; }
.bk-verdict--warn { color: #fbbf24; }
.bk-encrypt { display: flex; align-items: center; gap: 10px; cursor: pointer; }
#bk-password-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
#bk-password-row .tb-input { max-width: 300px; }
.bk-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.bk-crypto-inputs { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.bk-crypto-inputs .tb-input { max-width: 280px; }
#bk-crypto-chip { flex-shrink: 0; }

@media (max-width: 1000px) {
    .bk-split, .bk-split--log { grid-template-columns: minmax(0, 1fr); }
    .bk-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
    .bk-tabs { overflow-x: auto; }
    .bk-moment-actions { margin-left: 0; }
    .bk-target { flex-wrap: wrap; }
    .bk-target-actions { width: 100%; justify-content: flex-end; }
}

/* Підсвітка щойно оновленого лічильника (js/core/live-counters.js).
   Коротка й ненав'язлива: мета — щоб зміну помітили краєм ока, а не щоб
   сторінка мерехтіла. Тим, хто просив менше руху, анімацію не показуємо. */
@keyframes live-bump {
    0%   { background: rgba(96,165,250,0.28); }
    100% { background: transparent; }
}
.live-bump { animation: live-bump 900ms ease-out; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) {
    .live-bump { animation: none; }
}

/* Смуга кадрів над зображенням у редакторі розмітки: увесь фільм одним
   поглядом. Малюється на canvas, а не тисячею <div>: на відео з 4653 кадрами
   стільки вузлів у DOM з'їли б і памʼять, і кожен перемальовок. */
.frame-strip {
    display: block;
    width: 100%;
    height: 18px;
    margin: 0 0 4px;
    border: 1px solid #28313d;
    border-radius: 4px;
    background: #0e1116;
    cursor: pointer;
}
.frame-strip-legend {
    display: flex;
    gap: 14px;
    align-items: center;
    margin: 0 0 8px;
    flex-wrap: wrap;
}
.frame-strip-legend i {
    display: inline-block;
    width: 10px; height: 10px;
    border-radius: 2px;
    margin-right: 5px;
    vertical-align: -1px;
}

/* ── Панель «обʼєкти відео» (права шухляда редактора) ─────────────────────
   Хибне спрацювання — це ОДИН обʼєкт на сотні кадрів, тож картка обʼєкта
   мусить одразу відповідати на три питання: що це, скільки кадрів і де. */
.objects-panel { margin-top: 18px; border-top: 1px solid #242e3a; padding-top: 12px; }
.objects-head {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 4px;
}
.objects-head .muted { font-weight: 400; }
.objects-hint { margin: 0 0 8px; line-height: 1.35; }
.objects-icon-btn {
    margin: 0 0 0 auto;
    padding: 2px 7px;
    background: #151b23;
    border: 1px solid #28313d;
    border-radius: 6px;
    color: #93a1b3;
    font-size: 13px;
    line-height: 1.3;
    cursor: pointer;
}
.objects-icon-btn:hover { background: #28313d; color: #e6ebf2; }
.objects-icon-btn.danger { color: #fca5a5; border-color: #4c2626; }
.objects-icon-btn.danger:hover { background: #7f1d1d; color: #fff; }
.objects-actions { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.objects-btn {
    margin: 0;
    padding: 5px 9px;
    background: #151b23;
    border: 1px solid #28313d;
    border-radius: 6px;
    color: #e6ebf2;
    font-size: 12px;
    cursor: pointer;
}
.objects-btn:hover { border-color: #6d8dff; }
.objects-btn:disabled { opacity: .45; cursor: not-allowed; }
.objects-btn.danger { background: #7f1d1d; border-color: #991b1b; color: #fecaca; }
.objects-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.object-card {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px;
    background: #10161e;
    border: 1px solid #242e3a;
    border-radius: 8px;
    cursor: pointer;
}
.object-card:hover { border-color: #6d8dff; }
.object-card.selected { border-color: #6d8dff; background: #16203a; }
.object-check { width: 14px; height: 14px; margin: 0; flex: 0 0 auto; }
.object-thumb {
    flex: 0 0 auto;
    width: 76px;
    height: 56px;
    background: #000;
    border-radius: 5px;
}
.object-info { flex: 1; min-width: 0; }
.object-title {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    font-weight: 600;
    color: #e6ebf2;
    /* Довга назва класу не мусить робити картку вдвічі вищою за сусідні. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.object-title .object-dot { flex: 0 0 auto; }
.object-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.object-meta {
    margin-top: 2px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-size: 10.5px;
    color: #93a1b3;
}
.object-tag {
    display: inline-block;
    margin-right: 4px;
    padding: 1px 5px;
    background: #1e2836;
    border-radius: 4px;
    color: #cbd5e1;
    font-size: 10px;
}
.object-tag.pending { background: #3a2440; color: #f0abfc; }

/* ── Права шухляда редактора: сталий каркас ──────────────────────────────
   Список анотацій на кадрі щокадру різної довжини (0 рамок / 20 рамок), і
   поки він просто «тік» зверху, панель обʼєктів під ним стрибала вгору-вниз
   на кожному переході. Тепер шухляда — колонка з фіксованими зонами: список
   анотацій крутиться у СВОЄМУ вікні, панель обʼєктів завжди на тому самому
   місці. */
.editor-side.right {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.editor-side.right > h3 { flex: 0 0 auto; }
.editor-side.right > #annotation-list {
    flex: 0 0 34%;
    min-height: 108px;
    margin-bottom: 8px;
    overflow-y: auto;
}
.editor-side.right > #finish-polygon { flex: 0 0 auto; }
.objects-panel {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.objects-panel .objects-head,
.objects-panel .objects-hint,
.objects-panel .objects-actions,
.objects-panel #objects-status { flex: 0 0 auto; }
.objects-list { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding-right: 2px; }
/* Бейдж обʼєкта в рядку анотації: id + скільки таких рамок у всьому відео. */
button.obj-badge, .obj-badge-flat {
    padding: 1px 6px;
    background: #1e2836;
    border: 1px solid #2c3a4d;
    border-radius: 5px;
    color: #cbd5e1;
    font-size: 10.5px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    white-space: nowrap;
}
button.obj-badge { cursor: pointer; line-height: 1.4; }
button.obj-badge:hover { border-color: #6d8dff; color: #e6ebf2; }
/* Підсвітка картки, на яку перекинув клік по бейджу. Клас саме obj-flash:
   глобальний .flash — це банер-повідомлення зі своїми відступами. */
.object-card.obj-flash { animation: obj-flash 1.2s ease-out; }
@keyframes obj-flash {
    0%, 40% { border-color: #6d8dff; background: #1d2942; }
    100% { border-color: #242e3a; background: #10161e; }
}
/* «2+ у кадрі» — обʼєкт ділить кадр з іншими рамками; такі згори списку. */
.object-tag.crowded { background: #33291a; color: #fcd34d; }

/* ── Кольорові крапки-легенди й дрібні спільні модифікатори ─────────────────
 * Колір крапки — це ДАНІ легенди, а не оформлення конкретного місця, тому
 * заводимо іменовані модифікатори замість інлайн-стилю в шаблоні.
 */
.g-dot--blue { background: #6d8dff; }
.g-dot--green { background: #34d399; }
.g-dot--amber { background: #f5b04c; }
.g-dot--violet { background: #a78bfa; }
.g-dot--sky { background: #7dd3fc; }
.g-dot--pink { background: #f472b6; }
.g-dot--slate { background: #94a3b8; }
.g-dot--gray { background: #5b6c7a; }
.g-dot--orange { background: #f59e0b; }
.g-dot--dim { background: #28313d; }

/* Обрізання довгого тексту в один рядок (списки, картки). */
.g-ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Поле форми, що тягнеться, але не вужче за читабельну ширину. */
.g-field-grow { flex: 1; min-width: min(240px, 100%); }
.g-field-grow--wide { flex: 1; min-width: min(280px, 100%); }
.g-field-grow--row { flex: 1 1 320px; }
.g-col-min { min-width: min(130px, 100%); }
/* Панель масової дії над камерами — попереджувальний акцент. */
.cam-bulk-card { border: 1px solid #3b3410;
                 background: linear-gradient(180deg, rgba(234,179,8,.04), transparent); }
/* Дашборд: підписи у списках джоб і відео. */
.dash-progress-pct { font-size: 12px; color: #8fa8ff; }
.dash-job-msg { font-size: 11.5px; margin-top: 3px; }
.dash-video-name { font-size: 13px; font-weight: 700; color: #e8edf3; display: block; }
.dash-video-meta { font-size: 11.5px; color: #71809a; }
/* Хмарний міст: попередження про відсутність готових версій. */
.cb-warn { color: #f59e0b; }

/* Редактор розмітки: бейдж стану класу, підказка режиму, рядок на всю сітку. */
.ae-badge { font-size: 0.7rem; padding: 1px 6px; background: #3a4656; margin-left: 6px; }
.ae-hint { margin-top: 6px; padding: 6px 8px; background: #151b23;
           border-radius: 4px; border-left: 3px solid #6d8dff; }
.ae-row-full { grid-column: 1 / -1; }

/* ── Спільні дрібні компоненти, що раніше жили інлайн-стилями ───────────────
 * Ті самі значення, що були в шаблонах: заміна не міняє вигляду, але дає одне
 * місце правки й вмикає теми.
 */
/* Панель-вкладка під заголовком (розгортається кнопкою). */
.g-panel { margin-top: 12px; padding: 12px; border: 1px solid #28313d; border-radius: 6px; }
.g-panel--tight { margin-top: 8px; padding: 10px; }
.g-panel--wide { margin-top: 14px; }
/* Вкладена «врізка»: темніше тло, тонша рамка. */
.g-inset { border: 1px solid #242e3a; border-radius: 4px; background: #10161e; }
.g-inset--pad { padding: 8px 10px; }
.g-inset--mt { margin-top: 4px; }
.g-inset--scroll { max-height: 300px; overflow-y: auto; }
.g-inset--scroll-sm { max-height: 220px; overflow-y: auto; }
/* Ряд опцій, що переносяться. */
.g-optrow { display: flex; gap: 14px; flex-wrap: wrap; }
.g-optrow--bottom { align-items: flex-end; }
/* Чип-значення (параметри прогону, теги). */
.g-chip-sm { display: inline-block; padding: 2px 8px; border-radius: 10px;
             font-size: 11px; line-height: 16px; white-space: nowrap; }
.g-chip-sm--key { background: rgba(80,140,255,.16); color: #9cc0ff; border: 1px solid rgba(80,140,255,.3); }
.g-chip-sm--rest { background: rgba(120,130,150,.10); color: #6b7585; border: 1px solid rgba(120,130,150,.15); }
.g-chip-sm--special { background: rgba(180,140,80,.18); color: #e0b87a; border: 1px solid rgba(180,140,80,.3); }
/* Сітка форм: автозаповнення й повнорядковий елемент. */
.g-grid-auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }
.g-grid-auto--tight { gap: 4px; }
.g-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 8px; }
.g-row-full { grid-column: 1 / -1; }
.g-row-full--mt { grid-column: 1 / -1; margin-top: 6px; }
/* Підсумковий блок під панеллю. */
.g-stats-box { margin-top: 12px; padding: 10px; background: #0e1116; border-radius: 6px; }
/* Неактивне посилання навігації (немає куди йти). */
.g-nav-off { opacity: .4; cursor: default; }
/* Кольорові акценти тексту. */
.g-text-amber { color: #f59e0b; }
.g-text-pink { color: #ec4899; }
.g-text-blue { color: #cfe0ff; }
.g-text-bright { color: #eaf1ff; }
.g-text-soft { color: #dfe5ee; }
.g-text-warn { color: #e0b87a; }
.g-text-bad { color: #ef4444; }
/* Кастомні набори аугментацій/гіперпараметрів — показуються скриптом. */
.dv-custom { border: 1px solid #28313d; border-radius: 6px; padding: 10px; }
/* Чипи параметрів прогону: ключові / другорядні. */
.g-chip-sm--param { background: rgba(80,140,255,.14); color: #cfe0ff; border: 1px solid rgba(80,140,255,.28); }
.g-chip-sm--muted { background: rgba(120,130,150,.12); color: #aeb6c4; border: 1px solid rgba(120,130,150,.22); }
/* Версія датасету: широка сітка налаштувань і комірка прогресу. */
.dv-grid-wide { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 14px; }
.dv-progress-cell { display: flex; align-items: center; gap: 8px; min-width: min(150px, 100%); }
/* Вузьке числове поле всередині рядка таблиці/форми. */
.g-inline-num { width: 90px; padding: 4px; background: #10161e; color: #e6ebf2;
                border: 1px solid #242e3a; border-radius: 4px; }
.g-inline-num--sm { width: 70px; }

/* ─────────────── Схований стан: остання лінія оборони ────────────────────
 *
 * `.u-d-none` живе в utilities.css і має вагу (0,1,0) — рівно стільки ж, скільки
 * в компонентних класів, які САМІ вмикають display (.modal-backdrop → flex,
 * .tbtn → inline-flex, .card → block …). Тобто «сховане» вигравало ЛИШЕ за
 * рахунок порядку підключення файлів. Один збій доставки utilities.css (стара
 * копія в кеші браузера, проксі, помилка деплою) — і кожен такий елемент
 * розкривався сам собою; для модалки повторного розкадрування це означало вікно
 * з НЕЗВОРОТНОЮ дією просто при відкритті сторінки.
 *
 * Ваги (0,2,0) теж НЕ ВИСТАЧИЛО: правило на ID (`#extract-progress {display:flex}`)
 * має вагу (1,0,0) і перебивало її — смужка кадрування показувалась на кожному
 * завантаженні сторінки. Тому `!important`: сховане має бути АБСОЛЮТНИМ.
 *
 * Це безпечно саме тепер: видимістю керують лише `Sky.show/hide/setShown`
 * (core/dom.js), які СПОЧАТКУ знімають клас, а вже потім чіпають інлайн. Поки
 * клас на елементі — елемент має бути схований, конкуренції за це немає.
 * Дубль оголошення тут, у ядрі, лишає елемент схованим навіть якщо utilities.css
 * узагалі не доїхав. */
.u-d-none { display: none !important; }
