/* ===== Ported verbatim from the original uu.dakservice.ru style.css ===== */

html {
    font-size: 16px;
}

body {
    background-color: #2c3e50;
    color: #ecf0f1;
    font-family: Arial, sans-serif;
    text-align: center;
    margin: 0;
    padding: 0;
}

.dev-banner {
    background-color: #e67e22;
    color: #2c3e50;
    font-weight: bold;
    font-size: 0.85rem;
    text-align: center;
    padding: 6px 10px;
}

/* Persistent "Просмотр как…" banner (includes/header.php) — shown on every
   page while a real admin is previewing another role. Purple, not orange,
   so it's never confused with .dev-banner above at a glance (dev/prod is
   an environment fact; this is a per-account preview state) and reads as
   "you're the one who turned this on", not "something is wrong". */
.role-sim-banner {
    background-color: #8e44ad;
    color: #fff;
    font-size: 0.85rem;
    padding: 6px 10px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.role-sim-banner form {
    margin: 0;
}

h1 {
   font-size:20px;
}

h2 {
   font-size:20px;
}

.button {
    background-color: #3498db;
    color: #ecf0f1;
    border: none;
    padding: 10px 15px;
    cursor: pointer;
    border-radius: 5px;
    transition: background-color 0.3s;
}

.button:hover {
    background-color: #2980b9;
}

main {
    padding: 20px;
}

.login-container {
    width: 100%;
    max-width: 300px;
    margin: 30px auto;
    padding: 15px;
    background-color: #34495e;
    border-radius: 8px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.login-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.input-field {
    padding: 10px 8px;
    border: 1px solid #bdc3c7;
    border-radius: 5px;
    background-color: #ecf0f1;
    font-size: 16px; /* iOS Safari zooms in on focus if an input's font-size is under 16px */
    color: #2c3e50;
    width: 100%;
    box-sizing: border-box;
}

.input-field:focus {
    border-color: #3498db;
    outline: none;
}

.login-button {
    background-color: #3498db;
    color: white;
    border: none;
    padding: 12px 16px;
    font-size: 16px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
    width: 100%;
    box-sizing: border-box;
}

.login-button:hover {
    background-color: #2980b9;
}

.error {
    color: #e74c3c;
    font-size: 12px;
    margin-bottom: 8px;
}

.success {
    color: #27ae60;
    font-size: 12px;
    margin-bottom: 8px;
}

.header-container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #34495e;
    padding: 10px 20px;
    flex-wrap: wrap;
    gap: 10px;
}

.nav-buttons {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: center;
}

.nav-buttons button,
.nav-buttons a {
    background-color: #3498db;
    color: #ecf0f1;
    border: none;
    padding: 8px 12px;
    cursor: pointer;
    border-radius: 5px;
    transition: background-color 0.3s;
    text-decoration: none;
    display: inline-block;
    font-size: 0.8rem;
}

.nav-buttons button:hover,
.nav-buttons a:hover {
    background-color: #2980b9;
}

.nav-buttons:not(.admin-subnav) a.active {
    background-color: #f1c40f;
    color: #2c3e50;
}

.nav-buttons:not(.admin-subnav) a.active:hover {
    background-color: #d4ac0d;
}

.nav-buttons.admin-subnav a.active {
    background-color: #1abc9c;
}

.nav-buttons.admin-subnav a.active:hover {
    background-color: #16a085;
}

/* Icon shown only on mobile (see the @media block below) — a plain <span>
   inside each .nav-buttons/.admin-subnav/.lookup-tabs link, kept out of
   the desktop rendering entirely (not just visually collapsed) so desktop
   stays byte-for-byte the same button labels it always had. */
.tab-icon {
    display: none;
}

.logout-form {
    display: inline-flex;
    margin: 0;
}

.logout-button {
    background-color: #e74c3c;
    color: white;
    text-decoration: none;
    padding: 10px 15px;
    border: none;
    border-radius: 5px;
    transition: background-color 0.3s;
    font-size: 14px;
    font-family: inherit;
    cursor: pointer;
}

.logout-button:hover {
    background-color: #c0392b;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    justify-content: flex-end;
    margin-left: auto;
}

.header-icons {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Контейнер таблицы */
.table-container {
    flex-grow: 1;
    min-height: 0;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid #2c3e50;
    position: relative;
    background-color: #34495e;
    border-radius: 8px;
    margin: 0 20px 20px;
}

/* orders.php's mobile card list — see that file for why (many-field record
   list, not a comparison-heavy grid) and CLAUDE.md's "Push-уведомления
   (PWA)" section for the research behind the choice. Hidden by default;
   the mobile media query below swaps it in for .orders-table-container. */
.orders-cards {
    display: none;
}

.order-card {
    display: block;
    background-color: #34495e;
    border-radius: 8px;
    margin: 0 20px 12px;
    padding: 12px 14px;
    text-decoration: none;
    color: inherit;
}

.order-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid #2c3e50;
}

.order-card-title {
    font-weight: bold;
    color: #ecf0f1;
}

/* One row per field — label left, value right, same left-border-stripe
   .band-* health coloring the table's cells use (order_cell_band() in
   orders.php decides good/warn/bad the same way for both views). */
.order-card-field {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding: 4px 0 4px 8px;
    font-size: 0.85rem;
    border-left: 3px solid transparent;
}

.order-card-label {
    color: #95a5a6;
}

.order-card-value {
    text-align: right;
}

.order-card-field.band-good {
    border-left-color: #7ee787;
}

.order-card-field.band-warn {
    border-left-color: #f39c12;
}

.order-card-field.band-bad {
    border-left-color: #e74c3c;
}

/* Report pages (Заказы, Табеля): without a bounded height, .table-container
   never actually scrolls internally — the whole page scrolls instead, which
   leaves the (already-sticky) thead with no real scrolling ancestor to stick
   within. Turning the page into a fixed-viewport shell so only the table body
   scrolls gives thead's position:sticky something to pin against. Scoped to
   #ordersTable / .timesheet-table so other pages (forms, admin screens) keep
   normal page scroll. */
body:has(#ordersTable),
body:has(.timesheet-table),
body:has(.schedule-table) {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

body:has(#ordersTable) header,
body:has(.timesheet-table) header,
body:has(.schedule-table) header {
    flex-shrink: 0;
}

body:has(#ordersTable) main,
body:has(.timesheet-table) main,
body:has(.schedule-table) main {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* The table is the main working document on these pages — every px of
       chrome above it (title, month/filter controls) is px the grid loses.
       Tighter than the generic 20px `main` padding used by ordinary pages. */
    padding-top: 10px;
    padding-bottom: 10px;
}

body:has(#ordersTable) main > h1,
body:has(#ordersTable) .column-toggles-dropdown,
body:has(#ordersTable) .orders-toolbar,
body:has(.timesheet-table) main > h1,
body:has(.timesheet-table) .button-container,
body:has(.timesheet-table) .timesheet-toolbar,
body:has(.schedule-table) main > h1,
body:has(.schedule-table) .schedule-range-form {
    flex-shrink: 0;
}

body:has(#ordersTable) main > h1,
body:has(.timesheet-table) main > h1,
body:has(.schedule-table) main > h1 {
    margin: 4px 0 10px;
}

/* Month title + buttons + archive checkbox, merged into one row on
   timesheets.php's grid view — sized down to match the compact scale of
   the top nav (.nav-buttons: 0.8rem, 8px/12px padding) instead of the
   larger defaults .month/.checkbox-label carry for their other context
   (the month-picker grid, and forms elsewhere), which looked oversized
   next to both the nav above and the table below. */
.timesheet-month-header h1 {
    font-size: 15px;
}

.timesheet-month-header .month {
    flex: 0 0 auto;
    padding: 8px 12px;
    font-size: 0.8rem;
}

.timesheet-month-header .checkbox-label {
    font-size: 0.8rem;
}

/* Таблица */
table {
    width: 100%;
    border-collapse: collapse;
    background-color: #34495e;
    color: #ecf0f1;
    font-size: 12px;
    table-layout: auto;
}

/* Фиксированный заголовок */
thead {
    position: sticky;
    top: 0;
    background-color: #1abc9c;
    /* Выше 101 у липкого первого столбца ниже: иначе ячейки первой колонки
       при вертикальной прокрутке проезжают ПОВЕРХ заголовков. */
    z-index: 102;
}

thead th {
    padding: 8px;
    text-align: center;
    font-weight: bold;
    border-bottom: 2px solid #16a085;
    white-space: nowrap;
}

tbody td {
    padding: 6px;
    border-bottom: 1px solid #2c3e50;
    text-align: center;
    white-space: nowrap;
}

td:first-child, th:first-child {
    position: sticky;
    left: 0;
    background-color: #1abc9c;
    font-weight: bold;
    z-index: 101;
}

/* Стили для формы */
.form-container {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    margin-top: 10px;
    gap: 8px;
}

.form-container .btn {
    align-self: center;
}

/* Bare textarea outside .form-table/fieldset (feedback.php's single-field
   form doesn't need the full labeled-grid treatment those use) — same
   palette as .form-input textarea, just not nested inside that wrapper. */
.form-container textarea {
    width: 100%;
    max-width: 600px;
    padding: 8px;
    border: 1px solid #16a085;
    border-radius: 5px;
    background-color: #2c3e50;
    color: #ecf0f1;
    font-family: inherit;
    font-size: 1rem;
    resize: vertical;
}

/* Карточки на странице обратной связи. text-align: left обязателен: body
   задаёт center по умолчанию, из-за чего и обращение, и ответ читались как
   стихотворение в столбик. Тот же приём уже применён к .help-page. */
.feedback-message {
    background-color: #34495e;
    border-radius: 8px;
    padding: 16px 18px;
    max-width: 700px;
    margin: 0 auto 12px;
    text-align: left;
}

/* Форма ответа выравнивается по той же колонке, что и карточки выше, —
   иначе заголовки по центру страницы, а карточки и форма прижаты влево,
   как было до 2026-09-04. Тот же приём, что и у .help-page. */
.feedback-reply-form {
    max-width: 700px;
    margin-left: auto;
    margin-right: auto;
    text-align: left;
}

/* Ответ администратора отличается от самого обращения полосой слева — иначе
   в ленте из обращения и нескольких ответов все карточки одинаковые. */
.feedback-reply {
    border-left: 3px solid #3498db;
}

.feedback-message-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 10px;
}

.feedback-message p {
    white-space: pre-wrap;
    margin: 0;
}

/* Статус доставки по каналам: каждый канал — отдельный элемент, расстояние
   между ними задаётся здесь, а не пробелами в шаблоне. */
.feedback-delivery {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid rgba(236, 240, 241, 0.12);
}

.help-page {
    max-width: 760px;
    margin: 0 auto;
    text-align: left;
}

.help-page > .field-hint {
    text-align: left;
    border-top: none;
    padding-top: 0;
    font-size: 0.85rem;
    margin-bottom: 18px;
}

.help-section {
    background-color: #34495e;
    border-radius: 8px;
    margin-bottom: 14px;
    overflow: hidden;
}

.help-section > summary {
    cursor: pointer;
    padding: 14px 18px;
    font-size: 1.05rem;
    font-weight: bold;
    list-style: none;
    display: flex;
    align-items: center;
    gap: 8px;
}

.help-section > summary::-webkit-details-marker {
    display: none;
}

.help-section > summary::before {
    content: '▸';
    color: #16a085;
    transition: transform 0.15s;
}

.help-section[open] > summary::before {
    transform: rotate(90deg);
}

.help-section-body {
    padding: 4px 18px 18px;
}

.help-section-body h3 {
    font-size: 1rem;
    margin: 18px 0 6px;
    color: #1abc9c;
}

.help-section-body h3:first-child {
    margin-top: 4px;
}

.help-section-body p,
.help-section-body li {
    font-size: 0.9rem;
    line-height: 1.5;
}

.help-section-body ul,
.help-section-body ol {
    padding-left: 22px;
    margin: 6px 0;
}

.help-role {
    background-color: #2c3e50;
    border-radius: 6px;
    margin: 10px 0;
}

.help-role > summary {
    cursor: pointer;
    padding: 10px 14px;
    font-weight: bold;
    list-style: none;
}

.help-role > summary::-webkit-details-marker {
    display: none;
}

.help-role > summary::before {
    content: '▸ ';
    color: #16a085;
}

.help-role[open] > summary::before {
    content: '▾ ';
}

.help-role-body {
    padding: 2px 14px 14px;
    font-size: 0.88rem;
    line-height: 1.5;
}

.help-role-you {
    background-color: rgba(26, 188, 156, 0.18);
}

.help-role-you > summary::after {
    content: ' — это вы';
    color: #1abc9c;
    font-weight: normal;
    font-size: 0.8rem;
}

.help-admin-article {
    background-color: #34495e;
    border-radius: 8px;
    margin: 0 auto 14px;
    max-width: 700px;
    text-align: left;
    padding-bottom: 4px;
}

.help-admin-article > summary {
    cursor: pointer;
    padding: 12px 16px;
    font-weight: bold;
}

.help-admin-form,
.help-admin-add {
    padding: 0 16px 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.help-admin-add {
    background-color: #34495e;
    border-radius: 8px;
    margin: 0 auto;
    max-width: 700px;
    padding-top: 16px;
    text-align: left;
}

.help-admin-form label,
.help-admin-add label {
    display: block;
    font-weight: bold;
    font-size: 0.85rem;
    margin-bottom: 10px;
}

.help-admin-form input,
.help-admin-form select,
.help-admin-form textarea,
.help-admin-add input,
.help-admin-add select,
.help-admin-add textarea {
    width: 100%;
    box-sizing: border-box;
    padding: 8px;
    border: 1px solid #16a085;
    border-radius: 5px;
    background-color: #2c3e50;
    color: #ecf0f1;
    font-family: inherit;
    font-size: 0.9rem;
    margin-top: 4px;
}

.help-admin-form textarea,
.help-admin-add textarea {
    resize: vertical;
}

.form-table {
    display: table;
    border-spacing: 10px;
    background-color: #34495e;
    padding: 15px;
    border-radius: 10px;
    font-size: 14px;
    margin: 0 auto;
}

.form-header, .form-row {
    display: table-row;
}

.form-label, .form-input {
    display: table-cell;
    padding: 5px;
    text-align: center;
    vertical-align: middle;
}

.form-label {
    font-weight: bold;
    color: #ecf0f1;
    padding-bottom: 10px;
}

.form-input input,
.form-input select,
.form-input textarea {
    width: 100%;
    padding: 5px;
    border: 1px solid #16a085;
    border-radius: 5px;
    background-color: #2c3e50;
    color: #ecf0f1;
    text-align: center;
    font-family: inherit;
    box-sizing: border-box;
}

.button-danger {
    background-color: #e74c3c;
}

.button-danger:hover {
    background-color: #c0392b;
}

.checkbox-container {
    margin-bottom: 10px;
    padding: 8px 14px;
}

.column-toggles-dropdown {
    margin-bottom: 10px;
}

.column-toggles-dropdown summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background-color: #3498db;
    color: #ecf0f1;
    padding: 6px 12px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 0.8rem;
    user-select: none;
    list-style: none;
}

.column-toggles-dropdown summary::-webkit-details-marker {
    display: none;
}

.column-toggles-dropdown summary:hover {
    background-color: #2980b9;
}

.column-toggles-dropdown summary::after {
    content: '▾';
    font-size: 0.7rem;
}

.column-toggles-dropdown[open] summary::after {
    content: '▴';
}

.column-toggles-dropdown .checkbox-container {
    margin-top: 8px;
    margin-bottom: 0;
    max-width: max-content;
}

.checkbox-container label {
    font-size: 11px;
    margin-right: 10px;
    cursor: pointer;
}

.checkbox-container input {
    cursor: pointer;
    transform: scale(0.8);
}

.hidden {
    display: none;
}

.button-container {
    display: flex;
    margin: 30px auto;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
}

.month {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 12px;
    cursor: pointer;
    text-decoration: none;
    color: #ecf0f1;
    background: #3498db;
    border: none;
    border-radius: 5px;
    font-size: 13px;
    font-weight: 500;
    flex: 0 0 160px;
    box-shadow: 2px 5px 10px rgba(0, 0, 0, 0.3);
    transition: opacity 150ms linear;
}

.month:hover {
    opacity: 0.85;
}

.month.current {
    background: #f1c40f;
    color: #2c3e50;
}

.year-label {
    color: #bdc3c7;
    font-size: 0.9rem;
    margin: 24px 0 0;
}

/* ===== Mobile: real phones need bigger touch targets and readable text, ===== */
/* ===== not the original's shrink-everything-to-10px approach.          ===== */

/* Second condition (comma = OR): a phone rotated to landscape can exceed
   740px in width (e.g. iPhone 15 Pro Max is 932px wide sideways) while
   staying well under 500px tall — the owner found that without this,
   rotating to landscape flipped the whole page back to the desktop
   layout (nav icons/tabs gone) even on a phone. max-height keeps this
   from also matching a genuinely short desktop/laptop window. Applied to
   all four `max-width: 740px` blocks in this file identically — see
   CLAUDE.md's "Working conventions" on this file's cascade-order footgun;
   this is the exception case, not an instance of it. */
@media (max-width: 740px), (max-height: 500px) and (orientation: landscape) {
    main {
        padding: 12px;
        /* Room for the fixed .bottom-tab-bar so its last row of content
           isn't hidden behind it; env() adds the home-indicator's own
           safe area on top of that on notched iPhones. */
        padding-bottom: calc(70px + env(safe-area-inset-bottom));
    }
    table { font-size: 12px; }
    thead th, tbody td { padding: 8px 6px; }

    /* Табеля/Графики/Админка/Задачи move to .bottom-tab-bar below — these
       desktop copies (top nav + header bell) just get out of the way
       rather than duplicating every destination in two places.
       !important: .nav-buttons a (a class + an element, specificity 0,1,1)
       is MORE specific than a lone .primary-nav-link class (0,1,0), so
       without it .nav-buttons a's `display: inline-block` would win
       regardless of source order or how deep inside a @media block this
       sits. Confirmed live 2026-08-30: these three links were showing up
       duplicated, both here and in .bottom-tab-bar below. */
    .primary-nav-link {
        display: none !important;
    }

    /* !important: this file's later, unconditional `.bottom-tab-bar {
       display: none }` (added further down, alongside the other base
       header/nav rules) has equal specificity and comes after this block
       in source order, so without it this mobile override was silently
       losing the cascade — the exact bug documented in round 15, repeated
       here by not checking for it (caught 2026-08-29 when the bar simply
       never appeared on a real phone). See CLAUDE.md's "Working
       conventions" for the standing rule this is supposed to prevent. */
    .bottom-tab-bar {
        display: flex !important;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 500;
        background-color: #2c3e50;
        border-top: 1px solid #1c2833;
        padding-bottom: env(safe-area-inset-bottom);
    }

    .bottom-tab-bar a {
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2px;
        padding: 6px 2px 8px;
        color: #95a5a6;
        text-decoration: none;
        font-size: 0.65rem;
        text-align: center;
    }

    .bottom-tab-bar a.active {
        color: #3498db;
    }

    .header-container {
        display: grid;
        grid-template-columns: 1fr auto;
        grid-template-areas:
            "logo logout"
            "user icons"
            "nav nav";
        row-gap: 8px;
        padding: 10px 12px;
    }
    .logo { grid-area: logo; }
    /* unwrap .header-right so its children become individually placeable
       grid items instead of fighting for space inside it. .header-icons
       stays a real (flex) element rather than also going display:contents —
       an un-placed grid item with no grid-area falls back to
       browser auto-placement, which used to drop the 📲/🔔 icons into a
       stray extra row instead of next to the username. */
    .header-right {
        display: contents;
    }
    .nav-user {
        grid-area: user;
        text-align: left;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .header-icons {
        grid-area: icons;
        justify-self: end;
    }
    .logout-form {
        grid-area: logout;
    }
    /* Order-status filters only make sense while actually viewing Заказы —
       on every other section this same shared header.php markup would
       otherwise still render it (it's unconditional, for desktop's sake,
       see includes/header.php), so hide it here based on the
       body[data-section] header.php also sets. Desktop is untouched: this
       rule only exists inside this mobile media query.
       :not(.admin-subnav):not(.lookup-tabs): admin_nav.php/charts.php's own
       sub-nav elements both carry the shared `nav-buttons` class too (for
       its pill-button styling), so without this exclusion this rule was
       also hiding *their* tiles on every non-orders section — including on
       Админка/Графики themselves, where they're the only nav present.
       Found 2026-08-30 from the owner reporting the tiles had vanished
       there. */
    body:not([data-section="orders"]) .nav-buttons:not(.admin-subnav):not(.lookup-tabs) {
        display: none !important;
    }

    .nav-buttons {
        grid-area: nav;
    }

    /* Icon-over-label grid, matching .bottom-tab-bar's look — replaces the
       desktop's inline text-pill row entirely on mobile. flex-wrap (not
       nowrap+overflow-x like this used to be) so every button fits within
       the screen width across as many rows as needed, no horizontal
       scrolling. .admin-subnav/.lookup-tabs live outside .header-container
       (in admin_nav.php/charts.php), so grid-area doesn't apply to them —
       only the flex/icon styling below is shared. */
    .nav-buttons, .admin-subnav, .lookup-tabs {
        flex-wrap: wrap;
        justify-content: center;
    }
    .nav-buttons a, .nav-buttons button,
    .admin-subnav a, .lookup-tabs a {
        flex: 0 1 auto;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2px;
        padding: 8px 6px;
        font-size: 0.65rem;
        text-align: center;
        min-width: 64px;
    }
    .tab-icon {
        display: block;
        font-size: 1.3rem;
        line-height: 1.2;
    }

    /* Transparent tiles, not colored buttons, per owner's 2026-08-30
       request — matches .bottom-tab-bar's look (no fill, active tab shown
       by color alone). !important: overrides the desktop pill's
       background-color (blue/yellow/teal, set unconditionally further up
       this file) which would otherwise still win inside this query. */
    .nav-buttons a, .nav-buttons button,
    .admin-subnav a, .lookup-tabs a,
    .nav-buttons a:hover, .nav-buttons button:hover,
    .admin-subnav a:hover, .lookup-tabs a:hover {
        background-color: transparent !important;
        color: #ecf0f1;
    }
    .nav-buttons:not(.admin-subnav) a.active,
    .nav-buttons.admin-subnav a.active,
    .admin-subnav a.active,
    .lookup-tabs a.active,
    .nav-buttons:not(.admin-subnav) a.active:hover,
    .nav-buttons.admin-subnav a.active:hover {
        background-color: transparent !important;
        color: #3498db;
    }

    .table-container {
        margin: 0 12px 12px;
        -webkit-overflow-scrolling: touch;
    }

    /* !important on both: proactively, not after the fact this time (see
       CLAUDE.md's "Working conventions" — this exact file has already
       broken twice from a later unconditional rule of equal specificity
       silently winning over one of these mobile blocks). orders.php's own
       table swaps for the card list below 740px. */
    .orders-table-container {
        display: none !important;
    }

    .orders-cards {
        display: block !important;
    }

    .order-card {
        margin: 0 12px 12px;
    }

    /* !important on these three: the plain (unmedia-queried) `fieldset`,
       `.field-wide` and `output.computed` rules further down the file are
       later in source order and equal specificity, so without it they
       silently win the cascade even inside this max-width block — order
       forms rendered as multiple side-by-side columns and overflowed
       horizontally on every phone until this was caught (2026-08-29). */
    fieldset {
        grid-template-columns: 1fr !important;
    }

    /* Undo the desktop 14px value-field size below 740px — anything under
       16px makes iOS Safari zoom in on focus, which fights the user for
       control of the viewport. */
    fieldset input,
    fieldset select,
    fieldset textarea,
    output.computed {
        font-size: 16px !important;
    }

    .field-wide {
        grid-column: auto !important;
    }

    .checkbox-container {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        white-space: nowrap;
    }

    /* position:sticky on a table cell combined with auto table-layout
       triggers a WebKit/mobile-Safari bug that blows the first column's
       width up to most of the viewport. Not worth it on a narrow phone
       screen anyway — just let it scroll like every other column. */
    td:first-child, th:first-child {
        position: static;
    }
}

@media (max-width: 480px) {
    .login-container { max-width: 100%; margin: 0; min-height: 100vh; border-radius: 0; display: flex; flex-direction: column; justify-content: center; }
    .nav-user { font-size: 0.8rem; }
}

/* ===== Additions for the new dakservice-orders app (statuses, admin UI, ===== */
/* ===== computed fields, role-permission checkboxes) — same palette,   ===== */
/* ===== new elements the original site never had.                     ===== */

* { box-sizing: border-box; }

a { color: #3498db; }

.container {
    max-width: 1600px;
    margin: 0 auto;
    padding: 0 20px;
}

.logo {
    display: flex;
    align-items: center;
    text-decoration: none;
    white-space: nowrap;
}

.logo img {
    height: 38px;
    width: auto;
}

.nav-user {
    color: #ecf0f1;
    font-size: 0.9rem;
    font-weight: normal;
}

.count {
    color: #bdc3c7;
    font-weight: 400;
    font-size: 1rem;
}

.admin-subnav {
    margin: 20px 20px 24px;
    display: flex;
    justify-content: center;
}

.lookup-tabs {
    margin: 0 20px 20px;
    justify-content: center;
}

/* Landscape-phone OR-condition, see the first `max-width: 740px` block
   above for why. */
@media (max-width: 740px), (max-height: 500px) and (orientation: landscape) {
    /* Icon-grid, not the horizontal-scroll strip this used to be — wraps
       onto as many rows as needed instead. Kept in its own block (rather
       than folded into the one above) because it needs to come after that
       one in source order without accidentally un-wrapping it — this file's
       standing footgun (see CLAUDE.md's "Working conventions"), so this is
       the exception that proves the rule: same selectors, but written to
       reinforce the earlier rule instead of fight it. */
    .admin-subnav, .lookup-tabs {
        margin-left: 0;
        margin-right: 0;
        justify-content: center;
        flex-wrap: wrap;
        padding: 0 12px 4px;
    }
    .admin-subnav a, .lookup-tabs a {
        flex: 0 1 auto;
    }
}

.table-scroll {
    overflow-x: auto;
}

.orders-table td.num {
    text-align: right;
}

/* Last-manual-correction timestamp under the order title, table view only
   (orders.php) — deliberately muted so it doesn't compete with the title
   itself: the table's base text is 12px/light (#ecf0f1). A literal half
   (6px) was tried first and screenshotted — unreadable — the owner picked
   9px instead as the smallest size that's still actually legible. */
.order-title-updated-at {
    font-size: 9px;
    font-weight: normal;
    color: #7f8c8d;
}

/* admin_activity_log.php's "Детали" column — a field-diff summary can run
   long (several "поле: старое → новое" pairs joined by "; "). The base
   `tbody td { white-space: nowrap }` rule would force that onto one line
   and turn the whole table into horizontal scroll; this column specifically
   should wrap and cap its width instead. */
.activity-details {
    max-width: 420px;
    white-space: normal;
    text-align: left;
    word-break: break-word;
}

/* Task titles (admin_task_templates.php "Правила задач", admin_task_log.php
   "Журнал задач") — same overflow problem as .activity-details above: a
   title can run up to ~230 bytes on one nowrap line, which alone pushes the
   table past the page width. Wraps and left-aligns (readable prose, not a
   value to scan/compare); .task-rule-wrap below is for shorter label
   columns (assignee/status list) that wrap too but stay centered like
   their neighbours. */
.task-rule-title {
    max-width: 340px;
    white-space: normal;
    text-align: left;
    word-break: break-word;
}

.task-rule-wrap {
    max-width: 220px;
    white-space: normal;
    word-break: break-word;
}

/* Glance-able health indicator for utilization %/deadline-proximity cells —
   a left border stripe, deliberately not a filled background or colored
   text, so it reads clearly scanning down a whole column without competing
   with the number itself. See order_cell_band()/percent_band() in orders.php
   and includes/functions.php for what puts a row in each band. */
.orders-table td.band-good {
    border-left: 3px solid #7ee787;
}

.orders-table td.band-warn {
    border-left: 3px solid #f39c12;
}

.orders-table td.band-bad {
    border-left: 3px solid #e74c3c;
}

.order-title-link {
    color: #ecf0f1;
    text-decoration: none;
}

.order-title-link:hover {
    text-decoration: underline;
}

.orders-table tfoot td {
    font-weight: bold;
    background-color: #2c3e50;
}

.orders-table .empty {
    text-align: center;
    color: #bdc3c7;
    padding: 24px;
}

.status-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: bold;
    background: #2c3e50;
    color: #ecf0f1;
}

.status-в-работе { background: #3498db; }
.status-архив { background: #7f8c8d; }
.status-планируемый { background: #f39c12; }
.status-не-подтвержден { background: #e74c3c; }
.status-работы-выполнены { background: #1abc9c; }

.btn {
    display: inline-block;
    background-color: #3498db;
    color: #ecf0f1;
    border: none;
    padding: 10px 15px;
    border-radius: 5px;
    text-decoration: none;
    cursor: pointer;
    font-size: 0.9rem;
    transition: background-color 0.3s;
}

.btn:hover {
    background-color: #2980b9;
}

.btn-small {
    background-color: #3498db;
    color: #ecf0f1;
    border: none;
    cursor: pointer;
    border-radius: 5px;
    transition: background-color 0.3s;
    padding: 5px 10px;
    font-size: 0.8rem;
}

.btn-small:hover {
    background-color: #2980b9;
}

.btn-danger {
    background-color: #e74c3c;
}

.btn-danger:hover {
    background-color: #c0392b;
}

/* Приглушённый вариант .btn для второстепенного действия рядом с основным —
   «Сбросить фильтры» не должен выглядеть так же весомо, как «Показать».
   Тот же приём, что и .btn-danger: только цвет, вся геометрия из .btn. */
/* Процитированное обращение — и в предпросмотре под формой ответа, и внутри
   уже отправленного ответа (feedback.php). Переносы строк сохраняются как
   есть (pre-wrap), потому что показывать надо ровно то, что увидит адресат,
   но длинные строки переносятся, иначе одно длинное обращение растянет
   страницу вбок. */
.quoted-request {
    margin: 4px 0 14px;
    padding: 10px 12px;
    border-left: 3px solid #566573;
    border-radius: 0 5px 5px 0;
    background-color: rgba(0, 0, 0, 0.15);
    color: #bdc3c7;
    font-size: 0.85rem;
    white-space: pre-wrap;
    word-break: break-word;
}

.btn-muted {
    background-color: #566573;
}

.btn-muted:hover {
    background-color: #46545f;
}

.checkbox-label {
    display: flex !important;
    flex-direction: row !important;
    align-items: center;
    gap: 8px;
    text-align: left;
}

/* admin_roles.php's role-simulation picker — deliberately its own layout
   rather than .form + fieldset/.checkbox-label (that combo is tuned for
   order_edit.php-style multi-column field grids; nested inside .form's
   420px cap it squeezed fieldset's own grid down to one narrow column,
   wrapping names like "fin-admin" onto two lines with a wide dead strip
   of empty space beside each one — see the round that added this comment).
   Roles read better as a wrapping row of toggle chips than a vertical list
   of checkboxes, and there are only ever a handful of roles to show. */
.role-sim-form {
    background-color: #34495e;
    border-radius: 10px;
    padding: 20px;
    max-width: 700px;
    margin: 20px auto;
    text-align: left;
}

.role-sim-form-label {
    margin: 0 0 10px;
    font-weight: bold;
    font-size: 0.85rem;
}

.role-sim-options {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

.role-sim-chip {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    border-radius: 20px;
    background-color: #2c3e50;
    border: 1px solid #445a6f;
    font-size: 0.85rem;
    font-weight: normal;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s;
}

.role-sim-chip:hover {
    border-color: #8e44ad;
}

/* Checked state — same purple as .role-sim-banner, so a checked chip here
   visually previews the color of the banner it's about to turn on. */
.role-sim-chip:has(input:checked) {
    background-color: rgba(142, 68, 173, 0.35);
    border-color: #8e44ad;
}

.role-sim-chip input {
    width: auto;
    cursor: pointer;
}

.checkbox-label input {
    width: auto;
    cursor: pointer;
}

.field-hint {
    grid-column: 1 / -1;
    color: #95a5a6;
    font-size: 0.7rem;
    font-style: italic;
    margin: 2px 0 0;
    padding-top: 6px;
    border-top: 1px solid #2c3e50;
    text-align: left;
}

.field-note {
    color: #95a5a6;
    font-size: 0.7rem;
    font-weight: normal;
    display: block;
}

.field-wide {
    grid-column: span 2;
}

.suggest-buttons {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.field-note-manual {
    color: #f39c12;
    font-weight: bold;
}

/* Заметка, которая сообщает о расхождении, а не о состоянии поля: часы
   подрядчиков на заказе есть, а доля подрядчика из выручки не выделена.
   Красная, а не оранжевая, как «Введено вручную»: та говорит «так и задумано»,
   эта — «данные ещё не в порядке». Ширину не ограничиваем — текст длинный и
   должен переноситься по ширине поля, а не вылезать из сетки карточки. */
.field-note-warning {
    color: #c0392b;
    font-weight: bold;
    line-height: 1.35;
    margin-top: 4px;
}

.select-all-fields {
    grid-column: 1 / -1;
    border-bottom: 1px solid #2c3e50;
    padding-bottom: 10px;
    margin-bottom: 4px;
}

/* Per-field view/edit checkboxes on the role-edit page — a plain grid of
   labels doesn't read as "two checkboxes belong to this one field", so this
   fieldset switches to a row-per-field layout instead of the default
   multi-column card grid every other fieldset on this page uses. */
.role-fields-fieldset {
    display: block;
    max-width: 620px;
}

.role-field-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 6px 0;
    border-bottom: 1px solid #2c3e50;
}

.role-field-header {
    font-weight: bold;
    color: #1abc9c;
    border-bottom: 1px solid #2c3e50;
}

.role-field-name {
    flex: 1;
}

.role-field-row .checkbox-label {
    flex: 0 0 130px;
    justify-content: flex-start;
}

output.computed {
    display: block;
    padding: 5px;
    border-radius: 5px;
    background-color: #2c3e50;
    border: 1px dashed #16a085;
    color: #ecf0f1;
    font-size: 14px;
    font-weight: normal;
    text-align: center;
}

.computed-empty {
    color: #95a5a6;
    font-style: italic;
    font-size: 0.85em;
}

/* fieldset-based sections in order_edit.php get the .form-table treatment
   (dark card, rounded corners) since our form has more fields than the
   original's single-row layout can hold, grouped by category instead */
fieldset {
    background-color: #34495e;
    padding: 10px 14px;
    border-radius: 10px;
    border: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 6px 10px;
    text-align: left;
    width: 100%;
    max-width: 1150px;
    margin: 0 auto;
}

legend {
    padding: 0 6px;
    font-weight: bold;
    color: #1abc9c;
    font-size: 0.8rem;
}

fieldset label {
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 0.75rem;
    color: #ecf0f1;
    font-weight: bold;
}

fieldset input,
fieldset select,
fieldset textarea {
    width: 100%;
    padding: 5px;
    border: 1px solid #16a085;
    border-radius: 5px;
    background-color: #2c3e50;
    color: #ecf0f1;
    text-align: center;
    font-family: inherit;
    font-weight: normal;
    font-size: 14px; /* bumped back to 16px below 740px — prevents iOS Safari auto-zoom on focus */
    box-sizing: border-box;
}

fieldset input:focus,
fieldset select:focus,
fieldset textarea:focus {
    border-color: #3498db;
    outline: none;
}

.form {
    background-color: #34495e;
    border-radius: 10px;
    padding: 20px;
    max-width: 420px;
    margin: 20px auto;
    text-align: left;
}

.form label {
    display: block;
    margin-bottom: 12px;
    font-weight: bold;
    font-size: 0.85rem;
}

.transfer-pair {
    display: flex;
    gap: 12px;
}

.transfer-pair label {
    flex: 1;
}

.form input,
.form select,
.form textarea {
    width: 100%;
    padding: 10px 8px;
    border: 1px solid #16a085;
    border-radius: 5px;
    background-color: #2c3e50;
    color: #ecf0f1;
    font-family: inherit;
    font-weight: normal;
    font-size: 16px; /* prevents iOS Safari auto-zoom on focus */
    margin-top: 6px;
    box-sizing: border-box;
}

.alert {
    padding: 10px 15px;
    border-radius: 5px;
    font-size: 0.9rem;
    margin: 12px 20px;
}

.alert-error {
    background-color: rgba(231, 76, 60, 0.15);
    color: #e74c3c;
}

/* Предупреждение — для баннера замка у админа: его не останавливают,
   но он должен видеть, что перезапишет чужую работу. Оранжевый, как
   непроизводственные часы и «Простой»: цвет «обрати внимание» в приложении. */
.alert-warning {
    background-color: rgba(230, 126, 34, 0.15);
    color: #e67e22;
}

/* Замок стоит над формой, а не в общем потоке сообщений: его надо увидеть
   до того, как начал вводить. */
/* fieldset нужен только чтобы разом отключить вложенные поля при чужом
   замке — собственного оформления у него быть не должно. */
.lock-guard {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

.edit-lock-banner {
    font-weight: bold;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    justify-content: center;
}

.alert-success {
    background-color: rgba(26, 188, 156, 0.15);
    color: #1abc9c;
}

.login-body {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
}

.login-container img.login-logo {
    width: 220px;
    height: auto;
    margin: 0 auto 12px;
    display: block;
}

.login-container h2 {
    margin: 0 0 20px;
    font-size: 14px;
    color: #bdc3c7;
    font-weight: normal;
}

.day-special {
    background-color: rgba(241, 196, 15, 0.35) !important;
}

.hours-input {
    width: 44px;
    padding: 4px 2px;
    text-align: center;
    background-color: #2c3e50;
    color: #ecf0f1;
    border: 1px solid #16a085;
    border-radius: 4px;
    font-size: 12px;
}

.hours-input:disabled {
    opacity: 0.6;
}

.employee-total-row td {
    font-weight: bold;
    background-color: #2c3e50;
}

/* Timesheet grid — deliberately styled to look like the actual Excel workbook
   (white background, thin black grid lines, the same header fill colors as
   generate_xlsx_2026.php on the legacy server) rather than the site's dark theme. */
.timesheet-table {
    background-color: #ffffff;
    color: #000000;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 11px;
    border-collapse: collapse;
    /* Fixed layout + an explicit <colgroup> (see timesheets.php) makes every
       column's width authoritative — needed so the sticky identity columns'
       pixel "left" offsets always match what's actually rendered. Under the
       site-wide width:100% + table-layout:auto, a long "Заказ" title could
       force that column wider than assumed, throwing the sticky offsets off
       and leaving a gap that showed the page's own <thead> teal through. */
    width: auto;
    table-layout: fixed;
}

.timesheet-table th,
.timesheet-table td {
    border: 1px solid #000000;
    padding: 1px 5px;
    text-align: center;
    white-space: nowrap;
    background-color: #ffffff;
    color: #000000;
    overflow: hidden;
}

.timesheet-table th.col-fio,
.timesheet-table th.col-order,
.timesheet-table td.col-fio,
.timesheet-table td.col-order {
    white-space: normal;
    overflow-wrap: break-word;
}

.timesheet-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background-color: #5dfa3d;
    font-weight: bold;
    font-size: 13px;
    padding: 5px 6px;
}

/* Weekend/holiday shading only ever applies to body cells in the original —
   the day headers stay green regardless (fixes it leaking onto the header). */
.timesheet-table thead th.day-special {
    background-color: #5dfa3d;
}

/* № / Действия / ФИО / Заказ — the sticky "identity" strip on the left.
   Identified by class, not nth-child position: rowspan-merged cells (№, the
   grand-total column) are omitted from the DOM on continuation rows, which
   shifts every nth-child index on those rows and silently mis-targets cells —
   classes are immune to that. */
.timesheet-table thead th.col-num,
.timesheet-table thead th.col-actions,
.timesheet-table thead th.col-fio,
.timesheet-table thead th.col-order {
    background-color: #ff0000;
    color: #ffffff;
    z-index: 3;
}

.timesheet-table thead th.employee-grand-total,
.timesheet-table td.employee-grand-total {
    background-color: #87ceeb !important;
    font-weight: bold;
}

.timesheet-table tbody td.col-num,
.timesheet-table tbody td.col-actions,
.timesheet-table tbody td.col-fio,
.timesheet-table tbody td.col-order {
    position: sticky;
    background-color: #e6e6e6;
    font-weight: bold;
    text-align: left;
    z-index: 1;
}

/* Действия and Заказ aren't bold in the original workbook — only № and ФИО are. */
.timesheet-table tbody td.col-actions,
.timesheet-table tbody td.col-order {
    font-weight: normal;
}

.timesheet-table tbody td.col-num,
.timesheet-table tbody td.col-actions {
    text-align: center;
}

/* Sticky offsets — must match the <colgroup> widths in timesheets.php exactly,
   since table-layout:fixed makes those widths authoritative. table-layout:fixed
   alone wasn't enough, though: Chromium still let a cell's own content (wrapped
   text, a <select>) shrink or grow it below/above the declared column width —
   confirmed by testing (forcing min-width made it snap to the right size), so
   every identity column also gets width/min-width/max-width locked explicitly
   in addition to the <colgroup> declaration, removing any ambiguity. */
.timesheet-table th.col-num,
.timesheet-table td.col-num {
    left: 0;
    width: 44px;
    min-width: 44px;
    max-width: 44px;
}

.timesheet-table th.col-actions,
.timesheet-table td.col-actions {
    left: 44px;
    width: 70px;
    min-width: 70px;
    max-width: 70px;
}

.timesheet-table th.col-fio,
.timesheet-table td.col-fio {
    width: 150px;
    min-width: 150px;
    max-width: 150px;
}

.timesheet-table th.col-order,
.timesheet-table td.col-order {
    width: 160px;
    min-width: 160px;
    max-width: 160px;
}

.timesheet-table:not(.has-actions) th.col-fio,
.timesheet-table:not(.has-actions) td.col-fio {
    left: 44px;
    padding-left: 10px;
}

.timesheet-table:not(.has-actions) th.col-order,
.timesheet-table:not(.has-actions) td.col-order {
    left: 194px;
    padding-left: 10px;
}

.timesheet-table.has-actions th.col-fio,
.timesheet-table.has-actions td.col-fio {
    left: 114px;
    padding-left: 10px;
}

.timesheet-table.has-actions th.col-order,
.timesheet-table.has-actions td.col-order {
    left: 264px;
    padding-left: 10px;
}

.timesheet-table th.col-num,
.timesheet-table th.col-actions,
.timesheet-table th.col-fio,
.timesheet-table th.col-order {
    position: sticky;
}

.timesheet-table td.col-actions {
    white-space: nowrap;
    overflow: visible;
}

.timesheet-table td.col-actions .btn-small {
    position: relative;
    width: 18px;
    height: 18px;
    padding: 0;
    margin: 0 1px;
    font-size: 11px;
    font-weight: bold;
    line-height: 1;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.timesheet-table td.col-actions .btn-small:hover {
    transform: scale(1.2) rotate(-6deg);
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.55);
}

.timesheet-table td.col-actions .btn-danger {
    background: linear-gradient(135deg, #ff8a8a, #e63946);
    border: none;
}

.timesheet-table td.col-actions .add-row-btn {
    background: linear-gradient(135deg, #4facfe, #1976d2);
    border: none;
}

/* Отработка факт / Отработка ИТР: hover reveals the per-employee breakdown
   behind the total. .labor-tooltip just holds the content (never shown in
   place) — main.js copies it into the shared floating tooltip below, which
   is positioned in JS so it can't be clipped by .table-container's overflow
   or hidden behind the sticky thead the way an in-flow/absolute tooltip was. */
.labor-cell {
    cursor: help;
    border-bottom: 1px dotted rgba(236, 240, 241, 0.5);
}

.labor-tooltip {
    display: none;
}

.labor-tooltip-row {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 3px 0;
}

.labor-tooltip-row + .labor-tooltip-row {
    border-top: 1px solid rgba(236, 240, 241, 0.15);
}

/* Заголовок группы в подсказке по непроизводственным часам: код и его
   итог, под ним — фамилии. Владелец просил видеть и доли, и людей. */
.labor-tooltip-group {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 4px 0 2px;
    font-weight: bold;
    color: #f5b041;
}

.labor-tooltip-group:not(:first-child) {
    margin-top: 4px;
    border-top: 1px solid rgba(245, 176, 65, 0.35);
}

/* Фамилия под заголовком кода — с отступом, чтобы читалось как вложение. */
.labor-tooltip-group + .labor-tooltip-row,
.labor-tooltip-group ~ .labor-tooltip-row {
    padding-left: 10px;
}

.labor-tooltip-group + .labor-tooltip-row {
    border-top: none;
}

.labor-tooltip-hours {
    color: #1abc9c;
    font-weight: bold;
    margin-left: 12px;
}

/* Часы рядом с фамилией в подсказке по зарплате (payroll_people_tooltip_html):
   вторичная величина — главное там деньги, часы лишь объясняют, откуда сумма. */
.labor-tooltip-hint {
    opacity: 0.65;
    font-size: 0.85em;
    white-space: nowrap;
}

/* Отработка по внутренним заказам (chart_internal_labor.php) reuses this
   same .labor-cell/.labor-tooltip mechanism (main.js already binds to any
   .labor-cell generically), but here it wraps a whole chart column
   (value + bar), not a table cell — override the table-oriented default
   styling (dotted underline makes no sense under a bar) and give it the
   flex layout .revenue-bar-col's children need, since .revenue-bar-track's
   own width:100% now resolves against .labor-cell instead. */
.revenue-bar-col .labor-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    cursor: help;
    border-bottom: none;
}

.internal-labor-bar {
    position: relative;
    width: 62%;
    max-width: 44px;
    margin: 0 auto;
    border-radius: 7px 7px 2px 2px;
    background: linear-gradient(180deg, #22c3a6 0%, #16a085 55%, #0f7a63 100%);
    box-shadow: inset 3px 0 0 rgba(255, 255, 255, 0.22), inset -2px 0 0 rgba(0, 0, 0, 0.18), 0 8px 16px -6px rgba(0, 0, 0, 0.55);
    transform-origin: bottom;
    animation: revenue-bar-grow 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    transition: filter 0.15s ease, transform 0.15s ease;
}

.internal-labor-bar:hover {
    filter: brightness(1.1);
    transform: translateY(-2px);
}

/* Shared floating tooltip (main.js) — fixed-positioned at the body level so
   it always renders above the sticky table header and is never clipped by
   any scrolling ancestor, regardless of where its anchor sits on the page. */
.js-floating-tooltip {
    display: none;
    position: fixed;
    z-index: 9999;
    pointer-events: none;
    border-radius: 6px;
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.5);
}

.js-floating-tooltip-labor {
    background-color: #1c2833;
    color: #ecf0f1;
    padding: 8px 12px;
    text-align: left;
    font-weight: normal;
    font-size: 11px;
    font-family: Arial, Helvetica, sans-serif;
    white-space: nowrap;
}

/* Строки документа 1С в подсказке «Затраты из 1С» (order_edit.php): названия
   номенклатуры длинные, поэтому переносим их, а не растягиваем подсказку. */
.js-floating-tooltip-labor .onec-items {
    display: block;
    white-space: normal;
    max-width: min(480px, 92vw);
}

.onec-items .labor-tooltip-name {
    flex: 1 1 auto;
    min-width: 0;
}

.onec-items .labor-tooltip-hours {
    white-space: nowrap;
}

.js-floating-tooltip-button {
    background-color: #2c3e50;
    color: #ffffff;
    padding: 4px 9px;
    font-size: 11px;
    font-weight: normal;
    font-family: Arial, Helvetica, sans-serif;
    white-space: nowrap;
}

/* Сумма к распределению: marks a hand-corrected amount in the reports list
   (see .field-note-manual for the equivalent label in the order card). */
.manual-mark {
    color: #f39c12;
    cursor: help;
    font-size: 11px;
}

/* Thicker rule around each employee's block of order-rows, matching the medium
   outline the original workbook drew around every 6-row group. */
.timesheet-table tr.employee-group-start td {
    border-top: 2px solid #000000;
}

.timesheet-table tr.employee-group-end td {
    border-bottom: 2px solid #000000;
}

/* Bold frame around the whole №/Действия/ФИО/Заказ identity group, and around
   each of the three totals columns individually — matching the medium-weight
   outlines the original workbook drew around each of those. */
.timesheet-table th.col-num,
.timesheet-table td.col-num {
    border-left: 2px solid #000000;
}

.timesheet-table th.col-order,
.timesheet-table td.col-order {
    border-right: 2px solid #000000;
}

/* Офис rows merge ФИО+Заказ into one cell (colspan=2, no order concept at
   all) — col-fio's own rules give it the right sticky position/background,
   this just adds the closing edge col-order would normally provide. */
.timesheet-table td.office-name-cell {
    border-right: 2px solid #000000;
}

.timesheet-table th.col-total-plain,
.timesheet-table td.col-total-plain,
.timesheet-table th.col-total-weighted,
.timesheet-table td.col-total-weighted,
.timesheet-table th.employee-grand-total,
.timesheet-table td.employee-grand-total,
.timesheet-table th.col-wage,
.timesheet-table td.col-wage,
.timesheet-table th.col-row-sum,
.timesheet-table td.col-row-sum,
.timesheet-table th.employee-grand-sum,
.timesheet-table td.employee-grand-sum {
    border-left: 2px solid #000000;
    border-right: 2px solid #000000;
}

/* Money columns (Тариф / Сумма по заказу / Итого сумма) — only rendered for
   roles holding view_employee_hourly_wage. .employee-grand-sum is merged per
   employee with a rowspan exactly like .employee-grand-total next to it, and
   shares its highlight so the two per-employee totals read as a pair. */
/* Widths follow the same rule as the total columns above — wide enough for
   the header label on one line. Header cells are nowrap + overflow:hidden,
   so anything too narrow clips the label instead of wrapping it (first cut
   at 90/110px did exactly that). At 13px bold these labels measure roughly
   7.2px per character plus ~14px of padding/border. */
.timesheet-table th.col-wage,
.timesheet-table td.col-wage {
    width: 115px;
    min-width: 115px;
    max-width: 115px;
}

.timesheet-table th.col-row-sum,
.timesheet-table td.col-row-sum {
    width: 175px;
    min-width: 175px;
    max-width: 175px;
}

.timesheet-table th.employee-grand-sum,
.timesheet-table td.employee-grand-sum {
    width: 145px;
    min-width: 145px;
    max-width: 145px;
}

.timesheet-table thead th.employee-grand-sum,
.timesheet-table td.employee-grand-sum {
    background-color: #87ceeb !important;
    font-weight: bold;
}

/* Same width-locking as the identity columns above — table-layout:fixed alone
   let these drift a few px from their <colgroup> widths too. */
.timesheet-table th.day-col,
.timesheet-table td.day-col {
    width: 60px;
    min-width: 60px;
    max-width: 60px;
}

/* Wide enough for their header label on one line, unwrapped ("Итого с
   овертайм" measures ~113px at this font/weight; "Итого астр" ~69px). */
.timesheet-table th.col-total-plain,
.timesheet-table td.col-total-plain {
    width: 85px;
    min-width: 85px;
    max-width: 85px;
}

.timesheet-table th.col-total-weighted,
.timesheet-table td.col-total-weighted {
    width: 130px;
    min-width: 130px;
    max-width: 130px;
}

.timesheet-table th.employee-grand-total,
.timesheet-table td.employee-grand-total {
    width: 130px;
    min-width: 130px;
    max-width: 130px;
}

.timesheet-table .add-row-btn {
    background-color: #3498db;
    color: #ffffff;
    border: none;
}

/* A <select>'s intrinsic width follows its longest <option> text, and Chromium
   lets that grow the table cell even under table-layout:fixed — a percentage
   width doesn't override it. An explicit pixel width does, so the column can
   never balloon past what the <colgroup> declares (see timesheets.php). */
.timesheet-table td.col-order select.order-select {
    width: 148px;
    max-width: 148px;
    box-sizing: border-box;
    font-size: 12px;
}

.timesheet-table .day-special {
    background-color: #ffff00 !important;
}

.timesheet-table .hours-zero {
    background-color: #00bfff !important;
}

.timesheet-table .hours-input {
    width: 32px;
    padding: 1px;
    border: none;
    background: transparent;
    color: #000000;
    text-align: center;
    font-family: inherit;
    font-size: 12px;
}

.timesheet-table .hours-input:disabled {
    background: transparent;
    opacity: 1;
}

.timesheet-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: flex-end;
    justify-content: center;
    margin: 0 20px 20px;
}

.timesheet-toolbar .form {
    margin: 0;
}

.ts-toast {
    position: fixed;
    left: 50%;
    /* env() falls back to 0 on browsers that don't support it, so this is
       just "28px" everywhere except iPhones with a home-indicator bar,
       where it keeps the toast clear of that swipe-up gesture zone. */
    bottom: calc(28px + env(safe-area-inset-bottom));
    transform: translateX(-50%) translateY(10px);
    background-color: #2ecc71;
    color: #ffffff;
    padding: 10px 22px;
    border-radius: 8px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
    font-size: 14px;
    font-weight: bold;
    z-index: 10000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.ts-toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* График загрузки — originally ported byte-for-byte from the legacy
   admin/graph.php Gantt view's own inline <style> (white background, black
   grid, raw red/orange/#ff69b4 fills). Restyled 2026-08-31 to the
   "Тепловая карта загрузки" direction the owner picked from a 3-option
   comparison (artifact, chat history) — a heat-intensity ramp for actual
   workload instead of one flat "filled" color, dark palette to finally
   match the rest of the app instead of being its one Excel-white holdout,
   and compact badges for the missing-date/overdue states instead of a
   solid block filling the whole spanned range. Legacy detail still
   preserved: only the Заказ column is sticky/pinned, not Начало/Окончание —
   those two scroll away with the date columns, matching the original. */
.schedule-range-form {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 20px 12px;
}

.schedule-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
    background: #14181d;
}

.schedule-table th,
.schedule-table td {
    border: 1px solid #232a32;
    padding: 4px 6px;
    text-align: center;
    font-size: 11px;
    background: #14181d;
    color: #dbe4ea;
}

.schedule-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: #1b2128;
    font-weight: 600;
}

/* The one column whose numbers actually need to line up/compare at a
   glance — tabular-nums keeps digit widths uniform without pulling in a
   webfont the rest of this app deliberately doesn't load (see body's plain
   Arial stack) — an unnecessary external dependency for an internal tool,
   doubly so on an app this session already spent real effort keeping
   resilient to flaky mobile connectivity. */
.schedule-table td.cell {
    font-variant-numeric: tabular-nums;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

.schedule-table th.col-name,
.schedule-table th.col-date-start,
.schedule-table th.col-date-end {
    background: #1b2128;
}

.schedule-table th.today {
    box-shadow: inset 0 0 0 2px #e2a53a;
}

.schedule-table td.col-name,
.schedule-table th.col-name {
    position: sticky;
    left: 0;
    background: #1b2128;
    z-index: 3;
    white-space: nowrap;
    font-weight: 600;
    text-align: center;
}

.schedule-table td.col-name {
    text-align: left;
}

/* Heat ramp for a "normal" (in-progress, dated) cell's daily labor-hour
   load — relative to the max currently on screen (see graph_heat_level()
   in includes/chart_graph.php for why: too few orders have both plan dates
   *and* labor_plan filled in yet for a fixed absolute scale to mean
   anything). Tier 1 barely lifts off the page background; tier 4 is the
   brightest, boldest cell in the whole table — the two tiers a glance
   should land on first. */
.schedule-table .cell.normal[data-heat="1"] { background: #12262f; color: #8fb8c8; }
.schedule-table .cell.normal[data-heat="2"] { background: #1c3b4a; color: #bfe3f0; }
.schedule-table .cell.normal[data-heat="3"] { background: #215a70; color: #e2f4fb; }
.schedule-table .cell.normal[data-heat="4"] { background: #2b86a6; color: #ffffff; font-weight: 700; }

/* A cell whose "load" is really a status flag (просрочено / дата не
   задана) gets a softly-tinted lane plus a small pill-shaped badge, rather
   than a solid saturated block filling the whole colspan — the point of
   this pass was to stop the eye reading every wide colored rectangle as
   "the same kind of thing" as an actual workload cell. */
.schedule-table td.cell .schedule-badge {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-weight: 600;
    font-family: Arial, sans-serif; /* badge text isn't tabular data — override .cell's monospace */
    font-size: 10.5px;
    white-space: nowrap;
}

.schedule-table .cell.overdue {
    background: #2a1512;
    color: #f3c9c2;
}
.schedule-table .cell.overdue .schedule-badge {
    background: #c0392b;
    color: #fdecea;
}

.schedule-table .cell.missing {
    background: #2a2312;
    color: #ecd9a8;
}
.schedule-table .cell.missing .schedule-badge {
    background: #b9770e;
    color: #fdf3e3;
}

.schedule-table .cell.both {
    background: #241a2c;
    color: #ddc4ec;
}
.schedule-table .cell.both .schedule-badge {
    background: #8e44ad;
    color: #f5eafa;
}

.schedule-table td.cell.today {
    box-shadow: inset 0 0 0 2px #e2a53a;
}

.schedule-table .schedule-totals-row td {
    font-weight: 700;
    background: #0d1013;
}

/* Выручка по месяцам — a stacked bar per month (Работы/ЗИП split by color
   within the bar, per the owner's request), bottom-aligned in a fixed-height
   track so every month's bar is comparable at a glance. Работы (teal, this
   app's main accent) sits at the bottom of the stack as the usually-larger
   share; ЗИП (amber) stacks above it — plain flex-column source order, no
   column-reverse needed since ЗИП is written first in the markup. */
.revenue-filter-form {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 20px;
    padding: 0 20px 12px;
}

.revenue-filter-form select {
    background-color: #34495e;
    color: #ecf0f1;
    border: 1px solid #16a085;
    border-radius: 5px;
    padding: 6px 10px;
    font-size: 0.9rem;
}

/* Расчёт по месяцу / по периоду — a mutually-exclusive radio pair (styled
   plainly, not as pill buttons, so it doesn't visually compete with the
   year select right next to it). */
.calc-mode-toggle {
    display: flex;
    align-items: center;
    gap: 14px;
}

.calc-mode-option {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.85rem;
    color: #bdc3c7;
    cursor: pointer;
}

.calc-mode-option input[type="radio"] {
    accent-color: #16a085;
}

.revenue-summary {
    margin: 0 20px 8px;
    color: #bdc3c7;
}

.revenue-summary strong {
    color: #ecf0f1;
}

.revenue-legend {
    display: flex;
    gap: 18px;
    margin: 0 20px 16px;
}

/* Explains a chart whose bars mix two different order populations for the
   same month (see chart_labor_comparison.php / chart_rate_by_actual.php) —
   deliberately quieter than .revenue-summary so it reads as a caveat, not
   a headline number. */
.chart-note {
    margin: -8px 20px 16px;
    color: #7f8c9a;
    font-size: 0.78rem;
    line-height: 1.4;
}

.revenue-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    color: #bdc3c7;
}

.revenue-swatch {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    display: inline-block;
    box-shadow: inset 2px 2px 0 rgba(255, 255, 255, 0.25), 0 1px 3px rgba(0, 0, 0, 0.4);
}

.revenue-swatch-works {
    background: linear-gradient(160deg, #22c3a6, #0f7a63);
}

.revenue-swatch-parts {
    background: linear-gradient(160deg, #f5a83a, #cc6a12);
}

.revenue-chart {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    height: 340px;
    margin: 0 20px 20px;
    padding: 16px 12px 0;
    background-color: #2c3e50;
    border: 1px solid #34495e;
    border-radius: 10px;
    overflow-x: auto;
    /* Faint horizontal reference lines, evenly spaced from the baseline —
       purely a scale-reading aid (same spirit as the reference photo's
       dashed gridlines), kept subtle enough not to compete with the bars. */
    background-image: repeating-linear-gradient(
        to top,
        transparent 0,
        transparent calc(20% - 1px),
        rgba(255, 255, 255, 0.05) 20%
    );
}

.revenue-bar-col {
    flex: 1 1 60px;
    min-width: 50px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.revenue-bar-value {
    font-size: 0.74rem;
    font-weight: 700;
    color: #ecf0f1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    margin-bottom: 6px;
    min-height: 1em;
    padding: 2px 7px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.06);
}

/* Fixed px height, not flex-grow-derived — .revenue-bar-stack below sets
   its own height as a %, and a percentage height only reliably resolves
   against an ancestor with an *explicit* height, not one coming from
   flex-basis/flex-grow. A long-standing real Safari quirk (Chromium
   resolves it "leniently" and renders fine regardless, which is exactly
   why this shipped once already looking correct in every check done while
   building it — Chromium testing alone can't catch this class of bug).
   .revenue-chart's own align-items: flex-end bottom-aligns each column's
   natural (shorter) height within the row, so .revenue-bar-col no longer
   needs height: 100% either. */
.revenue-bar-track {
    height: 260px;
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

/* The "3D-ish" polish the owner asked for, without the literal isometric-
   box-and-gradient-wall look of the reference photo (that reads as dated
   next to the rest of this app's flat dark UI) — instead: a soft drop
   shadow for lift off the background, a glossy top-to-bottom gradient per
   segment suggesting a rounded/cylindrical surface, a bright highlight
   sliver down the left edge, and a grow-in animation on load. transform-
   origin: bottom + scaleY(0)->scaleY(1) is what animates — animating
   height directly would fight the inline height:% already driving layout. */
.revenue-bar-stack {
    width: 62%;
    max-width: 44px;
    display: flex;
    flex-direction: column;
    border-radius: 7px 7px 2px 2px;
    overflow: hidden;
    box-shadow: 0 8px 16px -6px rgba(0, 0, 0, 0.55);
    transform-origin: bottom;
    animation: revenue-bar-grow 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    transition: filter 0.15s ease, transform 0.15s ease;
}

.revenue-bar-col:hover .revenue-bar-stack {
    filter: brightness(1.1);
    transform: translateY(-2px);
}

@keyframes revenue-bar-grow {
    from {
        transform: scaleY(0);
    }
    to {
        transform: scaleY(1);
    }
}

.revenue-bar-seg {
    position: relative;
    box-shadow: inset 3px 0 0 rgba(255, 255, 255, 0.22), inset -2px 0 0 rgba(0, 0, 0, 0.18);
}

.revenue-bar-seg.revenue-bar-parts {
    background: linear-gradient(180deg, #f5a83a 0%, #e67e22 55%, #cc6a12 100%);
    border-bottom: 1px solid rgba(0, 0, 0, 0.25);
}

.revenue-bar-seg.revenue-bar-works {
    background: linear-gradient(180deg, #22c3a6 0%, #16a085 55%, #0f7a63 100%);
}

.revenue-bar-month {
    margin-top: 8px;
    font-size: 0.78rem;
    color: #95a5a6;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

/* Сравнение трудоемкости/отработки — same track/value/month scaffolding as
   .revenue-*, but each month is a *pair* of single-color bars side by side
   (Тр-ть факт left, Отработка факт right) instead of one stacked bar, so
   .labor-bar-col needs more width than .revenue-bar-col for two bars plus
   a gap to fit comfortably. */
.labor-bar-col {
    flex: 1 1 96px;
    min-width: 84px;
}

.labor-bar-pair {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 2px;
    width: 100%;
}

.labor-bar-item {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.labor-bar {
    width: 90%;
    max-width: 42px;
    margin: 0 auto;
    box-shadow: inset 3px 0 0 rgba(255, 255, 255, 0.22), inset -2px 0 0 rgba(0, 0, 0, 0.18), 0 8px 16px -6px rgba(0, 0, 0, 0.55);
    transform-origin: bottom;
    animation: revenue-bar-grow 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    transition: filter 0.15s ease, transform 0.15s ease;
}

/* Rounded only on each bar's outer edge, square on the edge that touches
   its partner — reads as one glued two-tone unit per month rather than two
   separate bars, per the owner's request to bring the pair closer together. */
.labor-bar-fact {
    border-radius: 7px 2px 2px 2px;
}

.labor-bar-actual {
    border-radius: 2px 7px 2px 2px;
}

.labor-bar:hover {
    filter: brightness(1.1);
    transform: translateY(-2px);
}

.labor-bar-fact {
    background: linear-gradient(180deg, #6c8cf5 0%, #4a63d6 55%, #38499e 100%);
}

.labor-bar-actual {
    background: linear-gradient(180deg, #22c3a6 0%, #16a085 55%, #0f7a63 100%);
}

/* Непроизводственная часть отработки — верхний сегмент того же столбика.
   Оранжевый, как «Простой» в табеле, чтобы цвет читался одинаково в обоих
   местах. Позиционируется от верха, потому что столбик растёт снизу. */
.labor-bar-nonprod {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    background: linear-gradient(180deg, #f5b041 0%, #e67e22 60%, #ca6f1e 100%);
    border-radius: 2px 7px 0 0;
}

.labor-bar-actual {
    position: relative;
}

.labor-swatch-fact {
    background: linear-gradient(160deg, #6c8cf5, #38499e);
}

.labor-swatch-actual {
    background: linear-gradient(160deg, #22c3a6, #0f7a63);
}

/* Стоимость часа по трудоемкости/по отработке — one bar per month again,
   like .revenue-bar-stack, but a single flat rate rather than a stacked
   split, so it gets its own (purple) color rather than reusing revenue's
   teal/amber, which are already "spoken for" as Работы/ЗИП elsewhere on
   this page. */
.rate-bar {
    width: 62%;
    max-width: 44px;
    margin: 0 auto;
    border-radius: 7px 7px 2px 2px;
    background: linear-gradient(180deg, #b088e8 0%, #8e63c9 55%, #6a459e 100%);
    box-shadow: inset 3px 0 0 rgba(255, 255, 255, 0.22), inset -2px 0 0 rgba(0, 0, 0, 0.18), 0 8px 16px -6px rgba(0, 0, 0, 0.55);
    transform-origin: bottom;
    animation: revenue-bar-grow 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    transition: filter 0.15s ease, transform 0.15s ease;
}

/* Прирост ставки, который даёт исключение дороги и простоя из знаменателя.
   Тот же оранжевый, что у непроизводственной отработки в остальных графиках:
   всюду на этих страницах он означает влияние непроизводственного времени. */
.rate-bar {
    position: relative;
}

/* Правый столбик пары — ставка только по производственным часам. Оранжевый,
   как непроизводственные часы везде в приложении: это та же величина,
   показанная с другой стороны. Когда дороги и простоя в месяце нет,
   столбик приглушается — он дублирует левый и не должен перетягивать взгляд. */
.rate-bar-prod {
    background: linear-gradient(180deg, #f5b041 0%, #e67e22 100%);
}

.rate-bar-same {
    opacity: 0.35;
}

.rate-bar-pair .revenue-bar-value {
    min-height: 1em;
}

.rate-bar-nonprod {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    background: linear-gradient(180deg, #f5b041 0%, #e67e22 100%);
    border-radius: 7px 7px 0 0;
}

.rate-bar:hover {
    filter: brightness(1.1);
    transform: translateY(-2px);
}

/* Отклонение по датам завершения — a zero-baseline waterfall, one row per
   order: bar grows right (red/orange) if date_end_fact is after
   date_end_plan, left (green) if before/on time. Color comes from the same
   good/warn/bad banding as everywhere else, not from the left/right
   direction, so band-good never colors a bar red regardless of which side
   it's on. */
.variance-filter-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
}

.variance-summary {
    color: #bdc3c7;
    margin-bottom: 16px;
}

.variance-chart {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: 1100px;
    margin: 0 auto;
}

.variance-row {
    display: grid;
    grid-template-columns: 260px 1fr 56px;
    align-items: center;
    gap: 10px;
}

.variance-label {
    color: #ecf0f1;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: left;
    font-size: 13px;
}

.variance-label:hover {
    text-decoration: underline;
}

.variance-track {
    position: relative;
    height: 16px;
    background: #1c2833;
    border-radius: 2px;
}

.variance-zero {
    position: absolute;
    left: 50%;
    top: 0;
    bottom: 0;
    width: 1px;
    background: #7f8c8d;
}

.variance-bar {
    position: absolute;
    top: 0;
    bottom: 0;
    border-radius: 2px;
}

.variance-bar.band-good {
    background: #7ee787;
}

.variance-bar.band-warn {
    background: #f39c12;
}

.variance-bar.band-bad {
    background: #e74c3c;
}

.variance-days {
    font-size: 12px;
    text-align: right;
    color: #ecf0f1;
}

/* Landscape-phone OR-condition, see the first `max-width: 740px` block
   near the top of this file for why. */
@media (max-width: 740px), (max-height: 500px) and (orientation: landscape) {
    .variance-row {
        grid-template-columns: 1fr;
        gap: 2px;
        margin-bottom: 6px;
    }

    .variance-days {
        text-align: left;
    }
}

/* Освоение нормо-часов — reuses .variance-row/.variance-label/.variance-days
   from the chart above (same row shell), just a 0-based bar instead of a
   zero-baseline waterfall, with the 80-120% norm corridor shaded on the
   track and a 100% reference line, both positioned in % of $maxScale by
   chart_utilization.php inline. */
.util-track {
    position: relative;
    height: 16px;
    background: #1c2833;
    border-radius: 2px;
}

.util-corridor {
    position: absolute;
    top: 0;
    bottom: 0;
    background: rgba(126, 231, 135, 0.12);
}

.util-hundred {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: #7f8c8d;
}

.util-bar {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    border-radius: 2px;
}

/* Непроизводственная часть отработки — правый конец той же полосы.
   Освоение считается от всей отработки, поэтому сегмент занимает свой
   процент внутри полосы, а не откладывается по общей шкале. */
/* Продолжение полосы освоения за её концом — дорога и простой. Полоса
   показывает освоение по производственным часам, этих часов в ней нет,
   поэтому закрашивать её кусок нельзя: продолжение честнее и заодно
   всегда видно — оно лежит на пустой части дорожки. */
.util-bar-extra {
    position: absolute;
    top: 0;
    bottom: 0;
    background-color: #e67e22;
    background-image: repeating-linear-gradient(
        135deg,
        rgba(0, 0, 0, 0.3) 0 4px,
        rgba(255, 255, 255, 0.22) 4px 8px
    );
    border-left: 2px solid #fdf2e3;
    border-radius: 0 3px 3px 0;
    min-width: 3px;
}

.util-bar.band-good {
    background: #7ee787;
}

.util-bar.band-warn {
    background: #f39c12;
}

/* Задачи — bell icon in the header, the login-day modal, and the shared
   task-list markup rendered both there and on /tasks.php. */
.tasks-bell {
    position: relative;
    text-decoration: none;
    font-size: 1.2rem;
    padding: 4px 8px;
    line-height: 1;
}

.badge {
    position: absolute;
    top: -4px;
    right: -2px;
    background: #e74c3c;
    color: #fff;
    border-radius: 999px;
    font-size: 0.65rem;
    padding: 1px 5px;
    line-height: 1.3;
}

/* Mobile-only primary-section navigation (Заказы/Табеля/Графики/Задачи/
   Админка) — see includes/header.php. Hidden by default; the mobile media
   query below turns it into a fixed bottom bar. Desktop keeps using the
   top .nav-buttons row's .primary-nav-link items instead, unchanged. */
.bottom-tab-bar {
    display: none;
}

.bottom-tab-icon {
    position: relative;
    display: block;
    font-size: 1.3rem;
    line-height: 1.2;
}

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 20px;
}

.modal-box {
    background: #34495e;
    color: #ecf0f1;
    text-align: left;
    border-radius: 8px;
    padding: 18px 20px;
    max-width: 560px;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
}

/* Login "Ваши задачи на сегодня" modal — the generic h2's default browser
   margin (~16px top/bottom at 20px font) made the header alone take as
   much vertical space as a couple of task rows; tightened here rather than
   touching h2 globally, since other pages' h2 spacing is unrelated. */
.modal-box h2 {
    margin: 0 0 10px;
    font-size: 1.1rem;
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 12px;
}

.task-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.task-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid #ecf0f1;
}

.task-item:last-child {
    border-bottom: none;
}

/* Login "Ваши задачи на сегодня" modal only — scoped under .modal-box so
   the full /tasks.php page (same .task-list/.task-item markup, via
   render_task_list_html()) keeps its normal spacing. Tighter padding,
   smaller text, and a low-opacity divider read as more compact without
   dropping any information. */
.modal-box .task-item {
    padding: 7px 0;
    border-bottom-color: rgba(236, 240, 241, 0.15);
    font-size: 0.9rem;
}

.task-label {
    display: flex;
    align-items: center;
    gap: 8px;
}

.task-checkbox {
    cursor: pointer;
}

.task-order-link {
    font-size: 0.8rem;
    white-space: nowrap;
}

.task-item-done {
    color: #7f8c8d;
}

.task-meta {
    font-size: 0.75rem;
    white-space: nowrap;
}

/* /tasks.php's h1/h2 used to need a scoped text-align:left override here
   (inherited centering from body{text-align:center} otherwise) — now moot,
   the page content is wrapped in .help-page (same treatment as help.php /
   install_app.php), which already sets text-align:left for the whole
   column. Left this comment as a pointer in case that wrapper ever comes
   off and the centering silently comes back. */

/* Landscape-phone OR-condition, see the first `max-width: 740px` block
   near the top of this file for why. */
@media (max-width: 740px), (max-height: 500px) and (orientation: landscape) {
    body[data-section="tasks"] .task-label span {
        font-size: 0.9rem;
    }
    body[data-section="tasks"] .task-checkbox {
        width: 1.1em;
        height: 1.1em;
    }
}

.task-overview-order-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.task-overview-order-list li {
    padding: 3px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.task-overview-order-list li:last-child {
    border-bottom: none;
}

details summary {
    cursor: pointer;
    color: #85c1ff;
}

.task-audit-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.75rem;
    white-space: nowrap;
}

.task-audit-user {
    background: #f39c12;
    color: #2c3e50;
}

.task-audit-system {
    background: #7ee787;
    color: #2c3e50;
}

/* Сверка табеля (admin_timesheet_reconciliation.php) — one <details> card
   per month, most recent first. Same dark-surface/teal-accent language as
   the rest of the admin pages, just introducing a semantic warn/bad pair
   (amber for "worth a look", red reserved for a genuinely failed run) on
   top of it. */
.reconcile-card {
    background: #2c3e50;
    border: 1px solid #34495e;
    border-radius: 10px;
    margin-bottom: 14px;
}

.reconcile-card-failed {
    padding: 14px 18px;
}

.reconcile-card summary {
    padding: 14px 18px;
    cursor: pointer;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
}

.reconcile-card summary::-webkit-details-marker {
    display: none;
}

.reconcile-summary-left {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.reconcile-month {
    font-weight: 700;
    font-size: 1rem;
}

.reconcile-generated {
    font-size: 0.75rem;
    color: #95a5a6;
    white-space: nowrap;
}

.reconcile-pill {
    display: inline-block;
    font-size: 0.72rem;
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 999px;
}

.reconcile-pill-good {
    background: rgba(22, 160, 133, 0.18);
    color: #22c3a6;
}

.reconcile-pill-warn {
    background: rgba(230, 126, 34, 0.18);
    color: #e67e22;
}

.reconcile-pill-bad {
    background: rgba(224, 82, 74, 0.18);
    color: #e0524a;
}

.reconcile-pill-dim {
    background: rgba(149, 165, 166, 0.15);
    color: #95a5a6;
}

.reconcile-body {
    padding: 4px 18px 18px;
    border-top: 1px solid #34495e;
}

.reconcile-body h3 {
    font-size: 0.92rem;
    margin: 20px 0 4px;
}

.reconcile-lead {
    color: #95a5a6;
    font-size: 0.82rem;
    margin: 0 0 10px;
}

.reconcile-dim {
    color: #95a5a6;
    font-size: 0.85em;
}

.reconcile-tbl-wrap {
    overflow-x: auto;
    border-radius: 8px;
    border: 1px solid #34495e;
}

table.reconcile-tbl {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
    background: #1c2833;
}

.reconcile-tbl th {
    text-align: left;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #95a5a6;
    background: #202b38;
    padding: 8px 12px;
    border-bottom: 1px solid #34495e;
    white-space: nowrap;
}

.reconcile-tbl td {
    padding: 8px 12px;
    border-bottom: 1px solid #2c3944;
}

.reconcile-tbl tr:last-child td {
    border-bottom: none;
}

.reconcile-tbl th.num,
.reconcile-tbl td.num {
    text-align: right;
}

.reconcile-tbl td.mono,
.reconcile-tbl th.mono {
    font-family: monospace;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.reconcile-diff-pos {
    color: #e67e22;
    font-weight: 700;
}

.reconcile-diff-neg {
    color: #e0524a;
    font-weight: 700;
}

.reconcile-subdetails {
    margin-top: 14px;
    background: #1c2833;
    border: 1px solid #34495e;
    border-radius: 8px;
    padding: 2px 14px 14px;
}

.reconcile-subdetails summary {
    padding: 10px 0;
    cursor: pointer;
    font-weight: 700;
    font-size: 0.85rem;
    list-style: none;
}

.reconcile-subdetails summary::-webkit-details-marker {
    display: none;
}

/* Коды времени в табеле. Ячейка с кодом не по умолчанию подсвечивается, а сам
   код виден как двухбуквенная метка в placeholder — она показывается, когда
   часов нет, и не мешает, когда есть. */
/* Цвет ячейки задаётся в справочнике и приходит inline-стилем — здесь
   только поведение, чтобы палитру можно было менять без правки кода. */
.timesheet-table .absence-input { cursor: pointer; text-align: center; }
.timesheet-table tr.absence-row .col-order { color: #777; }

/* Один список на всю страницу, переезжает к активной ячейке. */
.cell-code-picker {
    position: absolute;
    z-index: 60;
    min-width: 150px;
    font-size: 13px;
    padding: 2px 4px;
}

/* Метка кода в углу ячейки — видна и когда часы проставлены. */
.timesheet-table td.day-col { position: relative; }
.timesheet-table .cell-mark {
    position: absolute;
    top: 0;
    left: 1px;
    font-size: 8px;
    line-height: 1;
    font-weight: 700;
    color: #555;
    pointer-events: none;
}

/* Сообщение об ошибке сохранения — тем же всплывающим окном, что и «Сохранено»,
   но красным и подольше: после сохранения страница возвращается на прежнее
   место в сетке, и полосу наверху человек не видит. */
.ts-toast-error {
    background-color: #c0392b;
    max-width: min(560px, 90vw);
    text-align: center;
    line-height: 1.35;
    font-weight: 600;
}

/* Отметка о закрытом месяце табеля рядом с заголовком. */
.month-lock-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    background: #fdecea;
    color: #8a2318;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}

/* Пять колонок расчёта компенсационных дней справа от итогов. */
.timesheet-table .col-comp {
    min-width: 76px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    background: #f6f8fb;
}
.timesheet-table th.col-comp {
    font-size: 11px;
    line-height: 1.2;
    white-space: normal;
}
.timesheet-table .col-comp-final { font-weight: 700; }
.timesheet-table .comp-previous-input {
    width: 66px;
    text-align: center;
    font-size: 12px;
}

/* Панель над таблицей заказов: «Столбцы» и «Группировка» стоят в одну линию.
   position: relative — якорь для раскрывающихся панелей ниже. */
.orders-toolbar {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px;
}

/* Раскрытые списки вынуты из потока и прижаты к панели целиком. Без этого
   flex-элемент растягивался по своему max-content — список столбцов занимал
   3468px при ширине страницы 1400, страница уезжала вбок, а сама кнопка
   (inline-flex внутри блока с text-align: center) вставала в середину этой
   простыни. Заодно кнопки больше не прыгают при открытии. */
.orders-toolbar .column-toggles-dropdown .checkbox-container {
    position: absolute;
    left: 0;
    top: 100%;
    z-index: 200;
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    margin: 4px 0 0;
    padding: 10px 14px;
    text-align: left;
    background-color: #2c3e50;
    border: 1px solid #1abc9c;
    border-radius: 6px;
}

/* Варианты группировки — в строку, как галочки столбцов рядом. */
.orders-toolbar .group-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
}

.group-toggles label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-right: 0;
}

/* Строка-разделитель месяца. Ячейки настоящие, по одной на колонку: в них
   встают суммы за месяц, и скрытие столбца двигает разделитель вместе с
   данными. Цвет намеренно из палитры шапки — так строка не читается как ещё
   один заказ. */
.orders-table tr.order-group-row td {
    background-color: #2c3e50;
    border-top: 2px solid #1abc9c;
    padding: 7px 6px;
    font-weight: bold;
    font-size: 12px;
    color: #1abc9c;
}

/* Название месяца живёт в первой колонке — она липкая, поэтому при прокрутке
   широкой таблицы вбок месяц остаётся на виду сам собой. */
.orders-table tr.order-group-row td:first-child {
    text-align: left;
    padding-left: 10px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.order-group-count {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    background-color: #1abc9c;
    color: #1c2833;
    font-size: 10px;
    font-weight: bold;
    letter-spacing: 0;
}

/* Тот же разделитель для мобильного списка карточек: название месяца и те же
   суммы, что стоят в строке разделителя на большом экране. Отступы по краям
   совпадают с .order-card в мобильном блоке. */
.order-group-heading {
    text-align: left;
    margin: 10px 12px 8px;
    padding: 8px 10px;
    background-color: #2c3e50;
    border-left: 4px solid #1abc9c;
    border-radius: 4px;
    color: #1abc9c;
    font-size: 12px;
}

.order-group-title {
    font-weight: bold;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.order-group-sum {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-top: 4px;
    color: #ecf0f1;
    font-size: 11px;
}

.order-group-sum span:first-child {
    color: #bdc3c7;
}

/* Заказ, у которого выбранной даты нет и месяц определён запасной: та же
   роль и тот же цвет, что у .manual-mark — «значение получено не напрямую». */
.group-substitute {
    margin-left: 4px;
    color: #f39c12;
    cursor: help;
    font-size: 11px;
}

/* Свободный текст внутри всплывающей подсказки. Оболочка подсказки намеренно
   nowrap (числа и фамилии в ней переносить нельзя), поэтому описание переносим
   сами: блок со своей шириной и сохранением переводов строк. */
.tooltip-note {
    display: block;
    max-width: 320px;
    white-space: pre-wrap;
}

/* Отчёт о доходах и расходах (reports_pnl.php).
   Тема приложения тёмная (#2c3e50 / #ecf0f1), поэтому разделы выделяются не
   светлой заливкой, а полупрозрачным осветлением — иначе светлый текст ложится
   на светлый фон и цифры пропадают (замечание владельца 16.09.2026). */
.pnl-table .pnl-section {
    background: rgba(255, 255, 255, 0.10);
    cursor: pointer;
    font-weight: bold;
}
.pnl-table .pnl-section:hover {
    background: rgba(255, 255, 255, 0.16);
}
.pnl-table .pnl-detail td {
    color: #cfd8dc;
}
/* Первый столбец у всех таблиц приложения залит #1abc9c и жирный (правило
   td:first-child выше). Для строк-статей делаем его темнее и обычным
   начертанием, иначе статья и раздел в первом столбце неотличимы. */
.pnl-table .pnl-detail td:first-child {
    background-color: #16a085;
    font-weight: normal;
}
.pnl-table .pnl-ratio td:first-child {
    background-color: #16a085;
    font-weight: normal;
}
.pnl-table .pnl-gross td {
    border-top: 2px solid #7f8c8d;
    font-weight: bold;
}
.pnl-table .pnl-profit td {
    border-top: 2px solid #ecf0f1;
    background: rgba(26, 188, 156, 0.16);
    font-weight: bold;
}
.pnl-table .pnl-ratio td {
    color: #95a5a6;
    font-style: italic;
}
/* Убыток — красный из палитры приложения: #b00 на тёмном фоне почти чёрный. */
.pnl-negative {
    color: #e74c3c;
}
.pnl-note-missing {
    color: #f1c40f;
}
/* Рентабельность под суммой в ячейке отчёта по проектам: величина справочная,
   главное в ячейке — деньги. */
.pnl-cell-pct {
    color: #95a5a6;
    font-size: 0.85em;
}
/* ДиР по проектам — мельче остальных таблиц: полторы сотни строк с девятью
   колонками цифр, владелец 17.09.2026: «сделай чуть мельче, а то как-то крупно». */
.pnl-table.pnl-compact {
    font-size: 0.78rem;
}
.pnl-table.pnl-compact td,
.pnl-table.pnl-compact th {
    padding: 3px 6px;
    line-height: 1.25;
}
.pnl-table.pnl-compact .pnl-month td {
    padding-top: 7px;
}
/* Заголовок месяца и подытог в отчёте по проектам: месяцы должны отделяться
   друг от друга, иначе полторы сотни строк сливаются в одну простыню. */
.pnl-table .pnl-month td {
    background: rgba(255, 255, 255, 0.10);
    font-weight: bold;
    text-align: left;
    padding-top: 10px;
}
.pnl-table .pnl-month-total td {
    border-top: 1px solid #7f8c8d;
    border-bottom: 2px solid #7f8c8d;
    font-weight: bold;
}
/* Цифра-ссылка на страницу проверки: выглядит как обычное число, но по наведению
   подчёркивается — иначе таблица превратилась бы в ковёр из синих ссылок. */
.pnl-drill,
.pnl-drill:visited {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted rgba(255, 255, 255, 0.35);
}
.pnl-drill:hover {
    color: #1abc9c;
    border-bottom-color: #1abc9c;
}

/* «Аналитик Claude» (analysis_terminal.php): рамка вокруг ttyd-терминала.
   Высота — от низа шапки до низа окна, чтобы терминал не жил в маленьком
   окошке с двойной прокруткой; на телефоне (нижняя панель) — просто
   фиксированный минимум. */
.analysis-terminal-head { margin-bottom: 8px; }
.analysis-terminal-head h1 { margin-bottom: 4px; }
.analysis-terminal-hint { max-width: 70em; }
.analysis-terminal-examples { margin: 4px 0 8px 1.2em; color: #555; font-size: 0.92em; }
.analysis-terminal-examples li { margin: 2px 0; }
.analysis-terminal-frame {
    display: block;
    width: 100%;
    height: calc(100vh - 230px);
    min-height: 420px;
    border: 1px solid #b7c2cc;
    border-radius: 6px;
    background: #000;
}
@media (max-width: 739px) {
    .analysis-terminal-frame { height: 70vh; }
}

/* «Софт» (software.php) — карточки программ с файлами для скачивания. */
.software-page h2 { font-size: 1.1rem; margin: 0 0 6px; color: #1abc9c; }
.software-card {
    background-color: #34495e;
    border-radius: 8px;
    padding: 16px 18px;
    margin-bottom: 14px;
}
.software-desc { margin: 0 0 12px; font-size: 0.9rem; line-height: 1.5; }
.software-files { display: flex; flex-direction: column; gap: 8px; }
.software-file {
    display: grid;
    grid-template-columns: 8.5em 1fr auto;
    grid-template-areas: "os name action" "os meta action";
    align-items: center;
    column-gap: 12px;
    padding: 10px 14px;
    border-radius: 6px;
    background-color: #2c3e50;
    border: 1px solid rgba(236, 240, 241, 0.12);
    color: #ecf0f1;
    text-decoration: none;
    transition: border-color 0.15s, background-color 0.15s;
}
.software-file:hover { border-color: #1abc9c; background-color: #2f4658; }
.software-file:focus-visible { outline: 2px solid #1abc9c; outline-offset: 2px; }
.software-file-mine { border-color: #16a085; }
.software-os { grid-area: os; font-weight: bold; white-space: nowrap; }
.software-file-name { grid-area: name; font-size: 0.92rem; overflow-wrap: anywhere; }
.software-file-meta { grid-area: meta; font-size: 0.8rem; color: #b7c2cc; }
.software-file-mine .software-file-meta { color: #1abc9c; }
.software-file-action {
    grid-area: action;
    background-color: #3498db;
    color: #ecf0f1;
    border-radius: 5px;
    padding: 8px 14px;
    font-size: 0.85rem;
    white-space: nowrap;
}
.software-file:hover .software-file-action { background-color: #2980b9; }
@media (max-width: 739px) {
    .software-file { grid-template-columns: 1fr auto; grid-template-areas: "os action" "name action" "meta action"; row-gap: 2px; }
}

/* ДиР → «Нижняя цена КП» (reports_pnl.php?view=floor): карточки ввода и плитки результата. */
.floor-grid { display: flex; flex-wrap: wrap; gap: 12px; margin: 10px 0; }
.floor-card { background-color: #34495e; border-radius: 8px; padding: 10px 14px; text-align: left; display: flex; flex-direction: column; gap: 8px; min-width: 260px; }
.floor-card label { display: flex; flex-direction: column; gap: 3px; font-size: 0.88rem; color: #b7c2cc; }
.floor-card input[type=number], .floor-card select { font: inherit; padding: 5px 8px; border-radius: 5px; border: 1px solid #7f8c8d; background: #2c3e50; color: #ecf0f1; }
.floor-card .floor-check { flex-direction: row; align-items: center; gap: 8px; color: #ecf0f1; }
.floor-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; margin: 10px 0 14px; text-align: left; }
.floor-tile { background-color: #34495e; border-radius: 8px; padding: 10px 14px; }
.floor-label { font-size: 0.82rem; color: #b7c2cc; }
.floor-num { font-size: 1.5rem; font-weight: bold; color: #1abc9c; font-variant-numeric: tabular-nums; margin-top: 2px; }
.floor-num.floor-bad { color: #e74c3c; }
.floor-num.floor-good { color: #2ecc71; }
.floor-sub { font-size: 0.8rem; color: #b7c2cc; margin-top: 2px; }
.modal-box.modal-wide { max-width: 780px; }
.modal-overlay[hidden] { display: none; }
.floor-algo { padding-left: 22px; margin: 6px 0 0; font-size: 0.92rem; line-height: 1.5; }
.floor-algo li { margin: 6px 0; }

/* ---- «Управленческий дашборд» (dashboard.php) ----
   Отдельная тёмная палитра поверх общего стиля, по образцу дашборда коллеги
   (2026-09-21): всё под .dash, токены переопределяются для светлой темы
   через [data-theme="light"]. Страница во всю ширину: отрицательный отступ
   компенсирует padding общего main. */
.dash {
    --d-bg: #0b1220; --d-bg2: #0f182b; --d-panel: #121c31; --d-panel2: #182540; --d-border: #233152;
    --d-text: #e7edf8; --d-muted: #8d9cbb; --d-accent: #2dd4bf; --d-accent-dark: #0b1220;
    --d-red: #f26b6b; --d-orange: #f5a15a; --d-purple: #b48cf2; --d-green: #4ade80;
    display: grid; grid-template-columns: 236px minmax(0, 1fr); margin: -20px; min-height: 100vh;
    background: var(--d-bg); color: var(--d-text); text-align: left;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.dash[data-theme="light"] {
    --d-bg: #f3f6fb; --d-bg2: #e9eef7; --d-panel: #ffffff; --d-panel2: #f2f5fb; --d-border: #d9e1ef;
    --d-text: #14213d; --d-muted: #5c6b8a; --d-accent: #0f9f8f; --d-accent-dark: #ffffff;
    --d-red: #d64545; --d-orange: #d97b1f; --d-purple: #7b52d1; --d-green: #1f9d55;
}
.dash a { color: var(--d-accent); text-decoration: none; }
.dash a:hover { text-decoration: underline; }
.dash-side { background: var(--d-bg2); border-right: 1px solid var(--d-border); padding: 22px 18px; display: flex; flex-direction: column; gap: 14px; position: sticky; top: 0; align-self: start; height: 100vh; box-sizing: border-box; }
.dash-back { display: inline-block; align-self: flex-start; font-size: 0.82rem; color: var(--d-muted); border: 1px solid var(--d-border); border-radius: 999px; padding: 4px 12px; }
.dash-back:hover { color: var(--d-text); text-decoration: none; border-color: var(--d-accent); }
.dash-brand { font-size: 1.6rem; font-weight: 800; letter-spacing: 0.02em; color: var(--d-text); }
.dash-brand span { color: var(--d-accent); }
.dash-side-label { font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--d-muted); margin-top: 6px; }
.dash-side-nav { display: flex; flex-direction: column; gap: 2px; }
.dash-side-nav a { display: block; padding: 9px 12px; border-radius: 8px; color: var(--d-text); border-left: 3px solid transparent; }
.dash-side-nav a.active { background: var(--d-panel2); border-left-color: var(--d-accent); }
.dash-side-nav a.soon { color: var(--d-muted); }
.dash-side-nav a small { font-size: 0.7rem; margin-left: 4px; opacity: 0.7; }
.dash-side-nav a:hover { text-decoration: none; background: var(--d-panel2); }
.dash-side-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 8px; }
.dash-user { border: 1px solid var(--d-border); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 2px; }
.dash-user span { color: var(--d-muted); font-size: 0.85rem; }
.dash-theme { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid var(--d-border); border-radius: 10px; overflow: hidden; }
.dash-theme button { background: transparent; color: var(--d-muted); border: 0; padding: 9px; cursor: pointer; font: inherit; }
.dash-theme button.active { background: var(--d-panel2); color: var(--d-text); font-weight: 600; }
.dash-main { padding: 26px 30px 40px; display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.dash-eyebrow { font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--d-muted); }
.dash-h1 { font-size: 2.3rem; font-weight: 800; margin: 2px 0 6px; color: var(--d-accent); text-align: left; }
.dash-h1 span { color: var(--d-text); }
.dash-lead { margin: 0 0 6px; color: var(--d-muted); max-width: 720px; font-size: 1.05rem; }
.dash-section-title { font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--d-muted); margin-top: 4px; }
.dash-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
.dash-tile { background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 14px; padding: 16px 18px; }
.dash-tile-label { font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--d-muted); }
.dash-tile-num { font-size: 2.1rem; font-weight: 800; margin: 10px 0 4px; font-variant-numeric: tabular-nums; }
.dash-tile-num.bad, .dash .bad { color: var(--d-red); }
.dash-tile-num.warn, .dash .warn { color: var(--d-orange); }
.dash-tile-num.good, .dash .good { color: var(--d-green); }
.dash-tile-num.purple, .dash .purple { color: var(--d-purple); }
.dash-tile-sub { font-size: 0.8rem; color: var(--d-muted); }
.dash-panel { background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 14px; padding: 16px 18px; display: flex; flex-direction: column; gap: 10px; }
.dash-panel-title { font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--d-muted); }
.dash-panel-title.risk { color: var(--d-red); font-weight: 700; }
.dash-panel-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.dash-muted { color: var(--d-muted); font-size: 0.85rem; }
.dash-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.dash-btn { flex: 1 1 200px; display: inline-block; text-align: center; padding: 12px 18px; border-radius: 999px; border: 1px solid var(--d-border); background: var(--d-panel2); color: var(--d-text); font: inherit; font-weight: 600; cursor: pointer; }
.dash-btn.primary { background: var(--d-accent); color: var(--d-accent-dark); border-color: var(--d-accent); }
.dash-btn:hover { text-decoration: none; filter: brightness(1.1); }
.dash-risks { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.dash-risk-col { background: var(--d-bg2); border: 1px solid var(--d-border); border-radius: 12px; padding: 12px; min-height: 120px; }
.dash-risk-head { font-weight: 700; margin-bottom: 8px; text-transform: uppercase; font-size: 0.85rem; letter-spacing: 0.04em; }
.dash-risk-head::before { content: "●"; margin-right: 6px; }
.dash-risk-list { display: flex; flex-direction: column; gap: 8px; max-height: 330px; overflow-y: auto; }
.dash-risk-card { display: block; background: var(--d-panel); border: 1px solid var(--d-border); border-radius: 10px; padding: 10px 12px; color: var(--d-text); }
.dash-risk-card:hover { text-decoration: none; border-color: var(--d-accent); }
.dash-risk-title { font-weight: 700; margin-bottom: 2px; }
.dash-risk-line { font-size: 0.85rem; color: var(--d-muted); }
.dash-empty { color: var(--d-muted); padding: 14px 8px; text-align: center; }
.dash-field { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem; color: var(--d-muted); }
.dash-field input, .dash-field select { background: var(--d-bg2); color: var(--d-text); border: 1px solid var(--d-border); border-radius: 10px; padding: 10px 12px; font: inherit; color-scheme: dark; }
.dash[data-theme="light"] .dash-field input, .dash[data-theme="light"] .dash-field select { color-scheme: light; }
.dash-filter-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
.dash-checks { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; font-size: 0.9rem; }
.dash-checks label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.dash-checks .dash-btn { flex: 0 0 auto; margin-left: auto; padding: 9px 18px; }
.dash-scroll { overflow-x: auto; }
/* Общие правила таблиц (липкая бирюзовая первая колонка, центрирование,
   12px) здесь гасятся: у дашборда свой вид, цвет строки — полоска слева. */
.dash-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; min-width: 1180px; background: transparent; color: var(--d-text); }
.dash-table thead { position: static; background: transparent; }
.dash-table thead th { text-align: left; font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--d-muted); padding: 10px 10px; border-bottom: 1px solid var(--d-border); background: var(--d-panel); white-space: normal; }
.dash-table tbody td { padding: 12px 10px; border-bottom: 1px solid var(--d-border); vertical-align: top; text-align: left; white-space: normal; }
.dash-table td:first-child, .dash-table th:first-child { position: static; background: transparent; font-weight: normal; z-index: auto; border-left: 3px solid transparent; }
.dash-table tbody td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dash-table thead th:nth-child(n+5):nth-child(-n+11) { text-align: right; }
.dash-table tbody tr:hover td { background: var(--d-panel2); }
.dash-table .dash-n { color: var(--d-muted); }
.dash-table .dash-title { min-width: 220px; }
.dash-table .dash-title a { font-size: 0.85rem; }
.dash-table .dash-notes { max-width: 260px; color: var(--d-muted); font-size: 0.85rem; }
.dash-table tr.dash-purple td:first-child { border-left-color: var(--d-purple); }
.dash-table tr.dash-red td:first-child { border-left-color: var(--d-red); }
.dash-table tr.dash-orange td:first-child { border-left-color: var(--d-orange); }
.dash-table tr.dash-green td:first-child { border-left-color: var(--d-green); }
.dash-badge { display: inline-block; padding: 4px 10px; border-radius: 999px; font-size: 0.8rem; font-weight: 600; background: var(--d-panel2); white-space: nowrap; }
.dash-badge.risk { color: var(--d-orange); background: rgba(245, 161, 90, 0.15); }
.dash-badge.work { color: var(--d-accent); background: rgba(45, 212, 191, 0.12); }
.dash-badge.done { color: var(--d-green); background: rgba(74, 222, 128, 0.12); }
@media (max-width: 900px) {
    .dash { grid-template-columns: 1fr; margin: -12px; }
    .dash-side { position: static; height: auto; padding: 14px 16px; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 10px; }
    .dash-side-label { display: none; }
    .dash-back { align-self: center; }
    .dash-side-nav { flex-direction: row; flex-wrap: wrap; }
    .dash-side-nav a { padding: 6px 10px; border-left: 0; }
    .dash-side-bottom { margin-left: auto; flex-direction: row; align-items: center; }
    .dash-user { display: none; }
    .dash-main { padding: 16px; }
    .dash-h1 { font-size: 1.7rem; }
    .dash-risks { grid-template-columns: 1fr; }
    .dash-checks .dash-btn { margin-left: 0; }
}
