/* #123 */

.fm-density {
    display: inline-flex;
    gap: 0;
    border: 0.0625rem solid var(--border);
    padding: 0;
    overflow: hidden;
}
.fm-density-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.625rem;
    height: 1.375rem;
    background: transparent;
    border: 0;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0;
    line-height: 0;
}
.fm-density-btn + .fm-density-btn { border-left: 0.0625rem solid var(--border); }
.fm-density-btn svg { display: block; }
.fm-density-btn:hover { color: var(--text-primary); }
.fm-density-btn.is-active {
    color: var(--accent);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
}

/* Q5 — bottom quick-action bar + create sheet. Industrial: sharp corners,
   square "+" embedded center (Material research: embedded centered FAB wins
   on ergonomics), sheet slides from the bottom edge (thumb zone), mono micro
   title, hairline dividers. Items come from role_actions context='quick'. */
.fm-bottombar {
    transition: transform var(--dur-normal) var(--ease-out);
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 90;
    display: flex;
    align-items: center;
    justify-content: space-around;
    height: calc(3.5rem + env(safe-area-inset-bottom, 0px));
    padding-bottom: env(safe-area-inset-bottom, 0px);
    /* §12 — floating translucent tab bar: content scrolls UNDER the glass,
       matching the header. Solid fallback under reduced-transparency below. */
    background: color-mix(in srgb, #0a0a0a 72%, transparent);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    backdrop-filter: blur(20px) saturate(180%);
    border-top: 0.0625rem solid color-mix(in srgb, #ffffff 8%, transparent);
}
@media (prefers-reduced-transparency: reduce) {
    .fm-bottombar {
        background: #0a0a0a;
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        border-top-color: var(--border);
    }
}
/* Content must never hide behind the fixed bar (scoped to pages that render
   it — also keeps the bare `body` selector single-owner in base.css). */
body:has(.fm-bottombar) { padding-bottom: calc(3.5rem + env(safe-area-inset-bottom, 0px)); }
/* Desktop (≥1100px, тот же порог что .footer/.nav-footer): нижний таб-бар —
   мобильный паттерн, на десктопе навигация живёт в хедере. Прячем и снимаем
   резерв высоты (app.js замерит offsetHeight=0 → --fm-bottombar-h=0). */
@media (min-width: 68.75em) {
    .fm-bottombar { display: none; }
    body:has(.fm-bottombar) { padding-bottom: 0; }
}
/* Q6 tab: icon + micro mono label, muted → primary when active. */
.fm-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    min-width: 3.5rem;
    min-height: 2.75rem;
    padding: 0.2rem 0.4rem;
    background: transparent;
    border: none;
    color: var(--text-muted);
    text-decoration: none;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    line-height: 1;
    transition: color var(--dur-fast) var(--ease-out);
}
.fm-tab.active,
.fm-tab:hover { color: var(--primary); }
.fm-tab .icon { width: 1.125rem; height: 1.125rem; }
/* "+" is first in DOM (Askama can't count filtered loops); flex `order`
   slots it into the middle: home(1) reports(2) [+](3) chat(4) menu(5). */
.fm-bottombar .fm-plus { order: 3; }
.fm-bottombar a.fm-tab:nth-of-type(1) { order: 1; }
.fm-bottombar a.fm-tab:nth-of-type(2) { order: 2; }
.fm-bottombar a.fm-tab:nth-of-type(3) { order: 4; }
.fm-bottombar #fm-tab-menu { order: 5; }
.fm-plus {
    width: 2.75rem;
    height: 2.75rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0.0625rem solid var(--primary);
    color: var(--primary);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}
.fm-plus:active,
.fm-plus[aria-expanded="true"] {
    background: var(--primary);
    color: #111;
}
.fm-qsheet {
    position: fixed;
    inset: 0;
    z-index: 120;
    /* Closed = untouchable + invisible. Class-only state, no [hidden]. The
       visibility transition delay keeps the close animation visible. */
    pointer-events: none;
    visibility: hidden;
    transition: visibility 0s linear var(--dur-normal);
}
.fm-qsheet.is-open {
    pointer-events: auto;
    visibility: visible;
    transition: visibility 0s;
}
.fm-qsheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-out);
}
.fm-qsheet.is-open .fm-qsheet-backdrop { opacity: 1; }
.fm-qsheet-panel {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto; /* guard: bottom-anchored, natural height — never stretched */
    background: var(--bg-surface);
    border-top: 0.0625rem solid var(--border);
    padding: var(--space-md) var(--space-md) calc(var(--space-lg) + env(safe-area-inset-bottom, 0px));
    transform: translateY(100%);
    transition: transform var(--dur-normal) var(--ease-out);
}
.fm-qsheet.is-open .fm-qsheet-panel { transform: translateY(0); }
.fm-qsheet-title {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-muted);
    margin: 0 0 var(--space-sm);
    font-weight: 500;
}
.fm-qsheet-item {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    min-height: var(--tap-target, 3rem);
    padding: var(--space-sm) var(--space-xs);
    color: var(--text-primary);
    text-decoration: none;
    border-bottom: 0.0625rem solid var(--border);
    font-size: var(--content-font, 0.875rem);
}
.fm-qsheet-item:last-child { border-bottom: none; }
.fm-qsheet-item .icon { color: var(--primary); flex-shrink: 0; }
.fm-qsheet-item:hover,
.fm-qsheet-item:focus-visible {
    background: var(--bg-elevated);
    outline: none;
}

/* Q1 — Secondary reference shortcuts, de-emphasized under a label. Quiet
   icon+text links (transparent, muted, small) so project folders stay the
   heaviest thing on the home. Passes the blur test. */
.util-section {
    margin-top: var(--space-lg);
    /* Separate the quiet rules/requirements/archive links from the KPI ledger
       strip below them — .kpi-grid has only margin-bottom, so without this the
       two blocks collapse together. */
    margin-bottom: var(--space-lg);
}
.util-title {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-muted);
    margin: 0 0 var(--space-sm);
    font-weight: 500;
}
.util-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
}
.util-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.4rem 0.7rem;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.75rem;
    line-height: 1.2;
    min-height: var(--tap-target);
    transition: color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}
.util-link svg {
    flex-shrink: 0;
    color: var(--text-muted);
    transition: color var(--dur-fast) var(--ease-out);
}
.util-link:hover,
.util-link:focus-visible {
    color: var(--text-primary);
    border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
    outline: none;
}
.util-link:hover svg,
.util-link:focus-visible svg {
    color: var(--primary);
}
.util-link--quiet {
    color: var(--text-muted);
}

/* #124 — Rework list: informative card list (A16). Industrial-brutalist:
   sharp corners, mono numerals. The "needs rework" signal is carried by the
   rust-red mono index + pill — NO left-border accent rail (banned pattern).
   The card's spine is the reviewer's REASON — what makes it informative. */
.rework-section .rework-title {
    color: var(--secondary);
    border-color: var(--secondary);
    margin: 0;
}
.rework-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    margin-bottom: var(--space-md);
}
.rework-count {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    line-height: 1.4;
    color: var(--secondary);
    border: 1px solid color-mix(in srgb, var(--secondary) 40%, transparent);
    padding: 0 0.45em;
    font-variant-numeric: tabular-nums;
}
.rework-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}
.rework-card {
    --rw: var(--secondary);
    display: grid;
    /* Sequential idx (.rework-idx) dropped — it's per-list loop position, not a
       stable report number, so it carried no meaning and only ate a column. */
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--space-md);
    padding: var(--space-md);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    color: var(--text-primary);
    text-decoration: none;
    transition: transform var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out),
                background var(--dur-fast) var(--ease-out);
}
.rework-card:hover,
.rework-card:focus-visible {
    background: var(--bg-elevated);
    border-color: color-mix(in srgb, var(--rw) 55%, var(--border));
    transform: translateX(2px);
    outline: none;
}
.rework-idx { display: none; }
.rework-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.rework-top {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}
.rework-type {
    font-family: var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.75rem;
    font-weight: 600;
}
.rework-meta {
    font-size: 0.75rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.rework-pill {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--rw);
    border: 1px solid color-mix(in srgb, var(--rw) 35%, transparent);
    padding: 0.15em 0.5em;
    white-space: nowrap;
}
.rework-reason {
    margin: 0;
    font-size: var(--content-font, 0.8125rem);
    line-height: 1.45;
    color: var(--text-primary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.rework-reason-cap {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--rw);
    margin-right: 0.6em;
    vertical-align: 0.08em;
}
.rework-reason--empty {
    color: var(--text-muted);
    font-style: italic;
}
.rework-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-variant-numeric: tabular-nums;
}
.rework-foot .rework-media {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    margin-left: auto;
}
.rework-chevron {
    color: var(--text-muted);
    align-self: center;
    flex-shrink: 0;
    transition: transform var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out);
}
.rework-card:hover .rework-chevron,
.rework-card:focus-visible .rework-chevron {
    color: var(--rw);
    transform: translateX(2px);
}

/* #125 */
.rules-hint {
    font-family: var(--font-mono);
    color: var(--text-muted);
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: var(--space-lg);
    max-width: 80ch;
    line-height: 1.6;
}
.rules-grid {
    display: block;
    margin-bottom: var(--space-2xl);
    background: transparent;
    border-top: 0.0625rem solid var(--border);
    border-bottom: 0.0625rem solid var(--border);
}
.rules-head,
.rule-row {
    display: grid;
    grid-template-columns: var(--grid-cols,
        minmax(10rem, 1.2fr) minmax(10rem, 1fr) minmax(9rem, auto)
        minmax(12rem, 2fr)   minmax(12rem, 2fr) auto auto auto);
    gap: var(--space-md);
    align-items: center;
    padding: var(--space-md) 0;
    border-bottom: 0.0625rem solid var(--border);
}
.rules-head {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--text-muted);
    padding: var(--space-sm) 0;
    border-bottom-color: var(--text-muted);
}
.rule-row:last-of-type { border-bottom: 0; }
.rule-row:hover { background: color-mix(in srgb, var(--primary) 3%, transparent); }
.rule-row .form-input,
.rule-row .form-select,
.rule-row .rule-cell {
    min-width: 0;
}
/* #126 */
.rule-row .form-input,
.rule-row .form-select {
    background: transparent;
    border: 0;
    border-bottom: 0.0625rem solid transparent;
    padding: 0.25rem 0.125rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-primary);
    border-radius: 0;
    transition: border-color 0.15s ease;
}
.rule-row .form-input:hover,
.rule-row .form-select:hover { border-bottom-color: var(--border); }
.rule-row .form-input:focus,
.rule-row .form-select:focus {
    outline: none;
    border-bottom-color: var(--primary);
    background: color-mix(in srgb, var(--primary) 5%, transparent);
}
.rule-row .form-input::placeholder { color: var(--text-muted); opacity: 0.7; }

.channel-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
}
.channel-row .ch {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-muted);
    cursor: pointer;
}
.channel-row .ch input[type="checkbox"] {
    width: 0.75rem;
    height: 0.75rem;
    border-width: 0.0625rem;
}
.channel-row .ch input[type="checkbox"]:checked + span { color: var(--primary); }
.active-cell {
    display: flex;
    justify-content: center;
    align-items: center;
}
.i18n-cell {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.25rem;
}
.rule-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-xs);
}
/* #127 */
.rule-row .btn-sm {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    letter-spacing: 0.12em;
    padding: 0.25rem 0.5rem;
    min-height: 1.5rem;
}
.btn-link-danger {
    background: none;
    border: 0;
    padding: 0.25rem 0.5rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-muted);
    cursor: pointer;
}
.btn-link-danger:hover { color: var(--secondary); }
.rule-row-new {
    background: color-mix(in srgb, var(--bg-elevated) 50%, transparent);
}
.rules-add-title {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: var(--text-muted);
    margin: var(--space-2xl) 0 var(--space-md);
}
.rule-add-form { max-width: 44rem; }

/* #128 */
@media (max-width: 60em) {
    .rules-head { display: none; }
    .rule-row {
        grid-template-columns: 1fr;
        gap: 0.5rem;
        padding: var(--space-md) 0;
    }
    .i18n-cell { grid-template-columns: 1fr; }
}

/* #129 */
.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    overflow: hidden;
    background: var(--bg-surface);
    border: 0.0625rem solid var(--border);
    color: var(--text-muted);
    flex-shrink: 0;
    object-fit: cover;
    vertical-align: middle;
}
.avatar--sm { width: 1.5rem;   height: 1.5rem; }
.avatar--md { width: 2.25rem;  height: 2.25rem; }
.avatar--lg { width: 3rem;     height: 3rem; }
.avatar--xl { width: 10rem;    height: 10rem; border-width: 0.125rem; }
.avatar--placeholder svg {
    width: 60%;
    height: 60%;
    opacity: 0.5;
}
/* #130 */
img.avatar { object-fit: cover; }

/* #131 */
.profile-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-lg);
    align-items: start;
}
@media (min-width: 48em) {
    .profile-grid { grid-template-columns: auto 1fr; }
}
.profile-avatar-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-md);
}
.profile-avatar-form input[type="file"] { display: none; }
.profile-meta {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-xs) var(--space-md);
    margin-top: var(--space-lg);
    font-size: 0.8125rem;
}
.profile-meta dt {
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.6875rem;
}
.profile-meta dd { margin: 0; color: var(--text-primary); }

/* #132 */
.role-indicator {
    position: relative;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0.0625rem solid transparent;
    padding: 0.25rem;
    color: inherit;
    cursor: pointer;
    min-height: 2.25rem;
    min-width: 2.25rem;
}
.role-indicator:hover { border-color: var(--border); }
.role-indicator[aria-expanded="true"] { border-color: var(--accent); }
.role-indicator .role-badge {
    font-size: 0.6875rem;
    padding: 0.25rem 0.5rem;
}

/* #133 */
.fm-cmdk {
    padding: 0;
    border: 0.0625rem solid var(--border);
    background: var(--bg-elevated, var(--bg-surface));
    color: var(--text-primary);
    width: min(40rem, 92vw);
    max-height: 70vh;
    box-shadow: 0 1.5rem 4.5rem rgba(0,0,0,0.5);
    margin: 10vh auto;
    overflow: hidden;
    font-family: var(--font-mono);
}
.fm-cmdk::backdrop { background: rgba(0,0,0,0.55); }
.fm-cmdk-header {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.75rem 0.875rem;
    border-bottom: 0.0625rem solid var(--border);
    color: var(--text-muted);
}
.fm-cmdk-header input {
    flex: 1;
    background: transparent;
    border: 0;
    outline: 0;
    color: var(--text-primary);
    font-size: 0.875rem;
    text-transform: none;
    letter-spacing: normal;
}
.fm-cmdk-kbd {
    font-size: var(--micro-size);
    padding: 0.125rem 0.375rem;
    border: 0.0625rem solid var(--border);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}
.fm-cmdk-list {
    list-style: none;
    margin: 0;
    padding: 0.25rem;
    max-height: calc(70vh - 5.875rem);
    overflow-y: auto;
}
.fm-cmdk-item {
    display: grid;
    grid-template-columns: 4.5rem 1fr auto;
    gap: 0.75rem;
    align-items: center;
    padding: 0.625rem 0.75rem;
    font-size: 0.75rem;
    cursor: pointer;
    color: var(--text-primary);
    min-height: 2.5rem;
}
.fm-cmdk-item.is-selected,
.fm-cmdk-item:hover { background: var(--surface-2, rgba(255,255,255,0.05)); }
.fm-cmdk-cat {
    font-size: var(--micro-size);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    padding: 0.125rem 0.375rem;
    border: 0.0625rem solid var(--border);
    border-radius: 0.125rem;
    text-align: center;
}
.fm-cmdk-title { text-transform: none; letter-spacing: normal; font-size: 0.8125rem; }
.fm-cmdk-meta  { font-size: var(--micro-size); color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.08em; }
.fm-cmdk-empty { padding: 1.25rem 0.875rem; color: var(--text-muted); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.1em; text-align: center; }
.fm-cmdk-hint {
    padding: 0.5rem 0.875rem;
    border-top: 0.0625rem solid var(--border);
    color: var(--text-muted);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.1em;
}

/* #134 */
.fm-ingest-banner {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.625rem 0.875rem;
    margin-bottom: var(--space-md);
    border: 0.0625rem solid var(--accent);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-size: 0.75rem;
}
/* #135 */
.fm-ingest-spin { font-size: 1.125rem; color: var(--accent); animation: spin 1.6s linear infinite; display: inline-block; }
.fm-ingest-refresh {
    margin-left: auto;
    background: transparent;
    border: 0.0625rem solid var(--accent);
    color: var(--accent);
    padding: 0.25rem 0.625rem;
    cursor: pointer;
    font: inherit;
}
.fm-ingest-refresh:hover { background: var(--accent); color: var(--bg-base); }

/* #136 */
.fm-field-error {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    color: var(--secondary, #e2554c);
    margin-top: 0.25rem;
    line-height: 1.3;
}
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
    border-color: var(--secondary, #e2554c) !important;
    box-shadow: 0 0 0 0.0625rem var(--secondary, #e2554c);
}
/* #137 */
.fm-board {
    display: grid;
    grid-template-columns: repeat(var(--fm-cols), 1fr);
    gap: var(--fm-gutter);
    margin-bottom: var(--space-xl);
}
.fm-board-col { grid-column: span var(--fm-cols); }
@media (min-width: 37.5em) { .fm-board-col { grid-column: span 6; } }
@media (min-width: 60em) { .fm-board-col { grid-column: span 3; } }

.fm-board-col-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 0.375rem 0.625rem;
    border-top: 0.125rem solid var(--accent);
    border-bottom: 0.0625rem solid var(--border);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    margin-bottom: var(--space-xs);
}
.fm-board-col-title { color: var(--text-primary); }
.fm-board-col-count { color: var(--text-muted); font-variant-numeric: tabular-nums; }

.fm-board-col-list { display: flex; flex-direction: column; gap: var(--space-xs); }

/* #138 */
.fm-board-card {
    --accent-color: var(--text-muted);
    background: var(--bg-surface);
    border: 0.0625rem solid var(--border);
    /* Card already sits inside its status column — the coloured top-rail was a
       redundant status accent edge (no_left_border_accent). Uniform border. */
    padding: var(--space-sm);
    position: relative;
}

.fm-board-card-title {
    font-family: var(--font-sans);
    font-size: 0.8125rem;
    line-height: 1.35;
    color: var(--text-primary);
}
.fm-board-card-body {
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--text-secondary);
    white-space: pre-wrap;
    word-break: break-word;
}
.fm-board-card-foot {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.375rem;
    flex-wrap: wrap;
}
.fm-board-card-meta {
    flex: 1;
    min-width: 0;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fm-board-card-move { display: inline; margin: 0; }
.fm-board-btn {
    background: transparent;
    border: 0;
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    padding: 0.125rem 0.375rem;
    min-height: 1.375rem;
    cursor: pointer;
}
.fm-board-btn:hover:not(:disabled) { color: var(--accent); border-color: var(--accent); }
.fm-board-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.fm-board-btn-danger:hover { color: var(--secondary); border-color: var(--secondary); }
.fm-board-card-edit { margin-top: 0.375rem; }
.fm-board-empty {
    padding: var(--space-sm);
    color: var(--text-muted);
    text-align: center;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
}

/* #138 */
.fm-onboarding-layer { position: absolute; top: 0; left: 0; width: 0; height: 0; pointer-events: none; }
.fm-hint {
    position: absolute;
    z-index: 60;
    min-width: 13.75rem;
    max-width: 18.75rem;
    background: var(--bg-elevated, var(--bg-surface));
    border: 0.0625rem solid var(--accent);
    border-radius: 0.1875rem;
    box-shadow: 0 0.75rem 1.75rem rgba(0,0,0,0.5);
    font-family: var(--font-mono);
    pointer-events: auto;
}
.fm-hint-arrow {
    position: absolute;
    width: 0.5rem;
    height: 0.5rem;
    background: var(--bg-elevated, var(--bg-surface));
    border-top: 0.0625rem solid var(--accent);
    border-left: 0.0625rem solid var(--accent);
    transform: rotate(45deg);
}
.fm-hint--bottom .fm-hint-arrow { top: -0.3125rem; left: calc(50% - 0.25rem); }
.fm-hint--top    .fm-hint-arrow { bottom: -0.3125rem; left: calc(50% - 0.25rem); transform: rotate(225deg); }
.fm-hint--right  .fm-hint-arrow { left: -0.3125rem; top: calc(50% - 0.25rem); transform: rotate(315deg); }
.fm-hint--left   .fm-hint-arrow { right: -0.3125rem; top: calc(50% - 0.25rem); transform: rotate(135deg); }
.fm-hint-body { padding: 0.75rem 0.875rem; }
.fm-hint-title {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--accent);
    margin-bottom: 0.25rem;
}
.fm-hint-text {
    font-size: 0.7812rem;
    color: var(--text-primary);
    line-height: 1.45;
    font-family: var(--font-sans);
}
.fm-hint-actions { margin-top: 0.625rem; display: flex; justify-content: flex-end; }
.fm-hint-ok {
    background: var(--accent);
    border: 0;
    color: var(--bg-base);
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    padding: 0.375rem 0.75rem;
    cursor: pointer;
    border-radius: 0.125rem;
}
.fm-hint-ok:hover { background: var(--primary-dim); }

/* #139 */
.fm-sitebar {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--bg-elevated, var(--bg-surface));
    border-bottom: 0.0625rem solid var(--border);
    min-height: 2.5rem;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.fm-sitebar-inner {
    width: min(100%, 90rem);
    margin: 0 auto;
    /* #140 */
    padding: 0 var(--space-sm);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    min-height: 2.5rem;
}
@media (min-width: 40em) {
    .fm-sitebar-inner { padding: 0 var(--space-lg); gap: var(--space-md); }
}
.fm-sitebar-switch { position: relative; flex-shrink: 0; }
.fm-sitebar-current {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: transparent;
    border: 0.0625rem solid var(--border);
    color: var(--text-primary);
    padding: 0.25rem 0.625rem;
    font: inherit;
    cursor: pointer;
    min-height: 1.75rem;
}
.fm-sitebar-current:hover { border-color: var(--accent); }
.fm-sitebar-badge { color: var(--accent); font-size: 0.875rem; line-height: 1; }
.fm-sitebar-name { font-weight: 500; }
.fm-sitebar-menu {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 0;
    min-width: 16.25rem;
    background: var(--surface-1, var(--bg-elevated));
    border: 0.0625rem solid var(--border);
    box-shadow: 0 0.5rem 1.5rem rgba(0,0,0,0.4);
    z-index: 100;
    padding: 0.25rem;
}
.fm-sitebar-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.625rem;
    color: var(--text-primary);
    text-decoration: none;
    min-height: 2.25rem;
    font: inherit;
}
.fm-sitebar-item:hover { background: var(--surface-2, rgba(255,255,255,0.04)); }
.fm-sitebar-item.is-current { color: var(--accent); }
.fm-sitebar-item-name { flex: 1; }
.fm-sitebar-item-tick { color: var(--accent); }

.fm-sitebar-stats {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    gap: var(--space-md);
    align-items: center;
    flex-wrap: wrap;
}
.fm-sitebar-stat {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    color: var(--text-muted);
}
.fm-sitebar-stat-icon {
    width: 0.875rem;
    height: 0.875rem;
    flex-shrink: 0;
    opacity: 0.75;
}
.fm-sitebar-stat.is-alert .fm-sitebar-stat-icon { opacity: 1; }
.fm-sitebar-stat.is-alert { color: var(--secondary); }
.fm-sitebar-stat-val {
    font-size: 0.8125rem;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}
.fm-sitebar-stat.is-alert .fm-sitebar-stat-val { color: var(--secondary); }
/* #141 */
.fm-sitebar-stat-lbl { font-size: var(--micro-size); display: none; }

@media (min-width: 40em) {
    .fm-sitebar-stat-lbl { display: inline; }
}

/* #142 */
.fm-acc { position: relative; display: inline-flex; align-items: center; }
.fm-acc-menu {
    position: absolute;
    top: calc(100% + 0.25rem);
    left: 0;
    min-width: 15rem;
    background: var(--surface-1, #161618);
    border: 0.0625rem solid var(--border);
    box-shadow: 0 0.5rem 1.5rem rgba(0,0,0,0.4);
    z-index: 100;
    padding: 0.25rem;
    text-align: left;
}
/* #143 */
.fm-acc-avatar { flex-shrink: 0; }
/* #144 — active account row doubles as the profile link (no self-switch no-op) */
.fm-acc-item-go { margin-left: auto; color: var(--text-muted); flex-shrink: 0; }
a.fm-acc-item:hover .fm-acc-item-go { color: var(--accent); }
/* #145 */
.role-indicator .role-avatar {
    width: 2rem;
    height: 2rem;
    border-width: 0;
    object-fit: cover;
}
/* #146 */
.role-indicator:has(> .role-avatar) > svg { display: none; }

/* #147 */
.btn.btn-icon {
    width: 2.75rem;
    height: 2.75rem;
    min-height: 2.75rem;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    list-style: none;
    cursor: pointer;
}
/* #148 */
summary.btn {
    display: list-item;
    list-style: none;
    text-align: center;
    line-height: 1.2;
    /* #149 */
    cursor: pointer;
}
/* Диктовка. Кнопка сидить у правому краю самого поля — окрема кнопка збоку
   з'їдала б ширину композера на телефоні, а вводу тут і так мало місця. */
.fm-voice-wrap { position: relative; display: block; flex: 1 1 auto; min-width: 0; }
.fm-voice {
    position: absolute;
    right: 0.375rem;
    bottom: 0.375rem;
    width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease;
}
.fm-voice svg { width: 1.125rem; height: 1.125rem; }
.fm-voice:hover { color: var(--text-primary); }
/* Кнопка не должна ловить рамку-квадрат от общего стиля button и не должна
   стоять на уголке-ресайзере поля — Артьом прислал скрин со столкновением. */
.fm-voice:focus { outline: none; }
.fm-voice:focus-visible { outline: 0.125rem solid var(--primary); outline-offset: 0.125rem; }
.fm-voice-wrap > textarea { resize: none; }
/* Запис — щільна заливка акцентом, стан видно навіть краєм ока. */
.fm-voice--rec { background: var(--primary); color: var(--bg-base); }
.fm-voice--rec::after {
    content: "";
    position: absolute;
    inset: 0;
    border: 0.125rem solid var(--primary);
    animation: fm-voice-pulse 1.2s ease-out infinite;
}
.fm-voice--wait { color: var(--text-muted); cursor: progress; }
@keyframes fm-voice-pulse {
    from { transform: scale(1); opacity: 0.7; }
    to   { transform: scale(1.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .fm-voice--rec::after { animation: none; opacity: 0.5; }
}
/* Поле поруч із мікрофоном не має заповзати під нього. */
.fm-voice-wrap > textarea,
.fm-voice-wrap > input { width: 100%; padding-right: 2.75rem; }

/* Форма завантаження документа. Кнопка-розкривач була смугою на всю
   ширину екрана (на десктопі — помаранчевий банер), хоча це звичайна дія. */
.doc-upload { margin-bottom: var(--space-md); }
summary.doc-upload__toggle {
    display: inline-block;
    width: auto;
    min-width: 14rem;
    max-width: 100%;
}

summary.btn-icon {
    width: 2.75rem;
    height: 2.75rem;
    min-height: 2.75rem;
    padding: 0;
    display: list-item;
    text-align: center;
    line-height: 2.75rem;
    box-sizing: border-box;
    list-style: none;
    cursor: pointer;
}
.btn.btn-icon svg,
summary.btn-icon svg {
    width: 1.25rem;
    height: 1.25rem;
    vertical-align: middle;
    /* #150 */
    pointer-events: none;
}
/* #151 */
summary.btn-icon::-webkit-details-marker { display: none; }
summary.btn-icon::marker { content: ""; }

/* #152 */
.user-cell {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}
.user-cell-text {
    display: inline-flex;
    flex-direction: column;
    gap: 0.0625rem;
    min-width: 0;
}
.fm-acc-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    background: transparent;
    border: none;
    color: var(--text-primary);
    padding: 0.5rem 0.625rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-align: left;
    cursor: pointer;
    min-height: 2.25rem;
    text-decoration: none;
}
.fm-acc-item:hover { background: var(--surface-2, #1e1e21); }
.fm-acc-item.is-active { color: var(--accent); }
.fm-acc-item-role {
    font-size: var(--micro-size);
    color: var(--text-muted);
    padding: 0.125rem 0.25rem;
    border: 0.0625rem solid var(--border);
    text-transform: uppercase;
    letter-spacing: .08em;
}
.fm-acc-item-name { flex: 1; }
.fm-acc-item-tick { color: var(--accent); }
.fm-acc-add, .fm-acc-logout {
    border-top: 0.0625rem solid var(--border);
    margin-top: 0.25rem;
    color: var(--text-muted);
}
.fm-acc-add:hover { color: var(--accent); }

.logo {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.logo img {
    width: 2.75rem;
    height: 2.75rem;
    /* #153 */
    filter: invert(var(--logo-invert, 0));
    flex-shrink: 0;
}

.logo svg { color: var(--primary); flex-shrink: 0; }

.nav {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    order: 10;
}

.nav-link {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: rgba(255,255,255,0.7) !important;
    text-decoration: none;
    padding: var(--space-xs);
    min-height: 2.75rem;
    display: inline-flex;
    align-items: center;
    transition: color 0.15s;
    white-space: nowrap;
}

.nav-link::before { content: none; }
.nav-link .icon { opacity: 0.6; margin-right: 0.4em; transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out); }
.nav-sep { width: 0.0625rem; height: 1rem; background: rgba(255,255,255,0.15); flex-shrink: 0; }
@media (hover: hover) {
    .nav-link:hover { color: #fff !important; }
    .nav-link:hover .icon { opacity: 1; transform: translateX(0.125rem); }
    .nav-link.nav--settings:hover .icon { animation: spin 1.5s linear infinite; transform: none; }
}
.nav-link.active { color: var(--primary) !important; }
.nav-link.active .icon { opacity: 1; }

/* #154 */

.lang-switch {
    display: inline-flex;
    gap: 0.125rem;
}

.lang-btn {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-weight: 600;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    text-decoration: none;
    transition: color 0.15s;
}

@media (hover: hover) {
    .lang-btn:hover { color: var(--text-primary); }
}

.lang-btn.active {
    color: var(--text-secondary);
    border-bottom: 0.09375rem solid var(--primary);
}

/* #155 */

.checklist-app {
    background: var(--tg-bg, var(--bg-base));
    color: var(--tg-text, var(--text-primary));
    min-height: 100vh;
    /* #156 */
    padding: var(--space-sm);
}
@media (min-width: 48em) {
    .checklist-app { padding: var(--space-md); }
}

.step { display: none; }
.step.active { display: block; }

.step-title {
    font-family: var(--font-mono);
    font-size: 1rem;
    font-weight: 700;
    margin-bottom: var(--space-lg);
    text-align: center;
}

.site-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.site-btn {
    display: block;
    width: 100%;
    padding: var(--space-md) var(--space-lg);
    font-family: var(--font-mono);
    font-size: 1rem;
    font-weight: 600;
    background: var(--bg-surface);
    border: 0.09375rem solid var(--border);
    color: var(--tg-text, var(--text-primary));
    cursor: pointer;
    text-align: left;
    min-height: 3rem;
}

.site-btn:active { border-color: var(--primary); }

/* #157 */

.wizard-header {
    margin-bottom: var(--space-xl);
}

.wizard-counter {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--tg-hint, var(--text-secondary));
    text-align: right;
}

.wizard-category {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--primary);
    margin-bottom: var(--space-sm);
    min-height: 1.125rem;
}

.wizard-question {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.4;
    /* #158 */
    margin-bottom: var(--space-lg);
    min-height: 3rem;
}
@media (min-width: 48em) {
    .wizard-question { margin-bottom: var(--space-xl); min-height: 3.75rem; }
}

.wizard-actions {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    /* #159 */
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
}
@media (min-width: 48em) {
    .wizard-actions { gap: var(--space-sm); }
}

.wizard-btn {
    /* #160 */
    padding: var(--space-sm) var(--space-xs);
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 700;
    border: 0;
    cursor: pointer;
    min-height: 3rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    user-select: none;
}
@media (min-width: 48em) {
    .wizard-btn { padding: var(--space-md); font-size: 1rem; }
}

/* YES = «прошёл» → success-зелёный; NO = hazard-оранжевый (--secondary).
   Було YES=primary + NO=secondary — два оранжевих, семантика губилась. */
.wizard-btn-yes {
    background: var(--success);
    color: #fff;
}

.wizard-btn-no {
    background: var(--secondary);
    color: #fff;
}

/* "Not applicable" is the quiet third option — a bare label, so it never
   competes with the two real answers. */
.wizard-btn-na {
    background: transparent;
    color: var(--text-secondary);
}

.wizard-btn:active { opacity: 0.8; }
.wizard-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    filter: grayscale(0.5);
}

/* #161 */
.wizard-req {
    color: var(--secondary);
    margin-right: 0.25rem;
    font-weight: 700;
}

/* #162 */
.wizard-photo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    min-height: 3rem;
    padding: var(--space-md);
    margin-bottom: var(--space-md);
    border: 0.0625rem dashed var(--border);
    background: var(--bg-surface);
    color: var(--text-secondary);
    font-size: 0.875rem;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.wizard-photo:hover { border-color: var(--primary); color: var(--text-primary); }
.wizard-photo[data-required="1"] { border-color: var(--secondary); color: var(--secondary); }
.wizard-photo.is-uploading { opacity: 0.6; pointer-events: none; }
.wizard-photo.is-done {
    border-style: solid;
    border-color: var(--success);
    color: var(--success);
    background: color-mix(in srgb, var(--success) 8%, transparent);
}
.wizard-photo.is-error {
    border-color: var(--secondary);
    color: var(--secondary);
    background: color-mix(in srgb, var(--secondary) 8%, transparent);
}
.wizard-photo-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
}
.wizard-photo-thumb {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.wizard-photo-thumb .icon { width: 1.25rem; height: 1.25rem; }
/* #163 */
.wizard-btn kbd {
    display: none;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-weight: 400;
    padding: 0.0625rem 0.3125rem;
    margin-left: 0.375rem;
    border: 0.0625rem solid rgba(255,255,255,0.3);
    opacity: 0.6;
    vertical-align: middle;
}
@media (hover: hover) and (pointer: fine) {
    .wizard-btn kbd { display: inline-block; }
}
.wizard-btn-na kbd { border-color: var(--border); }

.wizard-note-row {
    margin-top: var(--space-sm);
}

.wizard-note {
    width: 100%;
    padding: var(--space-sm) var(--space-md);
    font-family: var(--font-sans);
    /* #164 */
    font-size: 1rem;
    border: 0.09375rem solid var(--border);
    background: var(--bg-surface);
    color: var(--tg-text, var(--text-primary));
}
@media (min-width: 48em) {
    .wizard-note { font-size: 0.875rem; }
}

.wizard-note:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 0.1875rem var(--focus-ring);
}

/* #165 */

.done-icon {
    font-family: var(--font-mono);
    font-size: 3rem;
    font-weight: 700;
    color: var(--primary);
    text-align: center;
    margin: var(--space-xl) 0 var(--space-md);
}

.done-stats {
    display: flex;
    justify-content: center;
    /* #166 */
    gap: var(--space-lg);
    margin-top: var(--space-lg);
}
@media (min-width: 48em) {
    .done-stats { gap: var(--space-xl); }
}

.done-stat {
    text-align: center;
}

.done-val {
    display: block;
    font-family: var(--font-mono);
    /* #167 */
    font-size: 1.75rem;
    font-weight: 700;
}
@media (min-width: 48em) {
    .done-val { font-size: 2rem; }
}

.done-yes { color: var(--success); }
.done-no { color: var(--secondary); }

.done-lbl {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--tg-hint, var(--text-secondary));
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-top: var(--space-xs);
}

/* #168 */

.role-assign {
    display: inline-flex;
    gap: 0.25rem;
    align-items: center;
}

.role-assign select {
    appearance: none;
    -webkit-appearance: none;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 0.25rem var(--space-sm);
    padding-right: 1.25rem;
    background: var(--bg-surface);
    border: 0.09375rem solid var(--border);
    color: var(--text-primary);
    cursor: pointer;
    min-height: 1.75rem;
    background-image: url("data:image/svg+xml,%3Csvg width='8' height='5' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%2378716c'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.375rem center;
    transition: border-color 0.15s ease;
}

.role-assign select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 0.1875rem var(--focus-ring);
}

@media (hover: hover) {
    .role-assign select:hover { border-color: var(--text-muted); }
}

@media (pointer: coarse) {
    .role-assign select { min-height: 2.5rem; font-size: 0.75rem; }
    .form-check input[type="checkbox"] { width: 1.375rem; height: 1.375rem; }
    .toggle input { width: 2.75rem; height: 1.5rem; }
    .toggle input::after { width: 1rem; height: 1rem; }
    .toggle input:checked::after { transform: translateX(1.25rem); }
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-md);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    /* Two kinds of button, no third: a SOLID BLOCK for the main action, a BARE
       LABEL for everything else. The outlined middle state is what made the UI
       look cheap, and an outlined box beside the phone's rounded screen corner
       always reads as chipped. Variants below set a background or a colour —
       none of them bring back a border. */
    border: 0;
    cursor: pointer;
    min-height: 2.75rem; /* #169 */
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    /* Bare `.btn` <button>s inherited the UA push-button look on iOS
       (solid blue fill, unreadable text — Alex 17.07). Kill the UA
       appearance and give the base class an explicit surface. */
    appearance: none;
    -webkit-appearance: none;
    background: var(--bg-surface);
    color: var(--text-primary);
    border-color: var(--border);
}

/* Solid block — the one main action on a screen. */
.btn-primary {
    background: var(--primary);
    color: #fff;
}

/* Bare label. Sat on a surface fill with a border before; next to a filled
   primary it now reads as clearly secondary without drawing a box. */
.btn-secondary {
    background: transparent;
    color: var(--text-primary);
}
.btn-secondary:hover { background: color-mix(in srgb, var(--text-primary) 8%, transparent); }

/* Деструктив: палітра свідомо без червоного («construction = orange»), тож
   суцільний оранж робив «Видалити» схожим на primary-CTA. Лишається підпис
   кольором hazard, заливка тільки на hover. */
.btn-danger {
    background: transparent;
    color: var(--secondary);
}
.btn-danger:hover {
    background: var(--secondary);
    color: #fff;
}

/* Review verdicts on the task page — colour in the label, palette-native. */
.btn-accept { color: var(--success); }
.btn-reject { color: var(--secondary); }
.btn-accept:hover { background: color-mix(in srgb, var(--success) 14%, transparent); }
.btn-reject:hover { background: color-mix(in srgb, var(--secondary) 14%, transparent); }

/* Upload preview chip + its remove cross (client ask: wrong file must be
   removable before submitting the form). */
.up-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    padding: 0.25rem 0.25rem 0.25rem 0.5rem;
    border: 1px solid var(--border);
    margin: 0.125rem;
    max-width: 100%;
    overflow-wrap: anywhere;
}
.up-chip-x {
    appearance: none;
    -webkit-appearance: none;
    border: 0;
    background: none;
    color: var(--secondary);
    font-size: 0.8125rem;
    line-height: 1;
    padding: 0.375rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* Chat media payloads: TG voice notes / videos / documents (Alex 17.07). */
.chat-msg-audio { display: block; width: 100%; max-width: 18rem; height: 2.25rem; }
/* Голосовое в личке — тот же плеер, что в чате объекта. */
.ac-audio { display: block; width: 100%; max-width: 16rem; height: 2.25rem; }
.chat-msg-video { display: block; max-width: 100%; max-height: 25rem; border: 1px solid var(--border); }
.chat-msg-doc,
.chat-msg-dl {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    text-decoration: underline;
    margin-top: 0.25rem;
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn:active:not(:disabled) { transform: scale(0.96); transition-duration: var(--dur-fast); }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 0.1875rem var(--focus-ring); }

/* #170 */
.btn[aria-busy="true"] { opacity: 0.7; pointer-events: none; }
/* #171 */
@media (hover: hover) {
    .btn-primary:hover { background: var(--primary-dim); border-color: var(--primary-dim); }
    .btn-secondary:hover { background: var(--bg-elevated); }
}

/* #172 */

.upload-zone {
    border: 0.125rem dashed var(--border);
    padding: var(--space-xl);
    text-align: center;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-muted);
    transition: border-color 0.15s;
}

.upload-zone.dragover { border-color: var(--primary); color: var(--primary); }
@media (hover: hover) { .upload-zone:hover { border-color: var(--primary); color: var(--primary); } }

.upload-zone input[type="file"] { display: none; }

.upload-preview {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-top: var(--space-md);
}

/* #173 */

/* #174 */
/* #175 */
.chip-island {
    display: flex;
    gap: 0.25rem;
    padding: 0.25rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg-elevated) 92%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 0.0625rem solid var(--border);
    box-shadow: 0 0.25rem 1rem rgba(0,0,0,0.35);
    position: fixed;
    left: 50%;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
    transform: translateX(-50%);
    z-index: 40;
    max-width: calc(100% - 1.5rem);
    overflow-x: auto;
    scrollbar-width: none;
}
.chip-island::-webkit-scrollbar { display: none; }
.chip-island-btn {
    appearance: none;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    padding: 0.5rem 1rem;
    min-height: var(--tap-target);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    border: 0;
    /* Пилюля запрещена (DESIGN.md, раздел 8, пункт 3). */
    border-radius: 0;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.chip-island-btn:hover { color: var(--text-primary); }
.chip-island-btn[data-active="true"] {
    background: var(--primary);
    color: var(--bg-base);
}
/* #176 */
@media (min-width: 48em) {
    .chip-island {
        position: static;
        transform: none;
        left: auto;
        bottom: auto;
        max-width: none;
        box-shadow: none;
        backdrop-filter: none;
        margin-bottom: var(--space-md);
        padding: 0;
        background: transparent;
        border: 0;
    }
    .chip-island-btn {
        border: 0.0625rem solid var(--border);
        background: var(--bg-surface);
    }
}
/* #177 */
@media (max-width: 47.99em) {
    /* Отступ под нижнюю панель фильтров + таб-бар. */
    .photo-grid { padding-bottom: 2rem; }
}

.chip-scroll {
    display: flex;
    gap: 0.375rem;
    align-items: center;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    padding-bottom: var(--space-sm);
    margin-bottom: var(--space-md);
    scrollbar-width: none;
}
.chip-scroll::-webkit-scrollbar { display: none; }

.chip {
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    min-height: var(--tap-target);
    padding: 0.375rem 0.75rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border: 0.0625rem solid var(--border);
    background: var(--bg-surface);
    color: var(--text-secondary);
    cursor: pointer;
    scroll-snap-align: start;
    transition: all var(--dur-fast) var(--ease-out);
    -webkit-tap-highlight-color: transparent;
}
.chip:hover { border-color: var(--text-muted); color: var(--text-primary); }
.chip[data-active="true"], .chip.active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.chip-select, .chip-date {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    padding: 0.375rem 0.5rem;
    min-height: var(--tap-target);
    border: 0.0625rem solid var(--border);
    background: var(--bg-surface);
    color: var(--text-primary);
    appearance: none;
    -webkit-appearance: none;
    white-space: nowrap;
    scroll-snap-align: start;
    flex-shrink: 0;
}
.chip-select {
    padding-right: 1.25rem;
    background-image: url("data:image/svg+xml,%3Csvg width='8' height='5' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%2378716c'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.375rem center;
}
/* `input.` не просто `.chip-date`: голый класс (0,1,0) проигрывает
   `input[type="date"]{width:100%}` (0,1,1) из primitives — поле распирало
   на всю строку и второй датчик уезжал за экран (скрин Артьома 12.08). */
input.chip-date { width: 8.5rem; flex: 0 0 auto; }
.chip-select:focus-visible, .chip-date:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 0.1875rem var(--focus-ring); }

/* #178 */
.chip-admin { border-color: var(--primary); color: var(--primary); background: transparent; }
.chip-inspector { border-color: var(--success); color: var(--success); background: transparent; }
.chip-foreman { border-color: var(--text-secondary); color: var(--text-primary); background: transparent; }
.chip-worker { border-color: var(--border); color: var(--text-secondary); background: transparent; }
.chip .site-label { font-weight: 400; opacity: .6; text-transform: none; letter-spacing: 0; margin-left: 0.25rem; }

/* #179 */
.row-list {
    display: flex;
    flex-direction: column;
}

.row-item {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) 0;
    border-bottom: 0.0625rem solid var(--border);
    text-decoration: none;
    color: inherit;
    transition: padding-left var(--dur-fast) var(--ease-out);
}

@media (hover: hover) {
    .row-item:hover {
        padding-left: var(--space-sm);
        background: linear-gradient(90deg, var(--bg-elevated) 0%, transparent 100%);
    }
}

.row-idx {
    font-family: var(--font-mono);
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--text-muted);
    min-width: 2.5rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
    transition: color var(--dur-fast) var(--ease-out);
}
.row-item:hover .row-idx { color: var(--primary); }

.row-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.row-title {
    font-weight: 600;
    font-size: 0.875rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.row-meta {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
    letter-spacing: 0.05em;
}

.row-end {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-shrink: 0;
}

/* #180 */
.btn-inline {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-weight: 700;
    padding: 0.25rem 0.5rem;
    border: 0;
    background: transparent;
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    transition: all var(--dur-fast) var(--ease-out);
}
.btn-inline--ok { color: var(--success); }
.btn-inline--ok:hover { background: var(--success); color: #fff; }

/* #181 — аккордеон групп удалён вместе с <details>-раскладкой галереи:
   заголовок дня рисует .rl-day, тот же примитив, что и в журнале отчётов. */

/* #182 */
.gal-day { margin-bottom: var(--space-lg); }
.gal-day .rl-day { margin-top: 0; }

.gallery-grid {
    display: grid;
    /* 6.5rem даёт три колонки уже на 390px: галерея должна показывать стену
       снимков, а не два крупных прев'ю в ряд. */
    grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
    gap: 0.1875rem;
}

.gallery-item {
    position: relative;
    overflow: hidden;
    background: var(--bg-surface);
    cursor: pointer;
    aspect-ratio: 1;
}
.gallery-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--dur-normal) var(--ease-out);
}
@media (hover: hover) {
    .gallery-item:hover img {
        transform: scale(1.05);
    }
    .gallery-item:hover .gallery-overlay {
        opacity: 1;
    }
}

/* #183 */
.gallery-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(transparent 50%, rgba(0,0,0,0.7));
    display: flex;
    align-items: flex-end;
    padding: var(--space-xs);
    /* На телефоне наведения нет, и подпись «кто / объект» не показывалась
       никогда: снимок висел без привязки к работе. Прячем её только там,
       где курсор действительно есть. */
    opacity: 1;
    transition: opacity var(--dur-fast) var(--ease-out);
    pointer-events: none;
}
@media (hover: hover) {
    .gallery-overlay { opacity: 0; }
}
.gallery-overlay span {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    line-height: 1.25;
    color: #fff;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* #184 */
.gallery-item--file {
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0.0625rem solid var(--border);
}
.gallery-item--file .gallery-overlay { background: none; align-items: center; justify-content: center; }
.gallery-item--file .gallery-overlay span { color: var(--text-secondary); }

/* #185 */
.audit-day { margin-bottom: var(--space-lg); }
.audit-date {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--text-muted);
    padding-bottom: var(--space-xs);
    border-bottom: 0.0625rem solid var(--border);
    margin-bottom: var(--space-xs);
}
.audit-entries { display: flex; flex-direction: column; }
.audit-entry {
    display: flex;
    gap: var(--space-sm);
    align-items: baseline;
    padding: 0.25rem 0;
    font-size: 0.8125rem;
    border-bottom: 0.0625rem solid rgba(255,255,255,0.03);
}
.audit-time {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
    min-width: 3.5rem;
    flex-shrink: 0;
}
.audit-event {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--primary);
    min-width: 8rem;
    flex-shrink: 0;
}
.audit-actor { color: var(--text-secondary); flex-shrink: 0; }
.audit-detail { color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.photo-grid {
    display: grid;
    /* #186 */
    grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
    gap: var(--space-sm);
}
@media (min-width: 48em) {
    .photo-grid { grid-template-columns: repeat(auto-fill, minmax(12.5rem, 1fr)); }
}

.photo-card {
    position: relative;
    overflow: hidden;
    border: 0.09375rem solid var(--border);
    cursor: pointer;
}

.photo-card img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
}

.photo-caption {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-secondary);
    padding: var(--space-xs) var(--space-sm);
    background: var(--bg-elevated);
    border-top: 0.0625rem solid var(--border);
    letter-spacing: 0.02em;
    line-height: 1.4;
}

.photo-meta {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-secondary);
    padding: var(--space-xs) var(--space-sm);
    background: var(--bg-surface);
}

/* #187 */
.video-card video {
    width: 100%;
    display: block;
    background: #000;
}

/* #188 */
.comment-thread {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.comment {
    padding: var(--space-sm) var(--space-md);
    background: var(--bg-surface);
    border: 0.09375rem solid var(--border);
    /* Type stripe on the block-start edge (not inline-start — house style bans
       a coloured left accent). Colour set per response type below. */
    border-top: 0.1875rem solid var(--comment-accent, var(--border));
}
/* Response-type meaning, at a glance. fix=submitted, review=accepted,
   reject=rework, comment=neutral. Tints the top stripe + a faint fill. */
.response-fix     { --comment-accent: var(--accent); }
.response-review  { --comment-accent: var(--success); }
.response-reject  { --comment-accent: var(--secondary); }
.response-comment { --comment-accent: var(--border); }
.response-fix, .response-review, .response-reject {
    background: color-mix(in srgb, var(--comment-accent) 6%, var(--bg-surface));
}

/* Threaded replies (client 21.07: «ветки»): one level of indent + an elbow
   connector drawn in the gutter so the eye links child → parent. Neutral
   hairline, sharp corners (house style), structural not a status accent. */
.comment-reply {
    margin-inline-start: 1.5rem;
    position: relative;
}
.comment-reply::before {
    content: "";
    position: absolute;
    inset-inline-start: -0.85rem;
    top: -0.35rem;
    width: 0.6rem;
    height: 1.15rem;
    border-inline-start: 0.09375rem solid var(--border);
    border-block-end: 0.09375rem solid var(--border);
    pointer-events: none;
}

.comment-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 0.25rem;
}

/* #189 */
.comment-user {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--primary);
    text-decoration: none;
}
.comment-user:hover { text-decoration: underline; }

.comment-date {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
}

.comment-text {
    font-size: 0.75rem;
    color: var(--text-primary);
    line-height: 1.5;
}

/* Photos attached to a response (client 21.07: «фото у відповіді»). */
.comment-media {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    margin-top: 0.5rem;
}
.comment-thumb {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: cover;
    border: 0.0625rem solid var(--border);
    display: block;
}
/* "↳ @parent" reference line above a threaded reply (indent + connector live
   next to the `.comment` rule above). */
.comment-parent {
    display: block;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
    margin-bottom: 0.25rem;
    text-decoration: none;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.comment-parent:hover { color: var(--primary); }
/* Flash the message you jumped to from a "↳ reply" reference. */
.comment:target { outline: 0.125rem solid var(--primary); outline-offset: 0.125rem; }
/* "Replying to @name" chip above the textarea, with a cancel link. */
.reply-context {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.375rem;
    padding: 0.35rem 0.5rem;
    background: var(--bg-surface);
    border: 0.0625rem solid var(--border);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    color: var(--text-muted);
}
/* `display:flex` above (author style) beat the `hidden` attribute (UA
   [hidden]{display:none}), so the reply-quote chip + its ✕ showed on EVERY
   task, not just while replying. Higher-specificity [hidden] rule restores it. */
.reply-context[hidden] { display: none; }
.reply-context .tk-reply-chip-txt {
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Bare icon button — kill the default <button> chrome (gray bevel) that made
   the ✕ look unstyled. */
.reply-cancel {
    flex: none; -webkit-appearance: none; appearance: none;
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.25rem; height: 1.25rem; padding: 0;
    background: none; border: none; cursor: pointer;
    color: var(--text-muted); font-size: 0.9rem; font-weight: 700; line-height: 1;
}
.reply-cancel:hover, .reply-cancel:focus-visible { color: var(--primary); outline: none; }

/* Add-photo affordance in the respond form. */
.resp-photo {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    margin-top: 0.5rem;
    padding: 0.375rem 0.625rem;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    border: 0.0625rem dashed var(--border);
    cursor: pointer;
    user-select: none;
}
.resp-photo:hover { color: var(--accent); border-color: var(--accent); }
.resp-photo.has-files { color: var(--accent); border-color: var(--accent); border-style: solid; }

/* #190 */
.lightbox {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.9);
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.lightbox[hidden] { display: none; }

.lightbox img {
    max-width: 90vw;
    max-height: 90vh;
    object-fit: contain;
}

/* #191 */

.inline-form {
    display: none;
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 0.0625rem solid var(--border);
}

.inline-form.active { display: block; }
details[open] > .inline-form { display: block; }

.site-card .btn { margin-top: var(--space-sm); font-size: 0.75rem; padding: var(--space-sm) var(--space-md); min-height: 2.75rem; }

/* #192 */

/* #193 */
.toast {
    position: fixed;
    bottom: var(--space-xl);
    left: 50%;
    transform: translateX(-50%);
    background: var(--bg-surface);
    color: var(--text-primary);
    border: 0.0625rem solid var(--border);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    padding: var(--space-sm) var(--space-lg);
    z-index: 300;
    animation: toast-in var(--dur-normal) var(--ease-out);
    min-height: 2.75rem;
    display: none;
    align-items: center;
    max-width: 90vw;
    overflow: hidden;
}
.toast::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    height: 0.125rem;
    background: var(--primary);
    animation: toast-timer 4s linear forwards;
}

.toast.toast-error { border-color: var(--secondary); }
.toast.toast-error::after { background: var(--secondary); }
.toast.toast-success::after { background: var(--success); }

.toast[style*="display: block"] { display: flex; }
/* #194 */

/* #195 — Group Chat */
.group-chat-page {
    max-width: 56rem;
    margin: 0 auto;
}

.group-chat-header {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}

.chat-selector {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
}

.chat-selector-label {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.chat-select {
    appearance: none;
    -webkit-appearance: none;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    padding: 0.25rem 1.5rem 0.25rem 0.5rem;
    background: var(--bg-surface);
    border: 0.0625rem solid var(--border);
    color: var(--text-primary);
    cursor: pointer;
    min-height: 1.75rem;
    background-image: url("data:image/svg+xml,%3Csvg width='8' height='5' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%2378716c'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.375rem center;
}

.chat-select:focus { outline: none; border-color: var(--primary); }

/* #196 */
.chat-meta {
    display: flex;
    gap: var(--space-md);
    margin-bottom: var(--space-sm);
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.chat-messages {
    display: flex;
    flex-direction: column;
    gap: 0;
    border: 0.0625rem solid var(--border);
    background: var(--bg-surface);
    max-height: 75vh;
    overflow-y: auto;
}

/* #197 */
.chat-msg {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    padding: var(--space-sm) var(--space-md);
    border-bottom: 0.0625rem solid var(--border);
    transition: background 0.15s ease;
}

.chat-msg:last-child { border-bottom: 0; }
.chat-msg:hover { background: var(--bg-elevated); }

.chat-msg-meta {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

.chat-msg-author {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--primary);
}

.chat-msg-time {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--text-muted);
}

.chat-msg-kind {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    padding: 0.0625rem 0.25rem;
    border: 0.0625rem solid var(--border);
}

.chat-msg-body {
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--text-primary);
    word-break: break-word;
}

.chat-msg-text { white-space: pre-wrap; }

.chat-msg-photo { margin-top: var(--space-xs); }

/* Internal vs Telegram in the merged feed — differentiated by author accent
   + a whisper-faint fill, no border bars. */
.chat-msg--fm { background: color-mix(in srgb, var(--primary) 5%, transparent); }
.chat-msg--fm .chat-msg-author { color: var(--primary); }
.chat-msg--tg .chat-msg-author { color: var(--text-secondary); }

/* Compose bar — sticky at the bottom of the chat view */
.chat-reply {
    position: sticky;
    bottom: 0;
    margin-top: var(--space-sm);
    padding-top: var(--space-xs);
    /* Keep the composer clear of the iPhone home indicator (full-screen chat). */
    padding-bottom: max(var(--space-xs), env(safe-area-inset-bottom));
    background: var(--bg-base);
}
.chat-reply-row {
    display: flex;
    gap: var(--space-xs);
    align-items: center;
}
.chat-reply-input {
    flex: 1 1 auto;
    min-height: 2.5rem;
    padding: 0.5rem 0.75rem;
    /* iOS zooms the page when a focused input is < 16px — kills the send button
       off the right edge. Hard 16px so tapping the field never zooms. */
    font-size: 16px;
    color: var(--text-primary);
    background: var(--bg-surface);
    border: 0.0625rem solid var(--border);
    border-radius: var(--radius);
}
.chat-reply-input:focus { outline: none; border-color: var(--primary); }
.chat-reply-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-height: 2.5rem;
    padding: 0 0.875rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #fff;
    background: var(--primary);
    border: 0;
    border-radius: var(--radius);
    cursor: pointer;
    white-space: nowrap;
}
.chat-reply-btn:hover { filter: brightness(1.08); }
.chat-reply-status { min-height: 1.1em; margin-top: 0.25rem; font-family: var(--font-mono); font-size: var(--micro-size); }
.chat-reply-ok { color: var(--primary); }
.chat-reply-err { color: var(--secondary); }

/* ── AI assistant chat (.ac-*) ──────────────────────────────────────
   Grouped bubbles, sender caption once per run, sharp corners (brand),
   tonal fill instead of a hard border on every message (kills the
   nested-box AI tell). Thread scrolls; compose pinned above the tab bar. */
.ac-chat {
    display: flex; flex-direction: column;
    height: calc(100dvh - var(--fm-header-h, 3.75rem) - var(--fm-bottombar-h, 3.5rem));
    min-height: 0;
}
/* Chat owns the whole viewport between header and tab bar — drop the page
   gutter + header gap that would otherwise push the compose under the bar. */
body:has(.ac-chat) .main { padding: 0; }
body:has(.ac-chat) .header { margin-bottom: 0; }
/* The one-time Face-ID install banner is fixed at bottom:0 and would sit ON
   the compose — the chat's primary control must never be covered. Suppress it
   on the chat page; it still prompts on every other screen. */
body:has(.ac-chat) .fm-install { display: none; }
.ac-thread {
    flex: 1; min-height: 0; overflow-y: auto;
    display: flex; flex-direction: column; gap: 0.12rem;
    padding: var(--space-md) var(--fm-gutter);
}
.ac-row { display: flex; flex-direction: column; align-items: flex-start; max-width: 100%; }
.ac-row--me { align-items: flex-end; }
.ac-row--head { margin-top: 0.75rem; }
.ac-row:first-child { margin-top: 0; }
.ac-head { display: flex; gap: 0.5rem; align-items: baseline; margin-bottom: 0.22rem; padding: 0 0.15rem; }
.ac-who {
    font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-secondary);
}
.ac-row--me .ac-who { color: var(--primary); }
.ac-time { font-family: var(--font-mono); font-size: var(--micro-size); color: var(--text-muted); }
.ac-bubble {
    max-width: 88%; padding: 0.55rem 0.78rem;
    background: var(--bg-elevated); color: var(--text-primary);
    animation: ac-bubble-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.ac-row--me .ac-bubble { background: color-mix(in srgb, var(--primary) 15%, var(--bg-surface)); }
.ac-text { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.9375rem; line-height: 1.45; }
@keyframes ac-bubble-in { from { opacity: 0; transform: translateY(0.35rem); } to { opacity: 1; transform: none; } }
.ac-empty {
    margin: auto; text-align: center; max-width: 22rem;
    font-family: var(--font-mono); font-size: 0.8125rem; color: var(--text-muted); line-height: 1.5;
}
/* Media inside a bubble (DM/group photo, voice, video) — same concept, one
   vocabulary; media just fills the bubble width. */
.ac-media { margin-bottom: 0.35rem; }
.ac-media:last-child { margin-bottom: 0; }
.ac-media img, .ac-media video { display: block; max-width: 100%; max-height: 20rem; }
.ac-media audio { display: block; width: 100%; max-width: 18rem; height: 2.25rem; }
/* Read ticks for own DM messages: ✓ sent, ✓✓ read (tint). Trails the bubble. */
.ac-tick {
    margin-top: 0.2rem; text-align: right;
    font-family: var(--font-mono); font-size: var(--micro-size); letter-spacing: 0.05em;
    color: var(--text-muted);
}
.ac-tick.is-read { color: var(--primary); }

/* Compose — pinned, full width, sits above the fixed tab bar (thread height
   already excludes it). Apple press feedback on send. */
.ac-compose {
    flex-shrink: 0;
    border-top: 0.0625rem solid var(--border); background: var(--bg-surface);
    padding: var(--space-sm) var(--fm-gutter) calc(var(--space-sm) + env(safe-area-inset-bottom, 0px));
}
.ac-compose-row { display: flex; gap: 0.5rem; align-items: flex-end; }
.ac-input {
    flex: 1; resize: none; max-height: 8rem; min-height: 2.75rem;
    /* 16px hard (not 1rem) so iOS never zooms the field on focus. */
    padding: 0.6rem 0.78rem; font-family: var(--font-sans); font-size: 16px;
    border: 0.0625rem solid var(--border); background: var(--bg-base); color: var(--text-primary);
    -webkit-appearance: none; appearance: none;
}
.ac-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 0.125rem var(--focus-ring); }
.ac-send {
    flex-shrink: 0; width: 2.75rem; height: 2.75rem;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--primary); color: #fff; border: none; cursor: pointer;
    -webkit-tap-highlight-color: transparent; touch-action: manipulation;
    transition: transform var(--dur-fast) var(--ease-out), filter var(--dur-fast) var(--ease-out);
}
.ac-send:active { transform: scale(0.9); }
@media (hover: hover) { .ac-send:hover { filter: brightness(1.08); } }

/* Typing — soft shimmer sweep, not pulsing dots (impeccable tell). Shown only
   while the request is in flight (htmx flags the form .htmx-request). */
.ac-typing {
    display: none; padding: 0 0.15rem 0.5rem;
    font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.04em;
    background: linear-gradient(90deg,
        var(--text-muted) 30%, var(--text-primary) 50%, var(--text-muted) 70%);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    animation: ac-shimmer 1.4s linear infinite;
}
form.ac-compose.htmx-request .ac-typing { display: block; }
@keyframes ac-shimmer { to { background-position: -200% center; } }
@media (prefers-reduced-motion: reduce) {
    .ac-bubble { animation: none; }
    .ac-typing { animation: none; -webkit-text-fill-color: var(--text-muted); }
    .ac-send:active { transform: none; }
}

/* #198 */
.chat-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2xl);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    border: 0.0625rem solid var(--border);
    background: var(--bg-surface);
}

/* ── Direct messages (moved from direct_messages.html head; foreman tokens) ── */
/* Мессенджер: full-height, БЕЗ декоративной рамки; высота вычитает реальные
   хедер и нижний таб-бар (--fm-* меряет app.js на каждой странице). */
.dm-layout { display:flex; height:calc(100dvh - var(--fm-header-h, 60px) - var(--fm-bottombar-h, 56px)); overflow:hidden; background:var(--bg-surface); }
/* Сайт-футер (desktop) в чате не нужен: .dm-layout уже занимает весь экран за
   вычетом хедера/таб-бара, а футер снизу добавляет высоту → лишний скролл. */
body:has(.dm-layout) .footer { display:none; }
/* Чат тянется на весь экран под хедером. .main НЕ должен добавлять свой
   padding: dm-layout высотой calc(100dvh − header − bottombar) уже точен, а
   любой отступ .main смещает его вниз ровно на padding → низ не помещается,
   появляется скролл. Обнуляем — окно садится впритык и «дышит» с ресайзом. */
body:has(.dm-layout) .main { padding: 0; }
.dm-sidebar { width:min(35vw, 340px); border-right:0.0625rem solid var(--border); flex-shrink:0; background:var(--bg-base); display:flex; flex-direction:column; }
/* Tab bar pinned at top; only the list below it scrolls. */
.dm-tabs { display:flex; flex-shrink:0; border-bottom:0.0625rem solid var(--border); }
.dm-tab {
  flex:1; padding:0.75em 0.5em; min-height:var(--tap-target); background:var(--bg-base); border:0;
  border-right:0.0625rem solid var(--border);
  color:var(--text-muted); font-family:var(--font-mono); font-size:0.72em;
  text-transform:uppercase; letter-spacing:0.08em; cursor:pointer;
  transition:color 0.15s, background 0.15s;
}
.dm-tab:last-child { border-right:0; }
.dm-tab:hover { background:var(--bg-elevated); color:var(--text-secondary); }
.dm-tab.is-active { color:var(--bg-base); background:var(--primary); font-weight:600; }
.dm-sidebar-scroll { flex:1; overflow-y:auto; min-height:0; }
/* Show only the section matching the active tab. */
.dm-sidebar[data-tab="groups"] .dm-section--dm { display:none; }
.dm-sidebar[data-tab="dm"] .dm-section--groups { display:none; }
.dm-empty--mini { flex:initial; min-height:0; padding:2.5em 1em; }

/* Horizontal wheel picker (workers count) — Apple-alarm mechanic on its side. */
.fm-wheel {
  position:relative; height:3.25rem; overflow:hidden;
  border:0.0625rem solid var(--border); background:var(--bg-surface);
}
.fm-wheel-track {
  display:flex; align-items:center; height:100%;
  overflow-x:auto; scroll-snap-type:x mandatory;
  scrollbar-width:none; -webkit-overflow-scrolling:touch;
}
.fm-wheel-track::-webkit-scrollbar { display:none; }
.fm-wheel:focus { outline:none; border-color:var(--accent); }
.fm-wheel:focus-visible { outline:none; border-color:var(--accent); box-shadow:inset 0 0 0 0.0625rem var(--accent); }
.fm-wheel-item {
  flex:0 0 3rem; scroll-snap-align:center;
  background:none; border:0; padding:0; cursor:pointer;
  color:var(--text-muted); font-family:var(--font-mono); font-size:1rem;
  transition:color 0.12s, transform 0.12s;
}
.fm-wheel-item.is-active { color:var(--accent); font-weight:700; transform:scale(1.3); }
/* Centre pill the numbers scroll under (the selected slot). */
.fm-wheel-pill {
  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  width:3rem; height:2.5rem; border:0.0625rem solid var(--accent);
  pointer-events:none; z-index:1;
}
/* Big unambiguous readout of the selected worker count + affordance hint. */
.fm-wheel-readout {
  display:flex; align-items:baseline; gap:0.5rem; margin-bottom:0.45rem;
}
.fm-wheel-readout-cap {
  font-family:var(--font-mono); font-size:0.75rem; text-transform:uppercase;
  letter-spacing:0.08em; color:var(--text-secondary);
}
.fm-wheel-readout-num {
  font-family:var(--font-mono); font-size:2.25rem; font-weight:700; line-height:1;
  color:var(--primary); font-variant-numeric:tabular-nums;
}
.fm-wheel-hint {
  margin:0.4rem 0 0; font-family:var(--font-mono); font-size:0.6875rem;
  letter-spacing:0.04em; color:var(--text-muted);
}

/* Work-direction index (contractor requirements split into 19 sections). */
.wdir-list { display:flex; flex-direction:column; border:0.0625rem solid var(--border); }
.wdir-item {
  display:flex; align-items:center; gap:0.75rem; padding:0.85rem 1rem; min-height:var(--tap-target);
  border-bottom:0.0625rem solid var(--border); text-decoration:none;
  color:var(--text-primary); transition:background 0.15s;
}
.wdir-item:last-child { border-bottom:0; }

/* Посилання в таблицях були 15-16px заввишки — інлайновий текст без власної
   висоти. У таблиці клікається саме слово, а не рядок, тож воно й має бути
   тап-таргетом. */
.table tbody a { display:inline-flex; align-items:center; min-height:var(--tap-target);
    min-width:var(--tap-target); }
.wdir-item:hover { background:var(--bg-elevated); }
.wdir-num {
  flex-shrink:0; width:1.75rem; height:1.75rem; display:flex; align-items:center;
  justify-content:center; font-family:var(--font-mono); font-size:0.78rem;
  color:var(--accent); border:0.0625rem solid var(--border); background:var(--bg-base);
}
.wdir-name { flex:1; font-size:0.9rem; }
.wdir-go { color:var(--text-muted); flex-shrink:0; }
.wdir-item:hover .wdir-go { color:var(--accent); }
.wdir-back {
  display:inline-block; margin-bottom:var(--space-md); color:var(--text-muted);
  text-decoration:none; font-family:var(--font-mono); font-size:0.8rem;
}
.wdir-back:hover { color:var(--accent); }

/* PWA install banner — fixed bottom, industrial, sharp corners. */
/* `display:flex` below would override the UA `[hidden]{display:none}`, leaving
   the banner permanently visible and making "Later" look dead — pin it back. */
.fm-install[hidden] { display:none; }
.fm-install {
  position:fixed; left:0; right:0; bottom:0; z-index:1200;
  display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap;
  padding:0.9rem 1rem calc(0.9rem + env(safe-area-inset-bottom));
  background:var(--bg-elevated); border-top:0.0625rem solid var(--border);
  box-shadow:0 -0.5rem 1.5rem rgba(0,0,0,0.35);
}
.fm-install-body { display:flex; align-items:center; gap:0.75rem; min-width:0; flex:1; }
.fm-install-icon { border-radius:0; flex-shrink:0; }
.fm-install-txt { display:flex; flex-direction:column; gap:0.15rem; min-width:0; }
.fm-install-txt strong { font-size:0.9rem; color:var(--text-primary); }
.fm-install-txt span { font-size:0.78rem; color:var(--text-muted); line-height:1.4; }
.fm-install-actions { display:flex; gap:0.5rem; flex-shrink:0; }
@media (max-width:30em) {
  .fm-install-actions { width:100%; }
  .fm-install-actions .btn { flex:1; }
}
.dm-chat { flex:1; display:flex; flex-direction:column; min-width:0; }
/* render_inline wrapper must fill the column so messages grow and the
   compose form sticks to the bottom (instead of floating up top). */
.dm-chat > #frag-dm-chat { flex:1; display:flex; flex-direction:column; min-height:0; }

.dm-contact {
  display:flex; align-items:center; gap:0.5em; padding:0.7em 1em;
  border-bottom:0.0625rem solid var(--border);
  cursor:pointer; transition:background 0.15s;
}
.dm-contact:hover { background:var(--bg-elevated); }
/* Active row — soft fill + name accent, no border bar (cleaner, modern). */
.dm-contact--active { background: color-mix(in srgb, var(--primary) 9%, var(--bg-base)); }
.dm-contact--active .dm-contact-name { color: var(--primary); }
.dm-contact-avatar {
  width:2.5em; height:2.5em; border-radius:50%; flex-shrink:0;
  background:var(--bg-elevated);
  display:flex; align-items:center; justify-content:center;
  font-weight:600; font-size:0.85em; color:var(--text-secondary); overflow:hidden;
}
.dm-contact-info { flex:1; min-width:0; }
.dm-contact-name { font-weight:600; font-size:0.9em; color:var(--text-primary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dm-contact-role { font-size:var(--micro-size); color:var(--text-secondary); text-transform:uppercase; letter-spacing:0.05em; font-family:var(--font-mono); }
.dm-contact-last { font-size:0.78em; color:var(--text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.dm-contact-meta { text-align:right; flex-shrink:0; min-width:2.5em; }
.dm-contact-time { font-size:var(--micro-size); color:var(--text-muted); font-family:var(--font-mono); }
.dm-contact-badge {
  display:inline-block; background:var(--primary); color:#fff;
  font-size:0.65em; font-weight:700; min-width:1.4em; padding:0.15em 0.35em;
  border-radius:0.7em; text-align:center; margin-top:0.15em;
}

.dm-empty {
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  color:var(--text-muted); gap:0.5em; font-family:var(--font-mono);
}
.dm-empty svg { width:3em; height:3em; opacity:0.3; }
.dm-empty p { font-size:0.85em; text-transform:uppercase; letter-spacing:0.08em; }

.dm-messages { flex:1; overflow-y:auto; padding:1em; display:flex; flex-direction:column; gap:0.3em; background:var(--bg-surface); }
.dm-msg { max-width:75%; padding:0.5em 0.85em; border-radius:1em; font-size:0.9em; line-height:1.4; word-break:break-word; }
.dm-msg--mine { align-self:flex-end; background:var(--primary); color:#fff; border-bottom-right-radius:0.2em; }
.dm-msg--their { align-self:flex-start; background:var(--bg-elevated); color:var(--text-primary); border-bottom-left-radius:0.2em; }
.dm-msg-sender { font-size:0.7em; font-weight:600; margin-bottom:0.15em; opacity:0.8; }
.dm-msg-time { font-size:0.65em; margin-top:0.3em; opacity:0.7; text-align:right; font-family:var(--font-mono); }

/* Compose bar — industrial: square edges (--radius:0), accent send, focus ring. */
.dm-input-wrap {
  padding:0.6rem 0.7rem;
  padding-bottom:max(0.6rem, env(safe-area-inset-bottom));
  border-top:0.0625rem solid var(--border);
  display:flex; gap:0.5rem; align-items:stretch;
  background:var(--bg-base);
}
.dm-input {
  flex:1; min-height:2.75rem; border-radius:0;
  border:0.0625rem solid var(--border);
  padding:0 0.85rem; font-size:0.9rem; line-height:2.75rem; outline:none;
  background:var(--bg-surface); color:var(--text-primary);
}
.dm-input::placeholder { color:var(--text-muted); }
.dm-input:focus { border-color:var(--accent); box-shadow:inset 0 0 0 0.0625rem var(--accent); }
.dm-send-btn {
  width:2.75rem; min-height:2.75rem; border-radius:0; border:0;
  background:var(--accent); color:#fff; cursor:pointer;
  display:flex; align-items:center; justify-content:center; flex-shrink:0;
}
.dm-send-btn:hover { background:var(--primary-dim); }
.dm-send-btn:active { transform:translateY(0.0625rem); }
.dm-send-btn:disabled { opacity:0.4; cursor:default; }

@media (max-width:600px) {
  .dm-sidebar { width:100%; max-width:100%; }
  .dm-chat { display:none; }
  .dm-layout--chat-open .dm-sidebar { display:none; }
  .dm-layout--chat-open .dm-chat { display:flex; }
  /* Hide the ugly scrollbar "полоски" on mobile — scroll still works. */
  .dm-sidebar, .dm-messages, .chat-messages { scrollbar-width: none; -ms-overflow-style: none; }
  .dm-sidebar::-webkit-scrollbar,
  .dm-messages::-webkit-scrollbar,
  .chat-messages::-webkit-scrollbar { width:0; height:0; display:none; }
  /* Full-screen messenger: with a conversation open, drop the global top
     nav/header (Ben Frain — small screens = single "tube" of content; the
     menu lives off-canvas/behind the back button). Conversation uses the
     whole viewport; the dm-chat-head IS the messenger top bar. */
  body.dm-chat-open .header { display:none; }
  body.dm-chat-open .dm-layout { height:100vh; height:100dvh; border:0; }
  /* Нижний таб-бар «уезжает» в режиме переписки (композер занимает низ);
     закрытие треда снимает класс — бар возвращается тем же transition. */
  body.dm-chat-open .fm-bottombar { transform: translateY(110%); }
  /* Плашка про Face ID фиксирована у нижней кромки (z-index 9998) и
     накрывала композер переписки. В треде её не показываем. */
  body.dm-chat-open #fm-passkey-offer { display: none; }
  body.dm-chat-open { padding-bottom: 0; }
  /* 2-class selector beats the base `.dm-back{display:none}` regardless of
     order; gated to ≤600px so the back button only appears single-pane. */
  .dm-layout--chat-open .dm-back { display:inline-flex; }
}

/* DM chat header (contact name + mobile back) */
.dm-chat-head { display:flex; align-items:center; gap:0.6em; padding:0.6em 1em; padding-top:max(0.6em, env(safe-area-inset-top)); border-bottom:0.0625rem solid var(--border); background:var(--bg-base); flex-shrink:0; }
.dm-back { display:none; align-items:center; justify-content:center; min-width:var(--tap-target); min-height:var(--tap-target);
    background:none; border:none; color:var(--text-secondary); font-size:1.5em; line-height:1; cursor:pointer; padding:0 0.3em; }
.dm-back:hover { color:var(--primary); background:var(--bg-elevated); }
.dm-chat-title { font-weight:600; color:var(--text-primary); font-size:0.95em; }

/* Group conversation entries in the unified DM list */
.dm-contact--group { text-decoration:none; color:inherit; }
.dm-avatar--group { color:var(--primary); background:color-mix(in srgb, var(--primary) 15%, var(--bg-elevated)); }

/* #139 — users page: per-object role cards, mobile-first */
.user-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Collapsed row — tap target ≥44px, no overflow at 360px */
.user-row {
  border: 0.0625rem solid var(--border);
  background: var(--bg-surface);
  overflow: hidden;
}
.user-row[open] { border-color: var(--accent); }

.user-row-summary {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.75rem;
  min-height: 3rem; /* ≥48px touch target */
  cursor: pointer;
  list-style: none; /* hide default triangle on WebKit */
  -webkit-user-select: none;
  user-select: none;
}
.user-row-summary::-webkit-details-marker { display: none; }
/* Custom disclosure indicator — a small chevron that rotates on open */
.user-row-summary::after {
  content: '';
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 0.125rem solid var(--text-muted);
  border-bottom: 0.125rem solid var(--text-muted);
  margin-left: auto;
  flex-shrink: 0;
  transform: rotate(45deg);
  transition: transform 0.15s ease;
}
.user-row[open] .user-row-summary::after { transform: rotate(-135deg); }

.user-row-avatar { flex-shrink: 0; }

.user-row-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.user-row-name {
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--text-primary);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-row-tg {
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  color: var(--text-muted);
  letter-spacing: 0.04em;
}

/* Compact role summary in collapsed state */
.user-row-roles-snippet {
  display: none; /* hidden by default on mobile (narrow) */
  font-size: 0.6875rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 10rem;
  flex-shrink: 1;
}
@media (min-width: 30em) {
  .user-row-roles-snippet { display: block; }
}

.user-row-no-roles {
  color: var(--text-muted);
  font-size: 0.75rem;
}

.role-tag {
  display: inline;
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.role-tag--worker    { color: var(--primary, #4a90d9); }
.role-tag--foreman   { color: var(--accent, #e8962e); }
.role-tag--inspector { color: var(--secondary, #d94a4a); }
.role-tag--admin     { color: var(--tertiary, #34a853); }
.role-tag--org       { color: var(--accent); }
.role-tag--subcontractor  { color: var(--text-secondary); }
.role-tag--project_manager { color: var(--primary); }
.role-tag-site {
  font-size: var(--micro-size);
  color: var(--text-muted);
}

/* ── Role card (/my-role) — "who am I on this object" ─────────── */
.rolecard-wrap { padding: 1rem; }
.rolecard {
  background: var(--bg-surface);
  border: 0.0625rem solid var(--border);
  border-radius: 0;
}
.rolecard-head {
  padding: 1rem 1rem 0.75rem;
  border-bottom: 0.0625rem solid var(--border);
}
.rolecard-kicker {
  font-family: var(--font-mono);
  font-size: var(--micro-size);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.rolecard-title {
  margin: 0.15rem 0 0.5rem;
  font-size: 1.5rem;
  line-height: 1.1;
  color: var(--text-primary);
}
.rolecard-roles { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.rolecard-roles .role-tag {
  padding: 0.15rem 0.45rem;
  border: 0.0625rem solid currentColor;
  font-size: 0.6875rem;
}
.rolecard-norole { color: var(--text-muted); font-size: 0.8125rem; }
.rolecard-section { padding: 0.75rem 1rem; }
.rolecard-section--cant { border-top: 0.0625rem solid var(--border); }
.rolecard-h2 {
  margin: 0 0 0.5rem;
  font-size: 0.9375rem;
  color: var(--text-primary);
}
.rolecard-bydesign {
  margin: -0.25rem 0 0.6rem;
  padding: 0.5rem 0.6rem;
  background: color-mix(in srgb, var(--secondary) 12%, transparent);
  font-size: 0.8125rem;
  color: var(--text-secondary);
}
.rolecard-list { list-style: none; margin: 0; padding: 0; }
.rolecard-item {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.3rem 0;
  border-bottom: 0.0625rem solid color-mix(in srgb, var(--border) 55%, transparent);
  font-size: 0.9375rem;
}
.rolecard-item:last-child { border-bottom: none; }
.rolecard-mark { font-weight: 700; width: 1rem; flex: none; }
.rolecard-item--yes .rolecard-mark { color: var(--success); }
.rolecard-item--no { color: var(--text-muted); }
.rolecard-item--no .rolecard-mark { color: var(--secondary); }
.rolecard-label { flex: 1; }
.rolecard-via {
  font-size: var(--micro-size);
  opacity: 0.7;
  border: none;
  padding: 0;
}
.rolecard-foot {
  padding: 0.75rem 1rem;
  border-top: 0.0625rem solid var(--border);
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* ── Users page: multi-role chips per object ─────────────────── */
.user-site-role {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0;
  border-bottom: 0.0625rem solid color-mix(in srgb, var(--border) 55%, transparent);
}
.user-site-role-name { font-size: 0.8125rem; color: var(--text-secondary); min-width: 6rem; }
.user-site-role-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.role-chip-form { display: inline; margin: 0; }
.role-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.5rem;
  border: 0.0625rem solid var(--border);
  background: var(--bg-elevated);
  border-radius: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  color: var(--text-primary);
  cursor: pointer;
}
.role-chip:hover { border-color: var(--secondary); }
.role-chip-x { color: var(--secondary); font-weight: 700; }
.role-add-form { display: inline-flex; gap: 0.3rem; align-items: center; }
.role-add-form .role-select { width: auto; min-width: 7rem; }

/* ── Onboarding hints: SSR inline cards, zero JS ─────────────── */
.fm-hints { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.75rem 1rem 0; }
.fm-hint-card {
  padding: 0.6rem 0.75rem;
  border: 0.0625rem solid var(--border);
  background: var(--bg-surface);
}
.fm-hint-card .fm-hint-title { font-weight: 700; font-size: 0.875rem; color: var(--text-primary); }
.fm-hint-card .fm-hint-text { font-size: 0.8125rem; color: var(--text-secondary); margin-top: 0.1rem; }
.fm-hint-card .fm-hint-actions { margin-top: 0.4rem; }
.fm-hint-card .fm-hint-ok {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  padding: 0.25rem 0.6rem;
  border: 0.0625rem solid var(--border);
  background: var(--bg-elevated);
  color: var(--text-primary);
  cursor: pointer;
}

/* Expanded detail area */
.user-row-detail {
  padding: 0.75rem;
  border-top: 0.0625rem solid var(--border);
  background: var(--bg-base);
}

/* «Всі об'єкти» org-select row */
.user-org-role {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  padding-bottom: 0.75rem;
  border-bottom: 0.0625rem solid var(--border);
  flex-wrap: wrap;
}
.user-org-label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-secondary);
  white-space: nowrap;
}
.user-org-role .role-select {
  flex: 1;
  min-width: 8rem;
  height: 2.75rem; /* ≥44px touch target */
  font-size: 0.8125rem;
}

/* Вимкнена обліковка: рядок гасне, але лишається читабельним — це не
   видалення, людину ще треба знайти в списку, щоб увімкнути назад. */
.role-tag--off { color: var(--secondary); }

/* Вимкнення доступу — окремий блок під ролями, з відступом-межею, щоб
   не читався як ще одна роль. */
.user-ban-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  padding-bottom: 0.75rem;
  border-bottom: 0.0625rem solid var(--border);
}
.user-ban-form .form-control {
  flex: 1;
  min-width: 10rem;
  height: 2.75rem;
  font-size: 0.8125rem;
}

/* Per-site role grid — responsive: 1 col narrow, 2 cols wide */
.user-role-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 0.5rem;
}

.user-site-role {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0;
  min-height: 2.75rem; /* touch target ≥44px */
}
.user-site-role-name {
  font-size: 0.8125rem;
  color: var(--text-primary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}
.user-site-role .role-select {
  width: 8rem;
  flex-shrink: 0;
  height: 2.5rem;
  font-size: 0.75rem;
}
.user-site-role .btn-sm {
  flex-shrink: 0;
  font-size: 0.6875rem;
  padding: 0.25rem 0.5rem;
  min-height: 2rem;
}

.user-role-empty {
  color: var(--text-muted);
  font-size: 0.8125rem;
  text-align: center;
  padding: 1rem 0;
}

/* Form-control base for selects */
.role-select {
  background: var(--bg-surface);
  border: 0.0625rem solid var(--border);
  color: var(--text-primary);
  padding: 0.25rem 0.5rem;
  font-family: inherit;
  appearance: auto;
  accent-color: var(--accent);
}
.role-select:focus-visible {
  outline: 0.125rem solid var(--accent);
  outline-offset: -0.125rem;
}

/* Hide noscript submit buttons when JS is active — HTMX handles autosave.
   The `noscript` element auto-hides when scripting is enabled. */

/* #199 — Tap-first chip groups for finite-value inputs (report forms, checklists).
   Each chip is a <button> inside a flex row; the active one gets solid fill.
   Under the hood a hidden radio syncs the value. */
.fm-chip-group {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    align-items: center;
}
.fm-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.75rem;      /* ≥44px touch target */
    min-width: 2.75rem;
    padding: 0.375rem 0.75rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    border: 0.0625rem solid var(--border);
    background: var(--bg-surface);
    color: var(--text-secondary);
    cursor: pointer;
    transition: all var(--dur-fast) var(--ease-out);
    -webkit-tap-highlight-color: transparent;
    user-select: none;
}
.fm-chip:hover { border-color: var(--text-muted); color: var(--text-primary); }
.fm-chip[aria-pressed="true"],
.fm-chip.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}
.fm-chip:focus-visible {
    outline: 0.125rem solid var(--primary);
    outline-offset: 0.125rem;
}
/* Wider chips for text labels ("YES"/"NO"/"N/A", zone names, etc.) */
.fm-chip--wide { min-width: 4rem; }

/* #200 — Preset row: chips + hidden free-input for "other" value.
   Layout: chips → "…" chip (reveals free-input) → trailing <input> */
.fm-chip-preset {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    align-items: center;
}
.fm-chip-preset .fm-chip--other {
    color: var(--text-muted);
    border-style: dashed;
}
.fm-chip-preset .fm-chip--other[aria-pressed="true"] {
    background: transparent;
    border-color: var(--primary);
    color: var(--primary);
}
.fm-chip-free {
    width: 3.5rem;
    min-height: 2.75rem;
    padding: 0.375rem 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    text-align: center;
    border: 0.0625rem solid var(--border);
    background: var(--bg-surface);
    color: var(--text-primary);
    border-radius: 0;
    -moz-appearance: textfield;
}
.fm-chip-free::-webkit-inner-spin-button,
.fm-chip-free::-webkit-outer-spin-button { opacity: 1; height: 2rem; }
.fm-chip-free:focus { outline: none; border-color: var(--primary); }
.fm-chip-free[hidden] { display: none; }

/* ─── Profile: industrial "spec-sheet" composition + micro-graphics ─── */
.pf { max-width: 640px; }

/* Identity band — equipment/ID header */
.pf-band { position: relative; border: 1px solid var(--border); background: var(--bg-base);
  padding: 1.5rem 1.25rem 1.25rem; margin-bottom: 1.75rem; overflow: hidden; }
.pf-band::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: var(--primary); }
.pf-band-tag { position: absolute; top: 0.5rem; left: 1.25rem; font-family: var(--font-mono);
  font-size: var(--micro-size); letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-muted); }
.pf-band-grid { position: absolute; inset: 0; pointer-events: none; opacity: 0.14;
  background-image: linear-gradient(var(--border) 1px, transparent 1px), linear-gradient(90deg, var(--border) 1px, transparent 1px);
  background-size: 22px 22px;
  -webkit-mask-image: linear-gradient(105deg, transparent, #000 60%); mask-image: linear-gradient(105deg, transparent, #000 60%); }
.pf-band-body { position: relative; display: flex; align-items: center; gap: 1.1rem; margin-top: 0.7rem; }

/* avatar with corner crosshairs (square = industrial) */
.pf-id-avatar-wrap { position: relative; flex-shrink: 0; width: 96px; height: 96px; }
.pf-id-avatar { width: 96px; height: 96px; object-fit: cover; border: 1px solid var(--border);
  background: var(--bg-surface); border-radius: 2px; display: block; }
.pf-id-avatar--ph { display: flex; align-items: center; justify-content: center; color: var(--text-muted); }
.pf-id-avatar--ph svg { width: 44%; height: 44%; }
.pf-cross { position: absolute; width: 9px; height: 9px; pointer-events: none; z-index: 1; }
.pf-cross::before, .pf-cross::after { content: ""; position: absolute; background: var(--primary); }
.pf-cross::before { width: 9px; height: 1px; top: 0; left: 0; }
.pf-cross::after  { width: 1px; height: 9px; top: 0; left: 0; }
.pf-cross--tl { top: -4px; left: -4px; }
.pf-cross--tr { top: -4px; right: -4px; } .pf-cross--tr::before { left: auto; right: 0; } .pf-cross--tr::after { left: auto; right: 0; }
.pf-cross--bl { bottom: -4px; left: -4px; } .pf-cross--bl::before { top: auto; bottom: 0; } .pf-cross--bl::after { top: auto; bottom: 0; }
.pf-cross--br { bottom: -4px; right: -4px; } .pf-cross--br::before { top: auto; bottom: 0; left: auto; right: 0; } .pf-cross--br::after { top: auto; bottom: 0; left: auto; right: 0; }
.pf-id-cam { position: absolute; bottom: -7px; right: -7px; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
  background: var(--bg-base); border: 1px solid var(--border); border-radius: 2px; color: var(--text-secondary); cursor: pointer; z-index: 2; }
.pf-id-cam:hover { color: var(--primary); border-color: var(--primary); }

.pf-id-meta { display: flex; flex-direction: column; gap: 0.32rem; min-width: 0; }
.pf-id-name { font-size: 1.3rem; font-weight: 800; letter-spacing: -0.02em; color: var(--text-primary); line-height: 1; }
.pf-id-role { display: inline-flex; align-items: center; gap: 0.45rem; font-family: var(--font-mono);
  font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-secondary); }
.pf-tick { width: 6px; height: 6px; background: var(--primary); display: inline-block; flex-shrink: 0; }
.pf-id-readout { font-family: var(--font-mono); font-size: 0.72rem; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* numbered sections */
.pf-sec { margin-bottom: 1.6rem; }
.pf-sec-h { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 0.85rem; font-family: var(--font-mono);
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-secondary); }
.pf-sec-h::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.pf-sec-no { color: var(--primary); }

/* editable fields */
.pf-form { display: flex; flex-direction: column; gap: 0.85rem; }
.pf-field { display: flex; flex-direction: column; gap: 0.32rem; }
.pf-field-k { font-family: var(--font-mono); font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); }
.pf-input { width: 100%; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 2px;
  padding: 0.62rem 0.7rem; color: var(--text-primary); font-size: 0.95rem; }
.pf-input:focus { outline: none; border-color: var(--primary); }
.pf-save { align-self: flex-start; margin-top: 0.2rem; }

/* tabular spec rows with dotted leaders */
.pf-rows { margin: 0; border: 1px solid var(--border); border-radius: 2px; }
.pf-row { display: flex; align-items: baseline; padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border); }
.pf-row:last-child { border-bottom: 0; }
.pf-row dt { flex: 1; display: flex; align-items: baseline; font-family: var(--font-mono); font-size: 0.7rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; }
.pf-row dt::after { content: ""; flex: 1; margin: 0 0.6rem 0.28em; border-bottom: 1px dotted color-mix(in srgb, var(--border) 85%, transparent); }
.pf-row dd { flex-shrink: 0; margin: 0; font-family: var(--font-mono); font-size: 0.85rem; color: var(--text-primary); text-align: right; }

.pf-action { display: flex; flex-direction: column; gap: 0.45rem; align-items: flex-start; }
.pf-toggle { display: flex; align-items: center; gap: 0.6rem; cursor: pointer; }
.pf-hint { color: var(--text-muted); font-size: 0.75rem; line-height: 1.4; }

/* ── Profile band: enerblock-style micro-graphics (LED · QR · blueprint caption · scanline) ── */
.pf-band { padding-top: 1.1rem; }
.pf-band-top, .pf-band-body, .pf-caption { position: relative; z-index: 1; }
.pf-band-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
/* tag now flows in the top row (override earlier absolute positioning) */
.pf-band .pf-band-tag { position: static; top: auto; left: auto; }
.pf-band-status { display: inline-flex; align-items: center; gap: 0.35rem; font-family: var(--font-mono);
  font-size: var(--micro-size); letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); flex-shrink: 0; }
.pf-led { width: 7px; height: 7px; border-radius: 50%; background: #4af626; box-shadow: 0 0 6px rgba(74,246,38,0.6);
  display: inline-block; animation: pf-pulse 2s ease-in-out infinite; }
@keyframes pf-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }

/* scannable traceability tag — printed-label look (cream tile, dark modules) */
.pf-qr { flex-shrink: 0; margin-left: auto; align-self: flex-start; width: 60px; height: 60px;
  padding: 4px; background: #e8e0d4; border-radius: 2px; line-height: 0; }
.pf-qr svg { width: 100%; height: 100%; display: block; }

/* blueprint metadata caption */
.pf-caption { display: block; margin-top: 0.9rem; padding-top: 0.55rem; border-top: 1px solid var(--border);
  font-family: var(--font-mono); font-size: var(--micro-size); letter-spacing: 0.08em; text-transform: uppercase;
  /* Підпис-креслення довший за смугу на 390px; це декоративний рядок,
     переносити його дешевше, ніж рубати «REV 01». */
  color: var(--text-muted); }

/* subtle scanline texture — band only (keeps page content fully readable in sunlight) */
.pf-scan { position: absolute; inset: 0; pointer-events: none; z-index: 0; opacity: 0.5;
  background-image: repeating-linear-gradient(0deg, transparent 0 2px, rgba(0,0,0,0.16) 2px 3px); }
@media (prefers-reduced-motion: reduce) { .pf-led { animation: none; } }

/* small phones: drop the QR so the ID band stays clean + tappable */
@media (max-width: 420px) { .pf-qr { display: none; } }

/* ── Profile SECURITY: enrolled status + ghost "add another" ── */
.pf-status { display: inline-flex; align-items: center; gap: 0.4rem; font-family: var(--font-mono);
  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-secondary); }
.pf-addmore { background: transparent; border: 1px solid var(--border); color: var(--text-secondary);
  padding: 0.4rem 0.75rem; font-size: 0.8rem; }
.pf-addmore:hover { border-color: var(--primary); color: var(--primary); }

/* AI-переклад у чаті: згорнутий оригінал під перекладом — mono-мікрографіка. */
.chat-orig { margin-top: 0.25rem; }
.chat-orig summary {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    cursor: pointer;
    list-style: none;
}
.chat-orig summary::before { content: "⇄ "; color: var(--primary); }
.chat-orig[open] summary { color: var(--text-secondary); }
.chat-orig-text {
    margin-top: 0.25rem;
    font-size: var(--content-font, 0.8125rem);
    color: var(--text-secondary);
}

/* Мессенджер: свои пузыри справа, чужие слева; композер-textarea. */
.chat-msg { max-width: 86%; }
.chat-msg--mine {
    margin-left: auto;
    background: color-mix(in srgb, var(--primary) 7%, var(--bg-surface));
    border-color: color-mix(in srgb, var(--primary) 30%, var(--border));
}
.chat-reply-input, .dm-input { resize: none; overflow-y: auto; line-height: 1.4; }

/* ── Групповой тред: ЧАТ, а не список (ресерч: column-reverse = скролл
   приклеен к низу, poll-afterbegin появляется визуально снизу; сентинел
   подгрузки истории оказывается сверху). ── */
/* display управляет базовый layout/media (мобайл прячет панель), здесь
   только направление — иначе display:flex в конце файла перебивал скрытие. */
.dm-chat { flex-direction: column; min-height: 0; }
.dm-chat .chat-meta { display: none; }               /* счётчики = «список», прячем */
.dm-chat .chat-messages {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    flex-direction: column-reverse;
    border: 0;
    background: transparent;
    overflow-y: auto;
    padding: var(--space-sm);
    gap: var(--space-sm);
}
/* Бабблы = той самий концепт, що AI-чат/личка (.ac-*): тональна заливка,
   БЕЗ рамки-коробки (kill nested-box AI-tell), острые углы (DS). Свои справа
   (primary tint), чужие слева (elevated). Мета-рядок = «шапка» баббла. */
.dm-chat .chat-msg {
    border: 0;
    background: var(--bg-elevated);
    color: var(--text-primary);
    max-width: 88%;
    padding: 0.5rem 0.72rem;
    align-self: flex-start;
    transition: none;
    animation: ac-bubble-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.dm-chat .chat-msg:hover { background: var(--bg-elevated); }
.dm-chat .chat-msg--fm { background: color-mix(in srgb, var(--primary) 7%, var(--bg-elevated)); }
.dm-chat .chat-msg--mine {
    align-self: flex-end;
    margin-left: 0;
    background: color-mix(in srgb, var(--primary) 15%, var(--bg-surface));
}
.dm-chat .chat-msg--mine .chat-msg-author { display: none; }  /* своё имя не нужно */
@media (prefers-reduced-motion: reduce) { .dm-chat .chat-msg { animation: none; } }
.dm-chat .chat-reply { margin-top: 0; padding: var(--space-xs) var(--space-sm) max(var(--space-xs), env(safe-area-inset-bottom)); }

/* Фрагмент-обёртка треда (#frag-group-chat) — прозрачный flex-проводник:
   именно она ребёнок .dm-chat, без этого .chat-messages не клампится. */
.dm-chat #frag-group-chat {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.dm-chat #frag-group-chat .chat-messages { flex: 1 1 auto; min-height: 0; }

/* Reply-цитата в пузыре и chip в композере — mono-микро, полная рамка (не рейл). */
.chat-quote, .chat-quotechip {
    font-size: 0.6875rem;
    color: var(--text-secondary);
    border: 0.0625rem solid var(--border);
    background: color-mix(in srgb, var(--bg-elevated) 60%, transparent);
    padding: 0.25rem 0.5rem;
    margin-bottom: 0.3rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.chat-quote-author {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--primary);
    margin-right: 0.5em;
}
.chat-quotechip { display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.25rem; }
.chat-quotechip button {
    margin-left: auto; background: none; border: 0; color: var(--text-muted);
    font-size: 1rem; cursor: pointer; line-height: 1;
}
.chat-msg-replybtn {
    background: none; border: 0; color: var(--text-muted); cursor: pointer;
    font-size: 0.75rem; padding: 0 0.25rem; line-height: 1;
}
.chat-msg:hover .chat-msg-replybtn, .chat-msg-replybtn:focus-visible { color: var(--primary); }
.chat-attach {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.5rem; min-height: 2.5rem; cursor: pointer;
    color: var(--text-muted); border: 0.0625rem solid var(--border);
}
.chat-attach:hover { color: var(--primary); border-color: var(--primary); }
/* Optimistic-статусы */
.chat-msg--pending { opacity: 0.55; }
.chat-msg--pending .chat-msg-status {
    font-family: var(--font-mono); font-size: var(--micro-size);
    text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted);
}
.chat-msg--pending.is-failed { opacity: 1; border-color: var(--secondary); cursor: pointer; }
.chat-msg--pending.is-failed .chat-msg-status { color: var(--secondary); }

/* Typing-индикатор и DM-галочки. */
.chat-typing {
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
    padding: 0.15rem var(--space-sm);
}
.chat-typing span { color: var(--primary); }
.dm-ticks { font-size: var(--micro-size); color: var(--text-muted); letter-spacing: -0.1em; }
.dm-ticks.is-read { color: var(--primary); }

/* AI-помічник: тред как чат, «думает…» — mono-микро. */
.asst-page { height: calc(100dvh - var(--fm-header-h, 60px) - var(--fm-bottombar-h, 56px)); display: flex; }
/* Специфичность (0,2,0) — иначе `.dm-chat .chat-messages{column-reverse}`
   перебивает и ответы помощника садятся НАД вопросом. history — oldest-first,
   поэтому именно column (не reverse); скролл к низу делает inline-скрипт. */
.dm-chat .asst-thread { flex: 1 1 auto; min-height: 0; overflow-y: auto; flex-direction: column; }
.asst-wait {
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase;
    letter-spacing: 0.1em; color: var(--primary); padding-top: 0.25rem;
}
.htmx-indicator { opacity: 0; transition: opacity 0.2s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }

/* Заметки (A14) + PDF-кнопка доков (A13). */
.note-add { display: flex; gap: var(--space-sm); align-items: flex-end; margin-bottom: var(--space-md); }
.note-add textarea { flex: 1 1 auto; }
.note-list { display: flex; flex-direction: column; gap: var(--space-sm); }
.note-card { border: 0.0625rem solid var(--border); background: var(--bg-surface); padding: var(--space-sm) var(--space-md); }
.note-meta { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.25rem; }
.note-time { font-family: var(--font-mono); font-size: var(--micro-size); color: var(--text-muted); }
.note-archive { display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--tap-target); min-height: var(--tap-target);
  background: none; border: 0; color: var(--text-muted); cursor: pointer; padding: 0.25rem; }
.note-archive:hover { color: var(--secondary); }
.note-text { white-space: pre-wrap; font-size: 0.875rem; line-height: 1.5; }
.doc-pdf-btn { margin-bottom: var(--space-md); display: inline-flex; align-items: center; gap: 0.4em; }

/* A20: недельный отчёт. */
.weekly-form .form-row { display: flex; gap: var(--space-md); flex-wrap: wrap; }
.weekly-done { margin-top: var(--space-md); }
.weekly-summary { margin-top: var(--space-sm); font-size: 0.875rem; line-height: 1.55; color: var(--text-secondary); white-space: pre-wrap; }

/* DM: композер-textarea (старый .dm-input был под однострочный input —
   line-height 2.75rem ломал textarea), flex-проводник фрагмента, фото. */
.dm-input { line-height: 1.45; padding: 0.6rem 0.85rem; min-height: 2.75rem; max-height: 10rem; }
.dm-chat #frag-dm-chat { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.dm-chat #frag-dm-chat .dm-messages { flex: 1 1 auto; min-height: 0; }
.dm-msg-photo img { max-width: 100%; max-height: 320px; display: block; }
.dm-input-wrap .chat-attach { min-height: 2.75rem; width: 2.75rem; flex-shrink: 0; }

/* Пиновані контакти мессенджера (помічник/нотатки) + нотатки-пузирі. */
.dm-pinned { border-bottom: 0.0625rem solid var(--border); }
.dm-avatar--asst { color: var(--primary); }
.dm-avatar--notes { color: var(--text-secondary); }
.notes-thread { flex-direction: column-reverse; }
/* Пузырь заметки прижимался вправо через `margin-left:auto`, а в колоночном
   флексе авто-отступ ещё и СЖИМАЕТ элемент по содержимому: текст переносился
   по букве в столбик шириной с миниатюру (скрин Артьома 12.08). Прижимаем
   через align-self и задаём вилку ширины, как в остальных чатах. */
.notes-thread .chat-msg {
    align-self: flex-end;
    margin-left: 0;
    width: fit-content;
    min-width: min(60%, 14rem);
    max-width: min(86%, 32rem);
}
.notes-thread .chat-msg-text { overflow-wrap: anywhere; }
.note-bubble .chat-msg-meta { justify-content: space-between; }
.note-bubble .note-archive { padding: 0 0.25rem; }

/* Пины «очікує погодження»: видно, но неактивно. */
.dm-contact--disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.dm-contact--disabled .dm-contact-role { color: var(--primary); font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em; }

.feature-pending-card { border: 0.0625rem solid var(--border); background: var(--bg-surface); padding: var(--space-lg); max-width: 34rem; }
.feature-pending-card p { margin: var(--space-sm) 0 0; font-size: 0.875rem; line-height: 1.55; }

/* Multi-assignee picker (create-task form): tap-target checkbox list scoped to
   the site. Sharp corners, no left-border accent — house style. */
.assignee-picker { display: flex; flex-direction: column; gap: 0.0625rem; border: 0.0625rem solid var(--border); background: var(--bg-surface); max-height: 14rem; overflow-y: auto; }
.assignee-opt { display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 0.75rem; font-size: 0.875rem; cursor: pointer; border-bottom: 0.0625rem solid var(--border); }
.assignee-opt:last-child { border-bottom: 0; }
.assignee-opt:has(input:checked) { background: color-mix(in srgb, var(--accent) 12%, var(--bg-surface)); }
.assignee-opt input { width: 1.1rem; height: 1.1rem; flex-shrink: 0; accent-color: var(--accent); }

/* Assignee chip row on the task-detail page (shown when >1 executor). */
.assignee-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.assignee-chip { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.15rem 0.5rem; background: var(--bg-surface); border: 0.0625rem solid var(--border); font-size: 0.8125rem; font-family: var(--font-mono); }

/* AI-translated task title/description — shown under the original, muted, with a
   mono tag pill (house signal style: mono + pill, never a left-border accent). */
.task-tr { color: var(--text-secondary); font-size: 0.9375rem; margin: 0.25rem 0 0; line-height: 1.5; }
.task-tr-tag { display: inline-block; font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em; color: var(--primary); border: 0.0625rem solid var(--border); padding: 0 0.3rem; margin-right: 0.35rem; vertical-align: 0.1em; }
/* Inline marker when an AI translation REPLACES the original (task title/desc).
   Small, muted, trailing — original text stays available via the title= tooltip. */
.task-tr-mark { display: inline-block; font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); border: 0.0625rem solid var(--border); padding: 0 0.25rem; margin-left: 0.4rem; vertical-align: 0.15em; cursor: help; }

/* Evening-report morning-plan "ghost": markable rows (done/partial/miss). Sharp
   corners, mono source tag, no left-border accent (house style). */
.plan-ghost { display: flex; flex-direction: column; gap: 0.0625rem; }
.plan-ghost-empty { color: var(--text-muted); font-size: 0.8125rem; margin: 0.25rem 0 0; }
.ghost-row { display: grid; grid-template-columns: 1fr auto; gap: 0.4rem 0.6rem; align-items: center; padding: 0.5rem 0.6rem; border: 0.0625rem solid var(--border); background: var(--bg-surface); }
.ghost-head { display: flex; align-items: baseline; gap: 0.45rem; min-width: 0; }
.ghost-src { font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); border: 0.0625rem solid var(--border); padding: 0 0.25rem; flex-shrink: 0; }
.ghost-label { font-size: 0.875rem; overflow-wrap: anywhere; }
.ghost-marks { display: inline-flex; gap: 0.0625rem; }
.ghost-mark { width: 2rem; height: 2rem; display: grid; place-items: center; font-size: 1rem; line-height: 1; border: 0.0625rem solid var(--border); background: var(--bg-base); color: var(--text-muted); cursor: pointer; }
.ghost-mark.m-done[aria-pressed="true"]    { background: var(--success); color: #fff; border-color: var(--success); }
.ghost-mark.m-partial[aria-pressed="true"] { background: var(--warning, #d98a00); color: #fff; border-color: var(--warning, #d98a00); }
.ghost-mark.m-miss[aria-pressed="true"]    { background: var(--secondary); color: #fff; border-color: var(--secondary); }
.ghost-note { grid-column: 1 / -1; margin-top: 0.15rem; }

/* Plan review on the report-detail page (read-only checklist). */
.plan-review { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
.pr-item { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.4rem 0.5rem; border: 0.0625rem solid var(--border); }
.pr-mark { font-size: 0.9rem; line-height: 1; flex-shrink: 0; }
.pr-mark-done { color: var(--success); }
.pr-mark-partial { color: var(--warning, #d98a00); }
.pr-mark-miss { color: var(--secondary); }
.pr-body { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem; min-width: 0; }
.pr-src { font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); border: 0.0625rem solid var(--border); padding: 0 0.25rem; }
.pr-label { font-size: 0.875rem; overflow-wrap: anywhere; }
.pr-note { font-size: 0.8125rem; color: var(--text-secondary); font-style: italic; width: 100%; }

/* Project task-completion progress (project overview header). Emerald bar, sharp
   corners, mono label — house style. Separate from the Gantt phase %. */
.po-progress { margin-top: var(--space-sm); }
.po-progress-head { display: flex; justify-content: space-between; align-items: baseline; }
.po-progress-label { font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-secondary); }
.po-progress-pct { font-family: var(--font-mono); font-weight: 700; font-size: 0.9375rem; color: var(--success); }
.po-progress-bar { height: 0.4rem; background: var(--bg-surface); border: 0.0625rem solid var(--border); margin: 0.25rem 0 0.15rem; }
.po-progress-bar > span { display: block; height: 100%; background: var(--success); }
.po-progress-sub { font-size: 0.6875rem; color: var(--text-muted); }

/* Note photos (personal notes can carry images — client 22.07). Reuses the
   comment-thumb sizing; the attach button borrows .chat-attach. */
.note-media { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.5rem; }
.note-thumb { width: 8rem; height: 8rem; object-fit: cover; border: 0.0625rem solid var(--border); display: block; cursor: pointer; }
.note-add { display: flex; align-items: flex-end; gap: 0.5rem; margin-bottom: var(--space-md); }
.note-add .chat-reply-input { flex: 1 1 auto; }
.note-attach { position: relative; flex-shrink: 0; }
.note-attach-count:empty { display: none; }
.note-attach-count { position: absolute; top: -0.25rem; right: -0.25rem; min-width: 0.9rem; height: 0.9rem; padding: 0 0.2rem; display: grid; place-items: center; background: var(--primary); color: #fff; font-family: var(--font-mono); font-size: var(--micro-size); line-height: 1; border-radius: 0.45rem; }

/* ══ Task discussion — chat thread (redesign 22.07) ═══════════════════════
   Was a full-width log with a colour stripe + repeated badge on every row.
   Now a real conversation: mine-right / others-left, avatar, status shown as a
   small tag only on transitions, replies quote the parent inline. */
.tk-thread { position: relative; display: flex; flex-direction: column; gap: 0.75rem; padding: 0.25rem 0 0.25rem 1.75rem; }
.tk-msg { position: relative; z-index: 1; display: flex; gap: 0.5rem; align-items: flex-start; max-width: 100%; }
.tk-msg--mine { flex-direction: row-reverse; }

/* Blueprint connectors parent→child (SVG overlay filled by task-thread.js).
   Micrographic: hairline orange traces in the left gutter, hollow square nodes
   at both ends (survey-point look). Sits behind the bubbles, ignores clicks. */
.tk-links { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: visible; }
.tk-link-path { fill: none; stroke: var(--primary); stroke-width: 1; opacity: 0.32; }
.tk-link-node { fill: var(--bg-base); stroke: var(--primary); stroke-width: 1; opacity: 0.55; }

.tk-avatar {
    flex-shrink: 0; width: 1.875rem; height: 1.875rem;
    display: grid; place-items: center; overflow: hidden; border-radius: 50%;
    background: var(--bg-elevated); border: 0.0625rem solid var(--border);
    font-family: var(--font-mono); font-size: 0.75rem; color: var(--text-secondary);
    text-transform: uppercase;
}
.tk-avatar img { width: 100%; height: 100%; object-fit: cover; }

.tk-bubble {
    position: relative; min-width: 0;
    max-width: min(34rem, 82%);
    background: var(--bg-surface);
    border: 0.0625rem solid var(--border);
    padding: 0.5rem 0.7rem 0.55rem;
}
.tk-msg--mine .tk-bubble {
    background: color-mix(in srgb, var(--primary) 10%, var(--bg-surface));
    border-color: color-mix(in srgb, var(--primary) 28%, var(--border));
}

.tk-head { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.2rem; }
.tk-author { font-family: var(--font-mono); font-size: 0.6875rem; font-weight: 700; color: var(--primary); text-transform: uppercase; letter-spacing: 0.04em; }
.tk-time {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    letter-spacing: 0.06em;
    white-space: nowrap;
}
/* Blueprint-annotation tick: small emerald diamond before the timestamp so it
   reads as a drawn label, not a raw DB string (client 23.07 «слабое звено»). */
.tk-time::before {
    content: "";
    width: 0.28rem;
    height: 0.28rem;
    border: 0.0625rem solid var(--primary);
    transform: rotate(45deg);
    opacity: 0.75;
    flex: none;
}

.tk-tag { font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em; padding: 0.05rem 0.3rem; border: 0.0625rem solid currentColor; line-height: 1.5; }
.tk-tag--fix    { color: var(--primary); }
.tk-tag--review { color: var(--success); }
.tk-tag--reject { color: var(--secondary); }

.tk-quote {
    display: block; margin: 0 0 0.35rem; padding: 0.25rem 0.45rem;
    background: var(--bg-elevated); border: 0.0625rem solid var(--border);
    font-size: 0.75rem; color: var(--text-secondary); text-decoration: none; max-width: 100%;
}
.tk-quote-author { display: block; font-family: var(--font-mono); font-size: var(--micro-size); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--primary); }
.tk-quote-text { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tk-quote:hover { border-color: var(--primary); }

.tk-text { font-size: 0.9375rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }

.tk-media { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.4rem; }
.tk-thumb { width: 9rem; height: 9rem; object-fit: cover; border: 0.0625rem solid var(--border); display: block; }

.tk-reply {
    display: inline-block; margin-top: 0.35rem;
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--text-muted); text-decoration: none; opacity: 0; transition: opacity 0.15s;
}
.tk-msg:hover .tk-reply, .tk-reply:focus-visible { opacity: 1; }
.tk-reply:hover { color: var(--primary); }
@media (pointer: coarse) { .tk-reply { opacity: 0.65; } }

.tk-msg:target .tk-bubble { outline: 0.125rem solid var(--primary); outline-offset: 0.125rem; }

/* Branch focus: click a message (or its connector) → show only that thread;
   click it again → restore. (client 22.07) */
.tk-bubble { transition: border-color 0.15s; }
.tk-msg:hover > .tk-bubble { border-color: color-mix(in srgb, var(--primary) 22%, var(--border)); }
.tk-msg.tk-collapsed { display: none; }
.tk-branch-mode .tk-msg.tk-branch-on > .tk-bubble { border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); }
/* Connector stripe is clickable (parent svg stays click-through). */
.tk-link-path { pointer-events: stroke; cursor: pointer; }
.tk-branch-bar {
    align-self: stretch; margin: 0 0 0.25rem -1.75rem; padding: 0.35rem 0.6rem 0.35rem 1.75rem;
    background: color-mix(in srgb, var(--primary) 10%, var(--bg-surface));
    border: 0.0625rem solid color-mix(in srgb, var(--primary) 28%, var(--border));
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--primary);
}

/* ══ Task response actions — role-gated icon tiles (client 22.07) ═════════
   Icon-over-label tiles, semantic colour per action (submit=primary,
   accept=success, rework=amber, comment=neutral). Sharp corners, mono labels.
   Accept/rework only render for PM+/assigner (server-gated via can_review). */
.tk-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: var(--space-sm); }
.tk-act {
    flex: 1 1 4.5rem; min-width: 4.5rem;
    display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
    padding: 0.6rem 0.4rem; cursor: pointer;
    background: var(--bg-surface); border: 0.0625rem solid var(--border);
    color: var(--text-secondary);
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.06em;
    transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.tk-act-ic { width: 1.35rem; height: 1.35rem; flex-shrink: 0; }
.tk-act span { line-height: 1.2; text-align: center; }
.tk-act:hover { background: var(--bg-elevated); }
.tk-act:active { transform: translateY(0.0625rem); }

.tk-act--fix    { color: var(--primary); border-color: color-mix(in srgb, var(--primary) 35%, var(--border)); }
.tk-act--fix:hover    { background: color-mix(in srgb, var(--primary) 12%, var(--bg-surface)); }
.tk-act--accept { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--border)); }
.tk-act--accept:hover { background: color-mix(in srgb, var(--success) 12%, var(--bg-surface)); }
.tk-act--reject { color: var(--warning, #d98a00); border-color: color-mix(in srgb, var(--warning, #d98a00) 40%, var(--border)); }
.tk-act--reject:hover { background: color-mix(in srgb, var(--warning, #d98a00) 12%, var(--bg-surface)); }
.tk-act--comment { color: var(--text-secondary); }

/* Decision bar — sits by the status up top, physically apart from the comment
   box, so accept/rework read as "task fate", not "act on my comment"
   (Alexandra: approve next to the input was confusing). */
.tk-decision {
    display: flex; flex-direction: column; gap: 0.4rem;
    margin: 0.75rem 0 0.25rem; padding: 0.6rem 0.7rem;
    background: var(--bg-surface); border: 0.0625rem solid var(--border);
}
.tk-decision-lbl {
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase;
    letter-spacing: 0.08em; color: var(--text-muted);
}
.tk-decision-acts { display: flex; gap: 0.4rem; }
/* Horizontal (icon+label inline) in the decision bar — reads as a firm button,
   not a small tile. */
.tk-decision .tk-act { flex: 1 1 0; flex-direction: row; justify-content: center; padding: 0.55rem 0.7rem; font-size: var(--micro-size); }
.tk-decision .tk-act-ic { width: 1.05rem; height: 1.05rem; }

/* Composer toolbar under the textarea: attach photo left, send right — one
   coherent row (send no longer stacks under the photo button). */
.tk-compose-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.5rem; }
.tk-compose-bar .resp-photo { margin-top: 0; }
/* Neutral "send message" — the only action by the comment box now. */
.tk-actions--send { justify-content: flex-end; margin-top: var(--space-sm); }
.tk-send {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.5rem 1rem; cursor: pointer;
    background: var(--bg-surface); border: 0.0625rem solid var(--border);
    color: var(--text-secondary);
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.06em;
    transition: border-color 0.15s, color 0.15s;
}
.tk-send:hover, .tk-send.is-quick { border-color: var(--primary); color: var(--primary); }
.tk-send .tk-act-ic { width: 1rem; height: 1rem; }

/* Compose actions group (right side of the bar): «На доработку» + «Отправить». */
.tk-compose-actions { display: flex; align-items: center; gap: 0.4rem; }
/* «На доработку» — mode toggle by the field (needs the typed reason). Amber,
   distinct from the neutral send. Becomes a neutral «Отмена» while active. */
.tk-rework-toggle {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.5rem 0.9rem; cursor: pointer;
    background: none; border: 0.0625rem solid color-mix(in srgb, var(--warning, #d98a00) 45%, var(--border));
    color: var(--warning, #d98a00);
    font-family: var(--font-mono); font-size: var(--micro-size); text-transform: uppercase; letter-spacing: 0.06em;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.tk-rework-toggle:hover, .tk-rework-toggle:focus-visible { background: color-mix(in srgb, var(--warning, #d98a00) 12%, transparent); outline: none; }
.tk-rework-toggle .tk-act-ic { width: 1rem; height: 1rem; }
.tk-rework-toggle.is-cancel { color: var(--text-muted); border-color: var(--border); }
.tk-rework-toggle.is-cancel:hover { background: var(--bg-elevated); }

/* Send button flips to the rework action while in rework mode — amber to match. */
.tk-send--rework { border-color: color-mix(in srgb, var(--warning, #d98a00) 60%, var(--border)); color: var(--warning, #d98a00); }
.tk-send--rework:hover { border-color: var(--warning, #d98a00); color: var(--warning, #d98a00); }

/* Reason field in rework mode — amber frame + a brief pulse so focus visibly
   lands here (the toggle "moves focus to the comment field"). */
#fm-respond-text { transition: border-color 0.2s ease, box-shadow 0.2s ease; }
.form-control.rework-focus {
    border-color: var(--warning, #d98a00);
    box-shadow: 0 0 0 0.0625rem var(--warning, #d98a00);
    animation: reworkPulse 0.35s ease;
}
@keyframes reworkPulse {
    from { box-shadow: 0 0 0 0.3rem color-mix(in srgb, var(--warning, #d98a00) 30%, transparent); }
    to   { box-shadow: 0 0 0 0.0625rem var(--warning, #d98a00); }
}
/* Reason required but empty → highlight the field the user must fill. */
.form-control.needs-reason { border-color: var(--warning, #d98a00); box-shadow: 0 0 0 0.0625rem var(--warning, #d98a00); }
.tk-act.is-quick { outline: 0.125rem solid currentColor; outline-offset: -0.0625rem; }

/* ══ Drawing primitives (dwg-*) — architectural annotation layer ═══════════
   Shared by the construction micrographics embedded across pages (timeline
   dimension chain, zone grid-bubbles, level datums, revision Δ, section refs).
   Line-weight hierarchy: cut > outline > dimension/grid. Inline SVG uses these
   classes; server prints the coordinates. Kept subtle — signal, not ornament. */
.dwg-dim    { stroke: var(--text-secondary); stroke-width: 1; fill: none; }
.dwg-ext    { stroke: var(--text-muted); stroke-width: .75; fill: none; }
.dwg-tick   { stroke: var(--primary); stroke-width: 1.5; stroke-linecap: round; }
.dwg-grid   { stroke: var(--text-muted); stroke-width: .9; stroke-dasharray: 6 2 1 2; fill: none; }
.dwg-bub    { stroke: var(--primary); stroke-width: 1.25; fill: var(--bg-base); }
.dwg-cut    { stroke: var(--text-primary); stroke-width: 2; fill: none; }
.dwg-solid  { fill: var(--primary); stroke: none; }
.dwg-hollow { fill: none; stroke: var(--primary); stroke-width: 1.25; }
.dwg-lbl    { font-family: var(--font-mono); font-size: 11px; font-weight: 700; fill: var(--text-primary); }
.dwg-sm     { font-family: var(--font-mono); font-size: 9px; fill: var(--text-muted); }
.dwg-dimtxt { font-family: var(--font-mono); font-size: 10px; fill: var(--text-primary); }

/* ══════════════════════════════════════════════════════════════════
   APPLE-DESIGN PASS — WWDC "Designing Fluid Interfaces" + type craft.
   CSS-only; served with ?v=__ASSET__ (mtime), so edits go live with no
   rebuild. Every rule cites the skill section it serves.
   ══════════════════════════════════════════════════════════════════ */

/* §12 — Sticky primary action on the report form.
   A long mobile form buried ОТПРАВИТЬ at the very bottom; the thumb had to
   scroll to reach the one action that matters. `position: sticky` (in-flow,
   NOT fixed) floats the action row above content while scrolling, then rests
   at its natural spot — so it never overlaps the fields the way a fixed bar
   would. Translucent glass (§12: content scrolls under floating chrome). */
@media (pointer: coarse) {
  #report-app .form-actions {
    position: sticky;
    /* Sit ABOVE the fixed bottom tab bar, not under it. app.js measures the
       bar into --fm-bottombar-h; fallback = its real height incl. safe-area.
       (Bar hidden on desktop → app.js sets the var to 0 → rests at bottom.) */
    bottom: var(--fm-bottombar-h, calc(3.5rem + env(safe-area-inset-bottom, 0px)));
    z-index: 40;
    margin-top: var(--space-lg);
    padding: var(--space-sm) 0;
    background: color-mix(in srgb, var(--bg-surface) 82%, transparent);
    -webkit-backdrop-filter: blur(14px) saturate(160%);
    backdrop-filter: blur(14px) saturate(160%);
  }
  /* §12 — scroll-edge, not a hard divider: fade content INTO the bar with a
     gradient sitting just above it, instead of a 1px line. */
  #report-app .form-actions::before {
    content: "";
    position: absolute;
    left: 0; right: 0;
    top: calc(-1 * var(--space-lg));
    height: var(--space-lg);
    pointer-events: none;
    background: linear-gradient(to top,
      color-mix(in srgb, var(--bg-surface) 82%, transparent), transparent);
  }
}
@media (prefers-reduced-transparency: reduce) {
  #report-app .form-actions {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  #report-app .form-actions::before { display: none; }
}

/* §12 — Translucent floating header.
   Was an opaque black strip that just consumed a fixed band. Now a real
   material: content scrolls UNDER a blurred, saturated pane, giving depth
   and the "floating chrome" hierarchy the skill describes. Keeps the
   sticky+margin-bottom top-gap (client «отступ сверху»). */
.header {
  background: color-mix(in srgb, #0a0a0a 72%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border-bottom-color: color-mix(in srgb, #ffffff 8%, transparent);
}
/* §14 — reduced transparency: frost it solid so text never loses contrast. */
@media (prefers-reduced-transparency: reduce) {
  .header {
    background: #0a0a0a;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-bottom-color: var(--border);
  }
}

/* Light OS theme: the chrome is a constant DARK brand frame, but the content
   scrolling behind it is now LIGHT. A 72%-dark glass over light content blends
   to a muddy grey — the dim (--text-muted) tab icons then lose contrast and
   merge with the faint border (client: «днём нижнее меню просвечивается, цвет
   сливается с бордером иконки»). So on light theme paint the chrome SOLID dark
   — glass stays only on dark theme, where the content behind is dark and the
   blend reads as real material. */
@media (prefers-color-scheme: light) {
  .header,
  .fm-bottombar {
    background: #0a0a0a;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .header { border-bottom-color: var(--border); }
  .fm-bottombar { border-top-color: var(--border); }
}

/* §3/§4 — Materialize on reveal (behavior over animation).
   Morning/evening field groups were hard display:none → block, a jump. Now
   they settle in: opacity + a small upward drift on a critically-damped
   ease (damping 1.0, no overshoot — a tap carried no momentum, so no
   bounce). Re-plays each time JS flips display none→'' on type change. */
@keyframes fm-materialize {
  from { opacity: 0; transform: translateY(0.5rem) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
#morning-fields,
#evening-fields {
  animation: fm-materialize var(--dur-slow) cubic-bezier(0.22, 1, 0.36, 1);
}
/* §14 — reduced motion: comprehension-only cross-fade, no drift/scale. */
@media (prefers-reduced-motion: reduce) {
  @keyframes fm-materialize { from { opacity: 0; } to { opacity: 1; } }
  #morning-fields,
  #evening-fields { animation-duration: var(--dur-fast); }
}

/* §15 — Size-specific tracking + leading. Large PROPORTIONAL display text
   reads too loose as it grows → tighten it and pull the leading in. Body
   stays open (already 1.5). Mono-caps spec labels (.form-title, .pf-sec-h)
   keep their wide brand tracking untouched — that width is intentional at
   small caps, exactly what §15 prescribes. */
h1 { letter-spacing: -0.02em; line-height: 1.08; }
.pf-id-name { letter-spacing: -0.02em; line-height: 1.05; }

/* §1 — Response: tappable list cards depress on press-down (not on release),
   so the finger gets instant physical feedback instead of a dead surface.
   Ancestor-:active means a press anywhere inside the card counts. */
.rework-card,
.assignment-card,
.site-card,
.note-card,
.complaint-card-mini,
.fm-qsheet-item {
  transition: transform var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.rework-card:active,
.assignment-card:active,
.site-card:active,
.note-card:active,
.complaint-card-mini:active,
.fm-qsheet-item:active {
  transform: scale(0.985);
}
.fm-tab:active { transform: scale(0.92); }
@media (prefers-reduced-motion: reduce) {
  .rework-card:active,
  .assignment-card:active,
  .site-card:active,
  .note-card:active,
  .complaint-card-mini:active,
  .fm-qsheet-item:active,
  .fm-tab:active { transform: none; }
}
