/**
 * ForensiQ — App Shell (refactor v2 — art direction)
 *
 * Layout two-pane inspirado em IDE / Linear / Cellebrite. Substitui
 * a navbar simples + container central da v1.
 *
 * Estrutura:
 *   .app-top      — header sticky (brand · chips contexto · clock · user)
 *   .app-grid     — grelha 2 colunas (sidebar | main)
 *   .app-sidebar  — 240px, navegação principal por grupos
 *   .app-main     — conteúdo da página (wrapper .container interno)
 *   .app-bottom   — footer técnico (versão · commit · região · CSP)
 *
 * Em <1024px: sidebar em off-canvas (aberta pelo hamburger do header,
 * com fundo e foco preso).
 *
 * Ver a especificação de art direction §Layout.
 */

/* =====================================================================
   Estrutura raiz
   ===================================================================== */

:root {
    --app-top-h:      52px;
    --app-bottom-h:   28px;
    --app-sidebar-w:  240px;
}

body.app-body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Skip-link (a11y): fonte única em main.css (auditoria D80). */

/* =====================================================================
   app-top — header de contexto operacional
   ===================================================================== */

.app-top {
    position: sticky;
    top: 0;
    z-index: 50;
    height: var(--app-top-h);
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 0 var(--sp-3);
    background: var(--bg-subtle);
    border-bottom: 1px solid var(--border);
}

/* Hamburger — navegação móvel (<1024px). Receita base em .icon-btn (main.css,
   auditoria D78) — aqui ficam só os deltas de layout. */
.app-top__nav-toggle {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    margin-left: calc(var(--sp-1) * -1);
}
.app-top__nav-toggle svg {
    width: 20px;
    height: 20px;
}
/* A partir de 1024px a sidebar é fixa: o hamburger desaparece. */
@media (min-width: 1024px) {
    .app-top__nav-toggle {
        display: none;
    }
}

/* <1024px (móvel/tablet, sidebar em off-canvas): aperta o gap do header para
   dar mais folga ao cluster da direita (carimbo · tema · sessão). */
@media (max-width: 1023px) {
    .app-top {
        gap: var(--sp-2);
    }
}

.app-top__brand {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--text-emphasis);
    text-decoration: none;
    font-weight: var(--fw-semi);
    letter-spacing: var(--tracking-tight);
    padding: var(--sp-1) var(--sp-2);
    border-radius: var(--r-2);
    transition: background var(--t-fast) var(--ease);
}
.app-top__brand:hover {
    background: var(--surface-hover);
    color: var(--text-emphasis);
}
.app-top__brand-mark {
    width: 28px;
    height: 24px;
    flex-shrink: 0;
}
.app-top__brand-name {
    font-size: var(--fs-sm);
}

.app-top__sep {
    color: var(--text-subtle);
    user-select: none;
}

/* Chips de contexto operacional (papel · nome · turno · zona · device) */
.app-top__chips {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--sp-1);
    overflow: hidden;
    flex-shrink: 1;
    min-width: 0;
}

.app-top__chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    line-height: 1.6;
    color: var(--text-muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-1);
    white-space: nowrap;
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    /* Nome/papel longo em ecrã estreito: trunca com reticências em vez de
       cortar o texto a meio do glifo (perde-se contexto operacional). */
    min-width: 0;
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-top__chip[data-variant="role"] {
    color: var(--accent-on-tint);
    border-color: var(--accent-tint);
    background: var(--accent-tint);
    /* Papel é vocabulário fechado e prioritário: encaixa o texto todo, sem o
       corte do max-width genérico (ex.: "Perito forense digital" cabia a meio).
       Em ecrã estreito o flex-shrink + reticências ainda tratam do overflow. */
    max-width: none;
}

.app-top__spacer { flex: 1 1 auto; min-width: var(--sp-2); }

.app-top__clock {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: var(--ffs-forensic);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    padding: 2px var(--sp-2);
    white-space: nowrap;
}
.app-top__date {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: var(--ffs-forensic);
    /* Mesmo estilo da hora (.app-top__clock): tamanho e cor iguais — a data e a
       hora leem-se como um só carimbo temporal. */
    font-size: var(--fs-sm);
    color: var(--text-muted);
    padding: 2px 0 2px var(--sp-2);
    white-space: nowrap;
}

/* Carimbo temporal (data + relógio). Em ≥768px é transparente
   (display:contents): a data e o relógio são filhos diretos do flex do header e
   ficam lado a lado, exatamente como antes. Em <768px (bloco mais abaixo) passa
   a coluna e empilha-os, ocupando a largura de uma só linha. */
.app-top__stamp {
    display: contents;
}

.app-top__clock-sep {
    transition: opacity var(--t-base);
}
@media (prefers-reduced-motion: no-preference) {
    .app-top__clock[data-blink="on"] .app-top__clock-sep {
        opacity: 0.35;
    }
}

/* <768px: esconde o nome da marca (fica só o aro) e EMPILHA o carimbo temporal
   — a data sobre o relógio, alinhados à direita. O par passa a ocupar a largura
   de uma linha (~metade do que data+hora lado a lado ocupavam): é o espaço que
   empurrava o "Terminar sessão" para fora do ecrã. */
@media (max-width: 767px) {
    .app-top__brand-name {
        display: none;
    }
    .app-top__stamp {
        display: flex;
        flex-direction: column;
        align-items: flex-end;
        gap: 0;
        line-height: 1.2;
    }
    .app-top__date,
    .app-top__clock {
        font-size: var(--fs-micro);
        padding: 0;
    }
    /* Chips de contexto (papel · nome) clipavam a meio da palavra no telemóvel
       ("PERIT", "P") — o avatar das iniciais e o aria-label do "Terminar sessão"
       já identificam a sessão. Saem com o separador; reaparecem na íntegra
       ≥768px (tablet/desktop), onde há largura para eles. */
    .app-top__sep,
    .app-top__chips {
        display: none;
    }
}

/* =====================================================================
   app-grid — grelha two-pane
   ===================================================================== */

.app-grid {
    flex: 1;
    display: grid;
    grid-template-columns: 1fr;
    min-height: 0;
}

@media (min-width: 1024px) {
    .app-grid {
        grid-template-columns: var(--app-sidebar-w) 1fr;
    }
}

/* =====================================================================
   app-sidebar
   ===================================================================== */

.app-sidebar {
    background: var(--bg-subtle);
    border-right: 1px solid var(--border);
    overflow-y: auto;
    overflow-x: hidden;
    padding: 0 0 var(--sp-6);
}

/* Cabeçalho do off-canvas — só no modo móvel (<1024px) */
.app-sidebar__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    height: var(--app-top-h);
    padding: 0 var(--sp-3);
    border-bottom: 1px solid var(--border);
}
/* Receita base do micro-rótulo na regra agrupada de forensic.css (D83). */
.app-sidebar__head-title {
    font-weight: var(--fw-semi);
}
/* Receita base em .icon-btn (main.css, auditoria D78) — só o tamanho próprio. */
.app-sidebar__close {
    width: 40px;
    height: 40px;
}

/* -------------------------------------------------------------------
   <1024px — sidebar como off-canvas controlado por body.nav-open
   ------------------------------------------------------------------- */
@media (max-width: 1023px) {
    .app-sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 80;
        width: min(86vw, var(--app-sidebar-w));
        padding-top: 0;
        transform: translateX(-100%);
        transition: transform var(--t-base) var(--ease);
        box-shadow: var(--shadow-lg);
    }
    body.nav-open .app-sidebar {
        transform: translateX(0);
    }

    .nav-backdrop {
        position: fixed;
        inset: 0;
        z-index: 70;
        background: rgba(0, 0, 0, 0.5);
        border: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .app-sidebar {
        transition: none;
    }
}

/* A partir de 1024px a sidebar é fixa na grelha; o off-canvas desliga-se. */
@media (min-width: 1024px) {
    .app-sidebar {
        padding-top: var(--sp-3);
        /* Mantém a navegação SEMPRE visível em páginas altas: a sidebar
           fixa-se logo abaixo do header (mesmo mecanismo `position: sticky`
           do `.app-top`) em vez de acompanhar o scroll do documento e sair do
           ecrã. `align-self: start` impede o item da grelha de esticar à
           altura total do conteúdo — sem isto o sticky não teria folga para
           agarrar. O `max-height` (viewport menos o header) faz a navegação
           rolar DENTRO da própria sidebar quando há grupos a mais, sem nunca
           empurrar o resto da página. */
        position: sticky;
        top: var(--app-top-h);
        align-self: start;
        max-height: calc(100dvh - var(--app-top-h));
    }
    .app-sidebar__head {
        display: none;
    }
    .nav-backdrop {
        display: none;
    }
}

.app-sidebar__group {
    padding: var(--sp-3) var(--sp-3) var(--sp-2);
}

.app-sidebar__group-title {
    font-weight: var(--fw-semi);
    margin: 0 var(--sp-2) var(--sp-2);
}

.app-sidebar__link {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    color: var(--text);
    border-radius: var(--r-2);
    border-left: 2px solid transparent;
    font-size: var(--fs-sm);
    text-decoration: none;
    line-height: 1.3;
    transition: background var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease);
    min-height: 32px;
}
.app-sidebar__link:hover {
    background: var(--surface-hover);
    color: var(--text-emphasis);
}
.app-sidebar__link:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}
.app-sidebar__link[aria-current="page"] {
    background: var(--accent-tint);
    color: var(--accent-on-tint);  /* âmbar legível sobre a tinta (AA) */
    border-left-color: var(--accent);
    font-weight: var(--fw-medium);
}

.app-sidebar__icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    color: currentColor;
}

.app-sidebar__label {
    flex: 1;
    min-width: 0;
}

/* Badge de contagem (ex.: "prova a chegar" por receber). Pílula âmbar discreta,
   dígitos em mono — alinhada à direita do link, sinaliza sem dominar. */
.app-sidebar__badge {
    flex-shrink: 0;
    min-width: 18px;
    height: 18px;
    padding: 0 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
    font-weight: var(--fw-semi);
    line-height: 1;
    color: var(--accent-on-tint);
    background: var(--accent-tint);
    border: 1px solid var(--accent);
    border-radius: var(--r-pill);
}

/* Atalho de ação rápida ("Nova ocorrência", "Novo item") — distinto dos links de
   navegação: rótulo discreto, afordância "+" em âmbar, tinta no hover. Abre o
   modal ação-in-place; degrada para a página completa via href. */
.app-sidebar__link--action {
    color: var(--text-muted);
    font-weight: var(--fw-medium);
}
.app-sidebar__link--action .app-sidebar__icon {
    color: var(--accent);
}
.app-sidebar__link--action:hover {
    background: var(--accent-tint);
    color: var(--accent-on-tint);
}
.app-sidebar__link--action:hover .app-sidebar__icon {
    color: var(--accent-on-tint);
}

/* =====================================================================
   app-main
   ===================================================================== */

.app-main {
    min-width: 0;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}
.app-main:focus { outline: none; }

/* Strip de breadcrumb dentro do main (reaproveita .breadcrumb da v1) */
.app-breadcrumb {
    padding: var(--sp-2) var(--sp-4);
    border-bottom: 1px solid var(--border);
    background: var(--bg);
    flex-shrink: 0;
}

/* Páginas raiz (ex.: /dashboard/) só emitem o rótulo `Início` (sem <a> de
   navegação). Em mobile o `.breadcrumb-current` é escondido, deixando uma
   faixa fantasma com padding + borda inferior. Quando o strip não tem
   navegação real (nenhum <a>), oculta o contentor por inteiro. */
.app-main > .app-breadcrumb:not(:has(a)) {
    display: none;
}

/* Cromado de painel ÚNICO (auditoria D79): cabeçalho, título e superfície
   dos painéis flutuantes (modal de ação, confirmação). A sombra vem
   dos tokens --shadow-* — adapta ao tema claro, que o literal antigo não fazia. */
.app-modal__head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    border-bottom: 1px solid var(--border);
    background: var(--bg-subtle);
}
.app-modal__title {
    flex: 1;
    margin: 0;
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    color: var(--text-emphasis);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.app-modal__panel, .confirm-dialog__panel {
    background: var(--bg-subtle);
    border: 1px solid var(--border);
    border-radius: var(--r-2, 10px);
    box-shadow: var(--shadow-lg);
}

/* =====================================================================
   app-bottom — footer técnico
   ===================================================================== */

.app-bottom {
    height: var(--app-bottom-h);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 0 var(--sp-3);
    background: var(--bg-subtle);
    border-top: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
    color: var(--text-subtle);
    overflow-x: auto;
    white-space: nowrap;
    flex-shrink: 0;
}

.app-bottom__item {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.app-bottom__item[data-status="ok"] { color: var(--text-muted); }

.app-bottom__sep {
    color: var(--text-placeholder);
    user-select: none;
}

/* <768px: o rodapé não cabe numa linha e ganhava scroll lateral. Os itens menos
   críticos (commit, região) e os respetivos separadores saem — fica
   "online · build · CSP". Marcados no template com a variante --optional. */
@media (max-width: 767px) {
    .app-bottom__item--optional,
    .app-bottom__sep--optional {
        display: none;
    }
}

/* Ponto "vivo" do rodapé: componente único .live-dot em main.css (auditoria
   D87) — o template emite class="live-dot app-bottom__dot". */

/* =====================================================================
   Lente de acesso (consolas por papel — ADR-0017)
   Barra de chips (topo do app-main) + sidebar adaptativa ao eixo ativo.
   Tudo CSS estático servido por <link> (sem inline → compatível com a CSP).
   ===================================================================== */

.lens-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
    border-bottom: 1px solid var(--border);
    background: var(--bg-subtle);
    flex-shrink: 0;
}
.lens-bar__label {
    font-weight: var(--fw-semi);
    margin-right: var(--sp-1);
}
.lens-chip {
    display: inline-flex;
    align-items: center;
    padding: var(--sp-1) var(--sp-3);
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    font-size: var(--fs-sm);
    line-height: 1.4;
    color: var(--text);
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease);
}
.lens-chip:hover {
    background: var(--surface-hover);
    color: var(--text-emphasis);
}
.lens-chip:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}
.lens-chip.is-active,
.lens-chip[aria-current="page"] {
    background: var(--accent-tint);
    color: var(--accent-on-tint);
    border-color: var(--accent);
    font-weight: var(--fw-medium);
}

/* Modo Instituição (zona "Instituição" da consola): a casca ganha uma cor FRIA
   PRÓPRIA (--scope-institution, aço dessaturado) — sinaliza que se vê o PROCESSO
   INTEIRO da instituição (a instituição é dona do processo), não só "as minhas".
   Token dedicado em vez de --info: o azul vivo acumulava 3 significados na
   mesma página (âmbito / prioridade normal / ação informativa). O chip ativo
   mantém o accent âmbar (regra única "accent = selecionado") — a faixa já
   sinaliza a zona. Tudo por seletor [data-console-mode]: CSP-safe. */
.app-main[data-console-mode="institution"] {
    box-shadow: inset 0 3px 0 0 var(--scope-institution);
}
.app-main[data-console-mode="institution"] .lens-bar {
    background: var(--scope-institution-tint);
    border-bottom-color: var(--scope-institution);
}

/* Sidebar adaptativa: o grupo "Principal" (eixo mine) fica no topo nas duas
   zonas; o seu título ganha a cor da zona ativa (âmbar em "as minhas",
   --info em "Instituição"). Apresentação pura — nenhum link sai do DOM. */
.app-sidebar nav {
    display: flex;
    flex-direction: column;
}
.app-sidebar__group { order: 2; }
.app-sidebar nav[data-lens="mine"]        [data-axis="mine"],
.app-sidebar nav[data-lens="institution"] [data-axis="mine"] {
    order: 1;
}
.app-sidebar nav[data-lens="mine"]        [data-axis="mine"] > .app-sidebar__group-title {
    color: var(--accent);
}
.app-sidebar nav[data-lens="institution"] [data-axis="mine"] > .app-sidebar__group-title {
    color: var(--scope-institution);
}

/* Pílula de âmbito (ex.: rótulo do feed de auditoria no painel). */
.scope-badge {
    font-weight: var(--fw-semi);
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    padding: 2px var(--sp-2);
    white-space: nowrap;
}

/* =====================================================================
   app-modal — modal de AÇÃO (<dialog> nativo, top-layer)

   Modelo "ação-in-place" (Fase 7): formulários de ação de propósito único
   abertos SOBRE a página atual, sem trocar de janela. A abertura é via
   showModal() em modal-action.js; aqui é só apresentação. CSP-safe (sem
   estilo inline).
   ===================================================================== */
/* Base partilhada dos <dialog> centrais (ação + confirmação): centragem, fundo
   e backdrop numa só fonte (DRY). position:fixed + inset:0 + margin:auto centra
   no top-layer — reintroduz o margin:auto que o reset universal *{margin:0}
   (main.css) remove e sem o qual o <dialog> modal encostaria ao canto superior
   esquerdo. A especificidade de classe (0,1,0) vence o seletor `*` (0,0,0). */
.app-modal,
.confirm-dialog {
    position: fixed;
    inset: 0;
    margin: auto;
    padding: 0;
    border: none;
    background: transparent;
    overflow: visible;
}
.app-modal::backdrop,
.confirm-dialog::backdrop {
    background: rgba(8, 10, 14, 0.62);
    backdrop-filter: blur(2px);
}

/* Modal de AÇÃO — largura proporcional ao ecrã (não ocupa tudo). */
.app-modal {
    width: min(560px, calc(100vw - 2 * var(--sp-4)));
    max-height: calc(100dvh - 2 * var(--sp-6));
}
/* Superfície/cabeçalho/título: no cromado de painel único (auditoria D79). */
.app-modal__panel {
    display: flex;
    flex-direction: column;
    max-height: calc(100dvh - 2 * var(--sp-6));
    isolation: isolate;  /* contém o stacking de mapas Leaflet internos */
    overflow: hidden;
}
.app-modal__head {
    padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
}
/* Receita base em .icon-btn (main.css, auditoria D78) — deltas: compacto + r-1. */
.app-modal__close {
    width: 28px;
    height: 28px;
    border-radius: var(--r-1);
}
.app-modal__close svg { width: 16px; height: 16px; }
.app-modal__body {
    overflow-y: auto;
    padding: var(--sp-4);
    min-height: 0;
}
@media (pointer: coarse) {
    .app-modal__close { width: var(--min-touch); height: var(--min-touch); }
}
/* Em ecrãs pequenos o modal ocupa o ecrã (folha inteira). */
@media (max-width: 560px) {
    .app-modal {
        width: 100vw;
        max-width: 100vw;
        max-height: 100dvh;
        margin: 0;
    }
    .app-modal__panel { max-height: 100dvh; border: none; border-radius: 0; }
}

/* =====================================================================
   Diálogo de CONFIRMAÇÃO (<dialog> nativo central) — decisões de propósito
   único, potencialmente destrutivas (terminar sessão, …). showModal()
   escurece e inativa o resto da página (::backdrop) e prende o foco até o
   utilizador decidir. CSP-safe (sem estilo inline).
   ===================================================================== */
/* Confirmação — cartão estreito centrado (base partilhada acima). */
.confirm-dialog {
    width: min(420px, calc(100vw - 2 * var(--sp-4)));
}
/* Superfície: no cromado de painel único (auditoria D79). */
.confirm-dialog__panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--sp-3);
    padding: var(--sp-6) var(--sp-5) var(--sp-5);
}
.confirm-dialog__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--r-pill);
    background: var(--accent-tint);
    color: var(--accent-on-tint);
}
.confirm-dialog__icon[data-tone="danger"] {
    background: var(--danger-tint);
    color: var(--danger);
}
.confirm-dialog__icon svg { width: 22px; height: 22px; }
.confirm-dialog__title {
    margin: 0;
    font-size: var(--fs-md);
    font-weight: var(--fw-semi);
    color: var(--text-emphasis);
}
.confirm-dialog__text {
    margin: 0;
    max-width: 34ch;
    font-size: var(--fs-sm);
    line-height: 1.5;
    color: var(--text-muted);
}
.confirm-dialog__actions {
    display: flex;
    gap: var(--sp-3);
    width: 100%;
    margin-top: var(--sp-2);
}
.confirm-dialog__actions .btn { flex: 1; }
/* Em ecrã muito estreito empilha: a ação primária (última no DOM) fica em cima. */
@media (max-width: 420px) {
    .confirm-dialog__actions { flex-direction: column-reverse; }
}

/* Seletor de localização no mapa (map-picker.js) — a moldura vem da regra
   única de forensic.css (auditoria D85); aqui só a altura e o overflow. */
.map-picker {
    --map-h: 240px;
    width: 100%;
    overflow: hidden;
}
.map-picker__hint {
    margin: var(--sp-1, 4px) 0 0;
    font-size: var(--fs-xs, 11px);
    color: var(--text-subtle);
}
