/* #93 */

/* #94 */
.fm-sheet-layer {
    position: fixed;
    inset: 0;
    z-index: 300;
    pointer-events: none;
}
.fm-sheet-layer[data-open] { pointer-events: auto; }
.fm-sheet-layer .fm-sheet-back {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0);
    transition: background 0.25s var(--ease-out);
}
.fm-sheet-layer[data-open] .fm-sheet-back {
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(0.125rem);
    -webkit-backdrop-filter: blur(0.125rem);
}
.fm-sheet-panel {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    max-width: 46rem;
    margin: 0 auto;
    height: 92dvh;
    background: var(--bg-base);
    color: var(--text-primary);
    border-top-left-radius: 1.25rem;
    border-top-right-radius: 1.25rem;
    box-shadow: 0 -1rem 3rem rgba(0, 0, 0, 0.55);
    transform: translateY(100%);
    transition: transform 0.22s cubic-bezier(.22, 1, .36, 1);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.fm-sheet-layer[data-open] .fm-sheet-panel { transform: translateY(0); }
/* #95 */
.fm-sheet-panel[data-drag] { transition: none; }
.fm-sheet-grip {
    flex: 0 0 auto;
    padding: 0.625rem 0;
    display: flex;
    justify-content: center;
    cursor: grab;
    touch-action: none;
}
.fm-sheet-grip::before {
    content: "";
    display: block;
    width: 2.25rem;
    height: 0.25rem;
    background: var(--text-muted);
    border-radius: 999px;
    opacity: 0.5;
}
/* Кнопка закрытия рисуется всегда, но на телефоне её роль играет ручка
   и свайп вниз — там она только отнимала бы место у заголовка. */
.fm-sheet-x { display: none; }

/* ── Десктоп: шторка перестаёт быть шторкой ────────────────────────────
   Мышью её не тянут, поэтому и ручка сверху лишняя (Артьом 12.08).
   Вместо неё — диалог по центру со своей повадкой: подъём с лёгким
   масштабом, скошенные углы фирменной диагонали, тонкая акцентная кромка
   сверху и явное «esc ✕». Шторочный translateY(100%) здесь перекрыт
   целиком, иначе карточка выезжала бы снизу, как на телефоне. */
@media (min-width: 68.75em) and (pointer: fine) {
    .fm-sheet-layer { display: grid; place-items: center; }
    .fm-sheet-layer[data-open] .fm-sheet-back {
        background: rgba(0, 0, 0, 0.72);
        backdrop-filter: blur(0.375rem) saturate(0.85);
        -webkit-backdrop-filter: blur(0.375rem) saturate(0.85);
    }
    .fm-sheet-panel {
        position: relative;
        inset: auto;
        margin: 0;
        width: min(46rem, 86vw);
        max-width: none;
        height: min(80dvh, 52rem);
        border-radius: 0;
        opacity: 0;
        transform: translateY(1.5rem) scale(0.985);
        transition: transform 0.34s cubic-bezier(.22, 1, .36, 1),
                    opacity 0.18s var(--ease-out);
        /* Диагональный срез — тот же язык, что у карточек объектов. */
        clip-path: polygon(
            0 0,
            calc(100% - var(--cut-lg)) 0,
            100% var(--cut-lg),
            100% 100%,
            var(--cut-lg) 100%,
            0 calc(100% - var(--cut-lg))
        );
    }
    .fm-sheet-layer[data-open] .fm-sheet-panel { opacity: 1; transform: none; }
    .fm-sheet-grip { display: none; }
    .fm-sheet-x {
        position: absolute;
        top: 0.75rem;
        right: 1rem;
        z-index: 3;
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.375rem 0.5rem;
        border: 0;
        background: transparent;
        color: var(--text-muted);
        font-family: var(--font-mono);
        font-size: var(--micro-size);
        letter-spacing: 0.15em;
        text-transform: uppercase;
        cursor: pointer;
        transition: color 0.15s var(--ease-out);
    }
    .fm-sheet-x:hover { color: var(--text-primary); }
    .fm-sheet-x svg { width: 1rem; height: 1rem; }
    .fm-sheet-content { padding-top: var(--space-lg); }
    @media (prefers-reduced-motion: reduce) {
        .fm-sheet-panel { transform: none; transition: opacity 0.15s linear; }
    }
}

.fm-sheet-content {
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* Вертикаль отдаём композитору, горизонталь забирает свайп между
       половинами дня. Без объявления браузер ждёт решения JS на каждом
       касании и первые кадры прокрутки идут рывком. */
    touch-action: pan-y;
    /* The sheet loads a bare fragment (no `.main` wrapper), so without a
       gutter here the section-title rule and full-width inputs run edge to
       edge and spill past the panel's rounded corners on mobile — Dmitriy's
       "адаптация мобильная / длина строки". Match `.main`'s horizontal inset. */
    padding: 0 max(var(--space-lg), 3vw) calc(var(--space-xl) + env(safe-area-inset-bottom));
}

/* Action bar carried into the sheet (app.js openSheetPage lifts #fm-actionbar).
   Sibling of .fm-sheet-content, so it stays pinned while the report scrolls.
   Not `position:fixed` like the page-level bar — inside the panel that would
   anchor to the viewport and sit under the tab bar. */
/* The zero-radius house style loses an argument with the phone: the panel sits
   at the screen edge, and the display's own corner radius shaves the segmented
   group's square corners — a sharp control read as a chipped one. Rather than
   round the control (which would surrender the style), the bar becomes a
   PLINTH: a full-bleed band in the darker base tone that carries the device
   curve, with the group inset from every edge so its corners stay in flat
   territory. The curve now cuts a surface that has no corners to lose. */
.fm-sheet-actionbar {
    flex: 0 0 auto;
    position: relative;
    background: var(--bg-base);
    border-top: 0.0625rem solid var(--border);
    box-shadow: 0 -0.375rem 1rem rgba(0, 0, 0, 0.18);
    /* Clearance on the sides, plus the home-indicator inset below. A single
       inset — the bar's padding used to stack with .rev-bar's own. */
    padding: 0.6rem 0.75rem calc(0.6rem + env(safe-area-inset-bottom, 0px));
}
.fm-sheet-actionbar .rev-bar { padding: 0; }
/* Plate on plinth: the group keeps the surface tone so it reads as the object
   you act on, the band behind it as structure. */
.fm-sheet-actionbar .rev-actions { background: var(--bg-surface); }

/* ── Снимки НАД шторкой ───────────────────────────────────────────────────
   `app.js openSheetPage` вынимает `.rep-shots` из содержимого и вешает сюда,
   тем же приёмом, что и `#fm-actionbar` выше: из скроллера убираем то, что
   не должно уезжать. Внутри панели снимок был первым в общем скролле и
   пропадал с первым движением пальца — сверять вердикт AI становилось не с
   чем. Теперь доказательство стоит над шторкой, разбор едет под ним.
   Слой не перехватывает касания (`pointer-events: none`), чтобы тап мимо
   кадра по-прежнему закрывал шторку; сама лента их принимает. */
/* Шов между кадром и разбором. Панель шторки залита `#0a0a0a` 82%
   (motion.css), земля слоя была ровно тем же тоном — два плана сливались в
   одно пятно. Разводим их: земля уходит в чистый чёрный, панель остаётся
   светлее и получает кромку.
   Кромка — `inset`-тенью, а не `border-top`: у панели `clip-path` со срезом
   угла (motion.css), обычная рамка обрезалась бы вместе с ним и линия
   обрывалась в пустоту. Inset ложится по форме и на срезе честно исчезает. */
.fm-sheet-layer--media .fm-sheet-panel {
    height: 58dvh;
    box-shadow:
        inset 0 0.0625rem 0 var(--border),
        0 -0.75rem 1.75rem rgba(0, 0, 0, 0.65);
}
/* Грип на тёмной земле терялся: у него `--text-muted` при opacity 0.5.
   Это единственный орган управления шторкой, он должен быть виден. */
.fm-sheet-layer--media .fm-sheet-grip::before {
    background: var(--text-secondary);
    opacity: 1;
}
.fm-sheet-stage {
    position: absolute;
    left: 0; right: 0; top: 0; bottom: 58dvh;
    max-width: 46rem;
    margin: 0 auto;
    padding: max(0.75rem, env(safe-area-inset-top)) 0.75rem 0.75rem;
    /* Хром всегда тёмный (DESIGN.md §1). Без своей земли слой оставался
       прозрачным, и в светлой теме по бокам портретного кадра просвечивал
       затемнённый список — серое мельтешение вплотную к доказательству.
       Плотная заливка убирает его и поднимает контраст самого снимка.
       Чистый чёрный, а не `#0a0a0a`: тем тоном залита сама панель шторки,
       и два плана сливались в одно пятно без границы. */
    background: #000;
    pointer-events: none;
    opacity: 0;
    transform: translateY(0.75rem);
    transition: opacity 0.22s var(--ease-out), transform 0.22s var(--ease-out);
}
.fm-sheet-layer--media[data-open] .fm-sheet-stage { opacity: 1; transform: none; }
/* Пока ярусом двигает палец или пружина — переход выключен: он ехал бы по
   своей кривой поверх покадровых значений, и элемент отставал от пальца.
   Тот же `data-drag`, что у панели (правило выше), и то же значение: «этим
   сейчас управляют напрямую». */
.fm-sheet-stage[data-drag] { transition: none; }
.fm-sheet-stage .rep-shots {
    pointer-events: auto;
    height: 100%;
    margin: 0;
    background: transparent;
}
/* `flex: 0 0 100%` ПОВТОРЕНО тут не зря: на min-width:48em сетка страницы
   ужимает кадр до 24rem (там их видно несколько разом), и в шторке снимок
   уезжал в левый угол с чёрной пустотой справа. В слое кадр всегда один. */
.fm-sheet-stage .rep-shot { height: 100%; flex: 0 0 100%; border: none; }
/* `contain`, а не `cover`: кадр — доказательство, обрезать у него края
   нельзя, дефект окажется ровно за срезом. */
.fm-sheet-stage .rep-shot img,
.fm-sheet-stage .rep-shot video {
    height: 100%;
    width: 100%;
    aspect-ratio: auto;
    object-fit: contain;
    /* Подложку под `contain` рисует САМ элемент, а не слой: в сетке превью
       у него `background: var(--bg-elevated)` — заглушка на время загрузки.
       В светлой теме это серый, и поля вокруг портретного кадра выходили
       светлыми поверх тёмной земли слоя. Гасим здесь, у кадра во всю высоту
       заглушке всё равно не место. */
    background: transparent;
}
/* Счётчик — подпись системы о данных, значит Mono прописными (DESIGN.md §2)
   и ПЛОТНОЙ заливкой: полупрозрачная надпись на солнце не читается, а
   градиент внизу кадра держался только на пейзажной пропорции. Сидит на
   тёмной земле в углу слоя, поэтому не зависит от формы снимка. */
.fm-sheet-stage .rep-shot-n {
    left: 0.5rem;
    right: auto;
    bottom: 0.5rem;
    max-width: calc(100% - 1rem);
    padding: 0.2rem 0.45rem;
    background: #0a0a0a;
    border: 0.0625rem solid rgba(245, 242, 238, 0.22);
    color: #f5f2ee;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Photo variant: панель обнимает картинку (до 92dvh), тёмный фон, без гуттера.
   Тап по фону / свайп грипа / Back — закрыть. Открывается через fmPhotoSheet. */
.fm-sheet-layer--photo .fm-sheet-panel { height: auto; max-height: 92dvh; background: #0a0a0a; }
.fm-sheet-layer--photo .fm-sheet-content {
    padding: 0 0 env(safe-area-inset-bottom);
    display: flex;
    align-items: center;
    justify-content: center;
}
.fm-sheet-img { display: block; width: 100%; height: auto; max-height: calc(92dvh - 2.75rem); object-fit: contain; }

/* #96 */
::selection {
    background: var(--primary);
    color: #fff;
}

/* #97 */
.table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none; /* #98 */
    -ms-overflow-style: none; /* #99 */
}
.table-wrap::-webkit-scrollbar { display: none; /* #100 */ }

/* #101 */

.header {
    background: #0a0a0a;
    color: #e8e4de !important;
    border-bottom: 0.0625rem solid var(--border);
    position: sticky;
    top: 0;
    z-index: 100;
    /* Reserve a gap in flow AFTER the sticky header so page content never tucks
       under it (the absolute-centred logo overhangs the collapsed side-icon
       row). margin-bottom on the sticky box pushes following content down —
       client «отступ сверху пропал». */
    margin-bottom: 0.875rem;
}

.header-inner {
    width: min(100%, 90rem);
    margin: 0 auto;
    /* #102 */
    padding: var(--space-sm) var(--space-md);
    display: flex;
    align-items: center;
    /* #103 */
    justify-content: flex-start;
    gap: var(--space-md);
}
@media (min-width: 48em) {
    .header-inner { padding: var(--space-sm) var(--space-lg); }
}

/* #104 */

.main {
    width: min(100%, 90rem);
    /* flex-элемент колонки body: занимает весь остаток высоты, поэтому
       подвал под ним оказывается у нижней кромки, а не посреди экрана. */
    flex: 1 0 auto;
    margin: 0 auto;
    padding: var(--space-md);
}
@media (min-width: 48em) {
    .main { padding: var(--space-xl) max(var(--space-lg), 3vw); }
}

/* #106 */

/* #107 — shown on every viewport (desktop too). The template only renders it
   off the dashboard/sites roots, so it never appears where there's nowhere to
   go back to. Client 20.07: "с компьютера не хватает кнопки назад". */
.nav-back {
    display: flex;
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    padding: var(--space-xs);
    min-width: 2.75rem;
    min-height: 2.75rem;
    align-items: center;
    justify-content: center;
    order: 21;
    -webkit-tap-highlight-color: transparent;
}
.nav-back .icon { transition: transform var(--dur-fast) var(--ease-out); }
.nav-back:active .icon { transform: translateX(-0.25rem); }

/* Drawer grip is JS+mobile-only (shown by `html.js .nav-grip.open`); hidden
   everywhere else so no-JS / desktop never render a stray button. */
.nav-grip { display: none; }

.nav-toggle {
    display: none;
    background: none;
    border: none;
    color: #fff !important;
    cursor: pointer;
    padding: var(--space-sm);
    min-width: 2.75rem;
    min-height: 2.75rem;
    align-items: center;
    justify-content: center;
    position: relative;
    order: 22;
    z-index: 201;
}

/* #108 */
.nav-toggle .icon {
    transition: transform var(--dur-normal) var(--ease-out);
}
.nav-toggle.active .icon {
    transform: rotate(90deg);
}

/* #109 */

@media (max-width: 68.75em) {
    .nav-back { display: flex; }
    /* Burger removed from the mobile header — the bottom-bar "Menu" tab and
       the drawer grip open the drawer. The button stays in the DOM (hidden)
       so app.js's `menuTab.click()` on .nav-toggle still fires. */
    .nav-toggle { display: none; }

    /* Mobile header layout: back (far left) · account/avatar (right of back)
       · LOGO centred · burger · notifications (far right). Logo is pinned to
       the centre absolutely so the side clusters don't shift it; the burger's
       auto left-margin splits the row into a left and a right cluster. */
    .header-inner {
        position: relative;
        /* Logo is out of flow (absolute-centred); without a floor the row can
           collapse to the small icon heights and the sticky header stops
           reserving enough space → dashboard cards slide under it. Pin a stable
           header height that clears the 2rem logo. */
        min-height: 3.25rem;
    }
    .header-inner .logo {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        margin: 0;
    }
    .nav-back      { order: 1; }
    #frag-switcher { order: 2; }
    #frag-inbox    { order: 9; margin-left: auto; }

    /* #110 */
    .nav {
        display: flex;
        flex-direction: column;
        gap: 0;
        background: #0a0a0a;
        border-top: 0.0625rem solid rgba(255,255,255,.12);
        /* Override the desktop `.nav { align-items: center }`: in the column
           drawer, centering makes rows shrink to content and stagger into an
           arc. Stretch → full-width, left-aligned rows. */
        align-items: stretch;
    }
    /* Brutalist mobile drawer (tactile brutalism 2026): full-bleed numbered
       wireframe rows, hard 1px dividers, mono uppercase, filled-orange active
       block, abrupt states, gloved-hand tap targets. `.nav …` prefixes win
       specificity over the global .nav-link !important colour. */
    .nav { counter-reset: navrow; gap: 0; }
    .nav .nav-link {
        counter-increment: navrow;
        font-family: var(--font-mono);
        font-size: 0.9375rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--text-primary) !important;
        min-height: 3.25rem;
        padding: var(--space-md);
        border-bottom: 0.0625rem solid var(--border);
        gap: var(--space-md);
        align-items: center;
        transition: none;
        white-space: normal;
        word-break: keep-all;
    }
    /* Leading-zero index prefix — brutalist convention, matches the lift-rail. */
    .nav .nav-link::before {
        content: counter(navrow, decimal-leading-zero);
        font-family: var(--font-mono);
        font-size: 0.6875rem;
        font-weight: 500;
        letter-spacing: 0.12em;
        color: var(--text-muted);
        min-width: 1.5rem;
    }
    .nav .nav-link .icon { opacity: 1; margin: 0; flex-shrink: 0; transform: none; }
    .nav .nav-link:active { background: var(--bg-surface); color: #fff !important; }
    /* Active = the icon glyph turns orange (no filled block). */
    .nav .nav-link.active { background: none; }
    .nav .nav-link.active::before { color: var(--primary); }
    .nav .nav-link.active .icon { opacity: 1; color: var(--primary); }

    /* Mobile de-dup: the bottom tab-bar owns the top destinations, so the
       drawer drops the entries that duplicate them (nav_dup) and the header
       drops its Messages shortcut — leaving only the notifications bell.
       Desktop (no tab-bar) keeps everything. */
    .nav .nav-link--dup { display: none; }
    #fm-dm-bell { display: none; }
    .nav-sep { width: 100%; height: 0;
        border-top: 0.0625rem solid var(--border);
        margin: 0; }
    .nav-backdrop { display: none; }
    .header-inner { gap: var(--space-sm); }

    /* #112 */
    @supports (transform: translateX(100%)) {
        html.js .nav {
            position: fixed;
            top: 0;
            right: 0;
            /* Two-stage drawer: opens as an icon-only rail; the grip pulls it
               wide (.wide) to reveal numbered labels + footer. */
            width: 4.75rem;
            /* Full-height rail (a proper side rail, not a half-screen strip).
               Compact square cells below keep the icons from looking stretched. */
            height: 100vh;
            height: 100dvh;
            /* Full-bleed rows: no side padding on the panel, the rows own it. */
            padding: 4.5rem 0 var(--space-2xl);
            overflow-y: auto;
            overflow-x: hidden;
            overscroll-behavior: contain;
            -webkit-overflow-scrolling: touch;
            z-index: 200;
            border-left: 0.09375rem solid var(--primary);
            border-top: none;
            transform: translateX(100%);
            transition: transform var(--dur-normal) var(--ease-out),
                        width var(--dur-normal) var(--ease-out);
            visibility: hidden;
        }
        html.js .nav.open { transform: translateX(0); visibility: visible; }
        html.js .nav.wide { width: min(20rem, 85vw); }

        /* ── Mini rail (icon-only) — hide labels/numbers/footer, centre icon.
           Compact near-square cells: without a label the row must NOT keep the
           tall 3.25rem label height, or the icon sits in a stretched box. ── */
        html.js .nav:not(.wide) .nav-label { display: none; }
        html.js .nav:not(.wide) .nav-link {
            justify-content: center;
            gap: 0;
            padding: 0;
            min-height: 3.25rem;   /* == 4.75rem rail minus borders → square-ish */
        }
        html.js .nav:not(.wide) .nav-link .icon { width: 1.375rem; height: 1.375rem; }
        html.js .nav:not(.wide) .nav-link::before { content: none; }
        html.js .nav:not(.wide) .nav-footer { display: none; }

        /* ── Grip handle — vertical pull-tab on the drawer's left edge ── */
        html.js .nav-grip {
            position: fixed;
            top: 50%;
            right: 4.75rem;
            transform: translateY(-50%);
            width: 1.375rem;
            height: 3.75rem;
            display: none;
            align-items: center;
            justify-content: center;
            padding: 0;
            background: var(--primary);
            color: #0a0a0a;
            border: none;
            border-radius: 0;
            cursor: pointer;
            z-index: 201;
            transition: right var(--dur-normal) var(--ease-out);
            -webkit-tap-highlight-color: transparent;
        }
        html.js .nav-grip.open { display: flex; }
        html.js .nav-grip.wide { right: min(20rem, 85vw); }
        html.js .nav-grip .icon { width: 1rem; height: 1rem;
            transition: transform var(--dur-fast) var(--ease-out); }
        html.js .nav-grip.wide .icon { transform: scaleX(-1); }
        html.js .nav-backdrop {
            display: block;
            position: fixed;
            inset: 0;
            background: rgba(0,0,0,0.6);
            z-index: 199;
            opacity: 0;
            visibility: hidden;
            transition: opacity var(--dur-normal) var(--ease-out), visibility 0s var(--dur-normal);
        }
        html.js .nav-backdrop.open {
            opacity: 1;
            visibility: visible;
            transition: opacity var(--dur-normal) var(--ease-out), visibility 0s;
        }
    }
    /* #113 */
    @supports (transform: translate3d(0, 0, 0)) {
        html.js .nav       { transform: translate3d(100%, 0, 0); }
        html.js .nav.open  { transform: translate3d(0,    0, 0); }
    }
}

/* #114 */
@media (min-width: 68.8125em) {
    .nav-toggle,
    .nav-backdrop { display: none; }
}

/* #115 */

/* #116 */
@media (max-width: 48em) {
    .table-cards thead { display: none; }
    .table-cards,
    .table-cards tbody { display: block; width: 100%; }

    .table-cards tr {
        display: grid;
        /* `auto` у першій колонці не мав нижньої межі й забирав усю ширину:
           на /documents середня колонка (категорія, автор) стискалась до 0px.
           `minmax(0,auto)` дозволяє їй стиснутись і віддати місце. */
        grid-template-columns: minmax(0, auto) minmax(4rem, 1fr) minmax(0, auto);
        gap: 0 var(--space-sm);
        background: var(--bg-surface);
        border: 0.0625rem solid var(--border);
        padding: var(--space-sm) var(--space-md);
        margin-bottom: 0.25rem;
        align-items: center;
        cursor: pointer;
    }

    .table-cards td {
        padding: 0;
        border: none;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* #117 */
    .table-cards td:nth-child(n+7) { display: none; }
    .table-cards td::before { display: none; }
    .table-cards td:empty { display: none; }

    /* #118 */
    .table-cards .report-actions { display: flex; grid-column: 3; }
}

/* #119 */

/* #120 */
/* #121 */
.footer {
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    color: var(--micro-color);
    padding: var(--space-xl) var(--space-md) var(--space-lg);
    border-top: 0.0625rem solid var(--border);
    margin-top: var(--space-2xl);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
}
/* #122 */
.footer > span:first-child { margin-right: auto; }
.footer-logout { margin-left: auto; }
.footer-logout-btn {
    background: none;
    border: 0;
    padding: 0.375rem 0.625rem;
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.15em;
    cursor: pointer;
}
.footer-logout-btn:hover { color: var(--text-primary); }
.footer-pwa-btn {
    background: none;
    border: 0;
    padding: 0.375rem 0.625rem;
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: var(--micro-size);
    text-transform: uppercase;
    letter-spacing: 0.15em;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}
.footer-pwa-btn:hover { color: var(--text-primary); }
@media (max-width: 47.99em) {
    .footer { gap: var(--space-sm); }
    .footer > span:first-child,
    .footer-logout { margin: 0; }
}

/* «Два футтера» на мобиле: где drawer off-canvas — большой футер прячем,
   его функции живут в низу drawer (.nav-footer). Desktop: наоборот. */
.nav-footer { display: none; }
@media (max-width: 68.75em) {
    .footer { display: none; }
    .nav-footer {
        display: flex;
        flex-direction: column;
        gap: var(--space-sm);
        margin-top: auto;
        /* Re-inset horizontally (panel is now full-bleed for the rows above). */
        padding: var(--space-lg) var(--space-md) 0;
        border-top: 0.0625rem solid var(--border);
    }
    .nav-footer-btn {
        display: inline-flex;
        align-items: center;
        gap: 0.5em;
        background: none;
        border: 0.0625rem solid var(--border);
        color: var(--text-secondary);
        font-family: var(--font-mono);
        font-size: 0.6875rem;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        padding: 0.5rem 0.75rem;
        cursor: pointer;
        width: 100%;
        justify-content: center;
    }
    .nav-footer-btn--logout { color: var(--text-muted); }
    .nav-footer form { width: 100%; }
}
