/**
 * ForensiQ — Design System (v2 — art direction refactor)
 *
 * Linguagem visual: ferramenta forense profissional — referências em
 * Bloomberg Terminal, IDE em modo debug, Cellebrite / Magnet AXIOM,
 * sala de comando policial. Densidade alta, restrição cromática,
 * monospace abundante, hierarquia por tipografia. NÃO é SaaS Notion/
 * Linear/Vercel (essa era a linguagem da v1 e comunicava errado o domínio).
 *
 * Dois modos: dia (light) e noite (dark, default).
 * Troca via <html data-theme="light">. Sem 'midnight'/'indigo' legacy.
 *
 * Tipografia: IBM Plex Sans (UI) + IBM Plex Mono (hashes, IDs, timestamps
 * forenses). Ambas SIL OFL 1.1. `font-feature-settings` global: "zero" 1
 * (slashed zero — assinatura terminal/forense), "tnum" 1 (tabular numbers
 * para alinhar colunas), "ss05" 1 (alternate Q). Ver
 * art direction e docs/design/login-design-credits.md.
 *
 * Accent: amber (#F6AD55 dark / #B45309 light) — quente, denso, forense.
 * O teal de v1 era da paleta Vercel e descontextualizava o produto.
 *
 * Mobile-first com edge-to-edge (<768px): sem padding lateral no container,
 * cards full-bleed sem border radius nos extremos.
 *
 * Respeita CSP estrita (sem inline styles nos templates).
 */

/* ============================================================
   1. DESIGN TOKENS
   ============================================================ */

:root {
    /* ---- Estrutura ---- */
    --r-1: 4px;           /* inputs, chips pequenos */
    --r-2: 6px;           /* botões, chips */
    --r-3: 8px;           /* cards */
    --r-4: 12px;          /* modais, blocos grandes */
    --r-pill: 999px;

    --sp-0: 0;
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 20px;
    --sp-6: 24px;
    --sp-8: 32px;
    --sp-10: 40px;
    --sp-12: 48px;
    --sp-16: 64px;

    --min-touch: 44px;          /* Apple HIG / uso com luvas */
    --min-touch-lg: 52px;       /* acções primárias */

    /* Navbar — tokens para alinhamento sticky (sidebar, wizards, etc).
       Aliasados ao token único da casca (--app-top-h, definido em app-shell.css)
       para que os offsets sticky herdem a altura real do header (52px) em vez
       de assumirem 56/60px. O fallback cobre páginas que não carregam a casca. */
    --navbar-h:          var(--app-top-h, 52px);  /* mobile */
    --navbar-h-desktop:  var(--app-top-h, 52px);  /* >=768px */

    /* ---- Tipografia ---- */
    --font-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
                 Roboto, 'Helvetica Neue', Arial, sans-serif;
    --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', 'Cascadia Mono',
                 Consolas, 'Courier New', monospace;

    /* Escala base 16px — apropriada para uso em campo (First Responders,
       luz variável, stress, luvas). 12px reservado apenas para chips/badges. */
    --fs-xs:   0.8125rem;  /* 13px — form hints, meta */
    --fs-sm:   0.875rem;   /* 14px — labels, subtitle */
    --fs-base: 1rem;       /* 16px — body */
    --fs-md:   1.0625rem;  /* 17px — body emphasized */
    --fs-lg:   1.125rem;   /* 18px — card titles */
    --fs-xl:   1.375rem;   /* 22px — section headings */
    --fs-2xl:  1.75rem;    /* 28px — page headings */
    --fs-3xl:  2.25rem;    /* 36px — big numbers */
    --fs-micro: 0.75rem;   /* 12px — apenas chips/badges compactos */
    --fs-2xs:   10px;      /* micro-rótulos mono uppercase (auditoria D83) */

    --lh-tight: 1.25;
    --lh-snug:  1.4;
    --lh-base:  1.55;      /* body */
    --lh-loose: 1.7;

    --fw-normal: 400;
    --fw-medium: 500;
    --fw-semi:   600;
    --fw-bold:   700;

    --tracking-tight:  -0.011em;   /* headings — assinatura Notion */
    --tracking-normal: 0;
    --tracking-wide:   0.04em;     /* labels maiúsculas */

    /* ---- Transições ---- */
    --t-fast: 120ms;
    --t-base: 180ms;
    --t-slow: 280ms;
    --ease:   cubic-bezier(0.2, 0, 0, 1);
}

/* -------------------------
   Tema NOITE (default)
   -------------------------
   Paleta dark neutra, ligeiramente fria (ligeiro matiz azul). Evita preto
   puro (#000) — cansa menos a vista e dá sensação de superfície real.
*/
:root,
[data-theme="dark"] {
    color-scheme: dark;

    --bg:              #0F1115;
    --bg-subtle:       #14171C;
    --bg-inset:        #0A0C10;
    --surface:         #181B21;
    --surface-hover:   #1F2229;
    --surface-active:  #23272F;
    --surface-elevated:#22262E;

    --text:            #E6E8EC;
    --text-emphasis:   #F4F5F7;
    --text-muted:      #9AA0A6;
    /* clareado de #6E737C (≈3.9:1 sobre as superfícies escuras, abaixo de AA)
       para ≈5.2:1 sobre --surface, mantendo-se mais discreto que --text-muted. */
    --text-subtle:     #8A8F98;
    --text-placeholder:#52575E;
    --text-inverse:    #0F1115;

    --border:          rgba(255, 255, 255, 0.07);
    --border-strong:   rgba(255, 255, 255, 0.13);
    --border-input:    rgba(255, 255, 255, 0.10);
    --divider:         rgba(255, 255, 255, 0.06);

    /* Accent — amber forense (#F6AD55). Quente, Bloomberg-adjacent.
       Substitui o teal Vercel de v1. Ver a especificação de art direction §Paleta. */
    --accent:          #F6AD55;
    --accent-hover:    #FBD38D;
    --accent-strong:   #D69E2E;
    --accent-tint:     rgba(246, 173, 85, 0.14);
    --accent-tint-hover: rgba(246, 173, 85, 0.20);
    --on-accent:       #1A1004;
    /* Texto âmbar SOBRE a tinta âmbar (chips, avatar). No escuro o âmbar vivo
       já contrasta de sobra com a tinta; no claro é escurecido (ver tema dia). */
    --accent-on-tint:  #F6AD55;

    --warning:         #F59E0B;
    --warning-strong:  #D97706;
    --warning-tint:    rgba(245, 158, 11, 0.14);

    --danger:          #F87171;
    --danger-strong:   #DC2626;
    --danger-tint:     rgba(239, 68, 68, 0.14);

    --success:         #34D399;
    --success-strong:  #059669;
    --success-tint:    rgba(16, 185, 129, 0.14);

    --info:            #60A5FA;
    --info-tint:       rgba(96, 165, 250, 0.14);

    /* ---- Prioridade processual (P1 lei / P2 manual / normal) ----------
       A prioridade NÃO usa cor: o hue é exclusivo da família ESTADO
       (core/labels.py → .state--*). Distingue-se por PESO — .pri/.urgency-dot
       (cheio P1 / contorno P2 / nada) e os pinos do mapa (priStyle() em
       forensic-list.js: cheio âmbar / anel / ponto esmaecido). Por isso não há
       tokens de cor de prioridade. NOTA: nunca escrever um glob com
       asterisco-barra num comentário CSS — fecha o comentário a meio e o
       parser engole a declaração seguinte. */

    /* Zona "Instituição" da consola — aço dessaturado PRÓPRIO, distinto de
       --info: o azul vivo ficava com 3 significados na mesma página (âmbito
       institucional / prioridade normal / ação informativa do feed). */
    --scope-institution:      #8AA2C0;
    --scope-institution-tint: rgba(138, 162, 192, 0.14);

    /* Anel de foco SÓLIDO (indicador não-textual exige >=3:1 — o translúcido
       compunha para ~2.7:1 no escuro e ~1.5:1 no claro); o halo translúcido
       fica só para o box-shadow dos inputs (--focus-halo). */
    --focus-ring:      var(--accent);
    --focus-halo:      rgba(246, 173, 85, 0.40);
    --selection-bg:    rgba(246, 173, 85, 0.28);
    --selection-text:  #E6E8EC;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.32);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.32), 0 1px 2px rgba(0, 0, 0, 0.20);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.44), 0 2px 6px rgba(0, 0, 0, 0.24);

    /* Features tipográficas forenses (zero riscado + dígitos tabulares) — fonte
       única do literal antes repetido 9× entre folhas (auditoria D82). */
    --ffs-forensic: "zero" 1, "tnum" 1;

    --scrollbar-thumb: rgba(255, 255, 255, 0.10);
    --scrollbar-thumb-hover: rgba(255, 255, 255, 0.18);
}

/* -------------------------
   Tema DIA
   -------------------------
   Off-white quente (#FAFAF9) — apoia o accent amber em vez do off-white
   neutro Notion. Texto `#37352F` (alto contraste). Accent amber é
   escurecido (`#B45309`, amber-700) para manter contraste WCAG AA
   sobre fundo claro (5.8:1).
*/
[data-theme="light"] {
    color-scheme: light;

    --bg:              #FAFAF9;
    --bg-subtle:       #F4F3EF;
    --bg-inset:        #EFEEE9;
    --surface:         #FFFFFF;
    --surface-hover:   #F7F6F3;
    --surface-active:  #F0EFEC;
    --surface-elevated:#FFFFFF;

    --text:            #37352F;
    --text-emphasis:   #1F1E1A;
    /* Dois níveis de texto secundário, AMBOS ≥4.5:1 (WCAG AA), também sobre os
       fundos tintados (--bg-subtle/--bg-inset). A hierarquia mantém-se por
       muted ser mais escuro que subtle (e por tamanho/peso), não por descer
       abaixo de AA. Antes: muted #6E6D6A ficava no limite em fundos tintados e
       subtle #9B9A97 falhava (≈2.6:1) — usado por .form-hint, contagens, etc. */
    --text-muted:      #5C5A55;   /* ≈6:1 sobre #FAFAF9; AA mesmo em --bg-inset */
    --text-subtle:     #6B6A64;   /* ≈4.9:1 sobre #FAFAF9; ≈4.6:1 em --bg-subtle */
    --text-placeholder:#8C887F;   /* legível (≈3:1) sem parecer campo preenchido */
    --text-inverse:    #FAFAF9;

    --border:          rgba(55, 53, 47, 0.09);
    --border-strong:   rgba(55, 53, 47, 0.18);
    --border-input:    rgba(55, 53, 47, 0.14);
    --divider:         rgba(55, 53, 47, 0.08);

    /* Accent — amber-700 (#B45309). 5.8:1 sobre #FAFAF9 → WCAG AA. */
    --accent:          #B45309;
    --accent-hover:    #92400E;
    --accent-strong:   #78350F;
    --accent-tint:     rgba(180, 83, 9, 0.10);
    --accent-tint-hover: rgba(180, 83, 9, 0.14);
    --on-accent:       #FFFFFF;
    /* Texto âmbar SOBRE a tinta âmbar: o --accent (#B45309) só dá ≈3.97:1 sobre
       a tinta (chips/avatar). Este tom escurecido dá ≈5.6:1 e mantém o âmbar. */
    --accent-on-tint:  #92400E;

    /* Warning destacado do accent (amber-600 #D97706) para que P2/aviso não
       colida com botões/marca (--accent #B45309). */
    --warning:         #D97706;
    --warning-strong:  #B45309;
    --warning-tint:    rgba(217, 119, 6, 0.12);

    --danger:          #B91C1C;
    --danger-strong:   #991B1B;
    --danger-tint:     rgba(185, 28, 28, 0.08);

    --success:         #047857;
    --success-strong:  #065F46;
    --success-tint:    rgba(4, 120, 87, 0.08);

    --info:            #1D4ED8;
    --info-tint:       rgba(29, 78, 216, 0.08);

    --scope-institution:      #475569;
    --scope-institution-tint: rgba(71, 85, 105, 0.10);

    --focus-ring:      var(--accent);
    --focus-halo:      rgba(180, 83, 9, 0.28);
    --selection-bg:    rgba(180, 83, 9, 0.18);
    --selection-text:  #4A2700;

    --shadow-sm: 0 1px 2px rgba(15, 15, 15, 0.06);
    --shadow-md: 0 2px 8px rgba(15, 15, 15, 0.08), 0 1px 2px rgba(15, 15, 15, 0.04);
    --shadow-lg: 0 12px 32px rgba(15, 15, 15, 0.14), 0 2px 4px rgba(15, 15, 15, 0.06);

    --scrollbar-thumb: rgba(55, 53, 47, 0.18);
    --scrollbar-thumb-hover: rgba(55, 53, 47, 0.32);
}

/* ============================================================
   2. RESET & BASE
   ============================================================ */

*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* Atributo hidden HTML5 — garantir que ganha sempre a `display:flex/grid`
   das classes de componentes (occurrence_detail, wizard, modais). Evita
   bugs em que o JS faz `el.hidden = true` mas o CSS ignora. */
[hidden] {
    display: none !important;
}

html {
    font-size: 16px;
    -webkit-text-size-adjust: 100%;
    -webkit-tap-highlight-color: transparent;
    background: var(--bg);
}

body {
    font-family: var(--font-sans);
    font-size: var(--fs-base);
    font-weight: var(--fw-normal);
    line-height: var(--lh-base);
    color: var(--text);
    background: var(--bg);
    min-height: 100vh;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    /* IBM Plex font-features:
       - "zero" 1 → slashed zero (assinatura terminal/forense, evita ambiguidade 0/O)
       - "tnum" 1 → tabular numbers (alinha colunas, hashes, timestamps)
       - "ss05" 1 → stylistic set 5 (alternate Q, mais densa) */
    font-feature-settings: "zero" 1, "tnum" 1, "ss05" 1;
}

img, svg, video {
    display: block;
    max-width: 100%;
}

button, input, select, textarea {
    font: inherit;
    color: inherit;
}

a {
    color: var(--accent);
    text-decoration: none;
    transition: color var(--t-fast) var(--ease);
}

a:hover {
    color: var(--accent-hover);
}

::selection {
    background: var(--selection-bg);
    color: var(--selection-text);
}

/* Scrollbars — fino, Notion-like */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) transparent;
}

*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-track {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: var(--r-pill);
    border: 2px solid transparent;
    background-clip: content-box;
}

*::-webkit-scrollbar-thumb:hover {
    background: var(--scrollbar-thumb-hover);
    background-clip: content-box;
}

/* Focus rings — consistentes em toda a app */
:focus {
    outline: none;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--r-1);
}

/* Tipografia — elementos nativos */
h1, h2, h3, h4, h5, h6 {
    font-weight: var(--fw-semi);
    line-height: var(--lh-tight);
    letter-spacing: var(--tracking-tight);
    color: var(--text-emphasis);
}

h1 { font-size: var(--fs-2xl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }

p { line-height: var(--lh-base); }

code, kbd, samp {
    font-family: var(--font-mono);
    font-variant-ligatures: none;
    font-size: 0.92em;
}

/* Utilitário .mono canónico (auditoria D82): semântica forense única — antes
   havia duas definições concorrentes (aqui e em forensic.css), decididas pela
   ordem de carregamento. */
.mono {
    font-family: var(--font-mono);
    font-variant-ligatures: none;
    font-variant-numeric: tabular-nums;
    font-feature-settings: var(--ffs-forensic);
    font-size: 0.92em;
}

hr {
    border: none;
    border-top: 1px solid var(--divider);
    margin: var(--sp-4) 0;
}

/* ============================================================
   3. LAYOUT — container edge-to-edge no mobile
   ============================================================ */

/* Edge-to-edge no mobile; a partir de ≥768px ganha padding mas ocupa toda a
   largura da coluna principal — as páginas adaptam-se a monitores grandes em
   vez de ficarem fixas/centradas (era 1160px, 1360px em ≥1440px). Aplica o
   sentido do audit #21: padding no container, sem cap de largura. */
.container {
    width: 100%;
    padding: 0;
    margin: 0;
}

@media (min-width: 768px) {
    .container {
        padding: var(--sp-6) var(--sp-6);
    }
}

/* Layout de página — espaço vertical uniforme entre secções */
.page {
    display: flex;
    flex-direction: column;
    gap: var(--sp-6);
    padding-top: var(--sp-4);
    padding-bottom: var(--sp-16);
}

@media (min-width: 768px) {
    .page {
        padding-top: 0;
        gap: var(--sp-8);
    }
}

/* ============================================================
   4. NAVBAR
   ============================================================ */

/* Breadcrumb — path de navegação. No desktop mostra a hierarquia completa.
   No mobile (<768px) o breadcrumb completo não cabe na navbar; é substituído
   por um único pill "← Voltar a {parent}" — UX adequada para o contexto de
   first-responder (operação rápida, possivelmente com luvas). */
.breadcrumb {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    min-width: 0;
    overflow: hidden;
}

.breadcrumb a {
    color: var(--text-muted);
    text-decoration: none;
    padding: var(--sp-1) var(--sp-2);
    border-radius: var(--r-2);
    white-space: nowrap;
    transition: background var(--t-fast) var(--ease);
}

.breadcrumb a:hover {
    background: var(--surface-hover);
    color: var(--text);
}

@media (max-width: 767px) {
    /* Mantém apenas o último link (parent imediato) como botão "voltar". */
    .breadcrumb a:not(:last-of-type),
    .breadcrumb .breadcrumb-sep,
    .breadcrumb .breadcrumb-current {
        display: none;
    }

    .breadcrumb a:last-of-type {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        padding: 6px 10px;
        background: var(--surface);
        border: 1px solid var(--border);
        color: var(--text);
        min-height: 36px;
    }

    .breadcrumb a:last-of-type::before {
        content: '';
        width: 14px;
        height: 14px;
        flex-shrink: 0;
        background-color: currentColor;
        -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m15 18-6-6 6-6'/></svg>") no-repeat center / contain;
        mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m15 18-6-6 6-6'/></svg>") no-repeat center / contain;
    }

    /* Quando o breadcrumb fica vazio (página raiz ex.: /dashboard/), oculta-o. */
    .breadcrumb:not(:has(a)) {
        display: none;
    }
}

/* Breadcrumb separator — chevron SVG via mask. O texto interno (/, ›)
   é mantido por compatibilidade mas não é mostrado (color:transparent +
   font-size:0). Linguagem visual unificada com o resto do design system. */
.breadcrumb-sep {
    display: inline-flex;
    align-self: center;
    flex-shrink: 0;
    width: 14px;
    height: 14px;
    color: transparent;
    font-size: 0;
    line-height: 0;
    background-color: var(--text-subtle);
    -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m9 18 6-6-6-6'/></svg>") no-repeat center / contain;
    mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m9 18 6-6-6-6'/></svg>") no-repeat center / contain;
    opacity: 0.7;
}

.breadcrumb-current {
    color: var(--text);
    font-weight: var(--fw-medium);
    padding: var(--sp-1) var(--sp-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Icon-only button — usado na navbar (theme toggle, user menu trigger) */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--r-2);
    color: var(--text-muted);
    cursor: pointer;
    transition: all var(--t-fast) var(--ease);
}

.icon-btn:hover {
    background: var(--surface-hover);
    color: var(--text);
}

.icon-btn:active {
    background: var(--surface-active);
}

/* Foco próprio, alinhado com os restantes controlos da casca
   (.app-top__nav-toggle): outline-offset negativo para o
   anel ficar contido dentro do strip sticky e não ser cortado. */
.icon-btn:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}

.icon-btn svg {
    width: 18px;
    height: 18px;
}

/* User menu na navbar */
.user-menu {
    position: relative;
}

.user-menu-trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-1);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--r-2);
    color: var(--text);
    cursor: pointer;
    transition: all var(--t-fast) var(--ease);
}

/* Intenção destrutiva: ao apontar, o controlo tinge-se de perigo (sem alarmar
   em repouso). A etiqueta e o ícone seguem currentColor; o avatar mantém o
   seu tom de acento. */
.user-menu-trigger:hover {
    background: var(--danger-tint);
    color: var(--danger);
}

/* Alvo de toque mínimo (44px, HIG / uso com luvas) em apontadores grosseiros —
   alinha o theme-toggle e o trigger de utilizador com os irmãos da casca
   (.app-top__nav-toggle) que já recebem este upgrade. */
/* Alvo de toque ÚNICO dos botões-ícone (auditoria D78): min-* em vez de
   width/height para vencer as dimensões próprias de cada consumidor da casca
   (nav-toggle 40, …) independentemente da ordem das folhas. */
@media (pointer: coarse) {
    .icon-btn {
        min-width: var(--min-touch);
        min-height: var(--min-touch);
    }
    .user-menu-trigger {
        min-height: var(--min-touch);
    }
}

.user-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: var(--r-pill);
    background: var(--accent-tint);
    color: var(--accent-on-tint);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semi);
    letter-spacing: 0.02em;
}

.user-menu-label {
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    white-space: nowrap;
}

/* Em ecrã estreito fica só o avatar + ícone; o aria-label do trigger mantém a
   ação anunciada a leitores de ecrã. */
@media (max-width: 639px) {
    .user-menu-label { display: none; }
}

/* ============================================================
   5. BUTTONS
   ============================================================ */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-height: var(--min-touch);
    padding: 0 var(--sp-5);
    font-size: var(--fs-base);
    font-weight: var(--fw-medium);
    line-height: 1;
    letter-spacing: -0.005em;
    border: 1px solid transparent;
    border-radius: var(--r-2);
    cursor: pointer;
    transition: background var(--t-fast) var(--ease),
                border-color var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease),
                transform var(--t-fast) var(--ease);
    text-decoration: none;
    white-space: nowrap;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.btn:active:not(:disabled) {
    transform: scale(0.98);
}

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

.btn svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* Variantes */
.btn-primary {
    background: var(--accent);
    color: var(--on-accent);
    border-color: var(--accent);
}

.btn-primary:hover:not(:disabled) {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
}

/* Modificador do sistema .btn LEGADO (diálogos da casca, 404/500, login).
   Composto .btn.btn-ghost para nunca disputar a cascata com o .btn-ghost
   standalone de forensic.css — donos distintos, explícitos (auditoria D81). */
.btn.btn-ghost {
    background: transparent;
    color: var(--text);
    border-color: var(--border-strong);
}

.btn.btn-ghost:hover:not(:disabled) {
    background: var(--surface-hover);
    border-color: var(--border-strong);
}

/* Ação destrutiva (terminar sessão, eliminar) — vermelho sólido, texto claro. */
.btn-danger {
    background: var(--danger-strong);
    color: #fff;
    border-color: var(--danger-strong);
}

.btn-danger:hover:not(:disabled) {
    background: var(--danger);
    border-color: var(--danger);
}

/* Tamanhos */
.btn-lg {
    min-height: var(--min-touch-lg);
    padding: 0 var(--sp-6);
    font-size: var(--fs-md);
    font-weight: var(--fw-semi);
}

.btn-block {
    width: 100%;
}

/* ============================================================
   6. FORMS
   ============================================================ */

.form-group {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin-bottom: var(--sp-4);
}

.form-label {
    display: block;
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    color: var(--text);
    margin-bottom: 0;
}

.form-label.required::after {
    content: ' *';
    color: var(--danger);
    font-weight: var(--fw-bold);
}

.form-input,
select.form-input,
textarea.form-input {
    width: 100%;
    min-height: var(--min-touch);
    padding: var(--sp-3) var(--sp-3);
    font-size: var(--fs-base);
    font-family: inherit;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-input);
    border-radius: var(--r-2);
    transition: border-color var(--t-fast) var(--ease),
                box-shadow var(--t-fast) var(--ease),
                background var(--t-fast) var(--ease);
    -webkit-appearance: none;
    appearance: none;
}

.form-input:hover:not(:focus):not(:disabled) {
    border-color: var(--border-strong);
}

.form-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--focus-halo);
}

.form-input::placeholder,
textarea.form-input::placeholder {
    color: var(--text-placeholder);
}

.form-input.error {
    border-color: var(--danger);
}

.form-input.error:focus {
    box-shadow: 0 0 0 3px var(--danger-tint);
}

/* Chevron do select. Um <select> nativo não aceita pseudo-elementos fiáveis nem
   recoloração da seta por mask (a mask recortaria também o texto/superfície do
   campo), por isso a seta continua a ser um background-image data-URI. Para
   eliminar o drift de cor (data-URIs não aceitam var()), a cor passa a estar
   centralizada num único token por tema — --select-arrow — derivado de
   --text-muted. Há só UM sítio a actualizar por tema se o token mudar, em vez de
   dois hex espalhados pela regra. */
:root,
[data-theme="dark"] {
    /* seta = --text-muted (#9AA0A6) */
    --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%239AA0A6' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}

[data-theme="light"] {
    /* seta = --text-muted (#6E6D6A) */
    --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236E6D6A' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}

select.form-input {
    background-image: var(--select-arrow);
    background-repeat: no-repeat;
    background-position: right var(--sp-3) center;
    padding-right: var(--sp-10);
}

textarea.form-input {
    min-height: 104px;
    padding: var(--sp-3);
    resize: vertical;
    line-height: var(--lh-base);
}

/* .form-hint / .form-error(.visible) / .form-actions: dono ÚNICO em
   forensic.css (auditoria D81) — desde que o forensic.css passou a carregar
   sempre na casca (D67), as definições daqui estavam mortas em todas as
   páginas com formulários. O login mantém o seu .lp-error próprio (animado). */

/* ============================================================
   11. TOASTS
   ============================================================ */

.toast-container {
    position: fixed;
    top: calc(var(--sp-4) + env(safe-area-inset-top));
    left: 50%;
    transform: translateX(-50%);
    z-index: 100;
    width: calc(100% - var(--sp-8));
    max-width: 420px;
    pointer-events: none;
}

@media (min-width: 768px) {
    .toast-container {
        top: calc(var(--navbar-h-desktop) + var(--sp-4) + env(safe-area-inset-top));
    }
}

.toast {
    pointer-events: auto;
    background: var(--surface-elevated);
    color: var(--text);
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--border);
    border-radius: var(--r-3);
    margin-bottom: var(--sp-2);
    font-size: var(--fs-sm);
    box-shadow: var(--shadow-lg);
    animation: toast-in 0.25s var(--ease);
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
}

.toast.success { border-left: 3px solid var(--success); }
.toast.error,
.toast.danger  { border-left: 3px solid var(--danger); }
.toast.warning { border-left: 3px solid var(--warning); }
.toast.info    { border-left: 3px solid var(--info); }

@keyframes toast-in {
    from { opacity: 0; transform: translateY(-12px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
   12. SPINNERS / LOADING / SKELETONS
   ============================================================ */

.spinner {
    display: inline-block;
    width: 20px;
    height: 20px;
    border: 2px solid var(--border-strong);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    flex-shrink: 0;
}

/* @keyframes ÚNICO de rotação (auditoria D86) — consumido também pelo
   .toolbar__busy de forensic.css (antes havia um fq-spin idêntico). */
@keyframes spin {
    to { transform: rotate(360deg); }
}

/* Ponto de estado "vivo" pulsante (rodapé da casca + login) — componente único
   (auditoria D87); o guard de reduced-motion existe só aqui. */
.live-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--success);
    flex-shrink: 0;
}
@media (prefers-reduced-motion: no-preference) {
    .live-dot { animation: live-pulse 2.4s ease-in-out infinite; }
    @keyframes live-pulse {
        0%, 100% { opacity: 0.6; transform: scale(0.9); }
        50%      { opacity: 1;   transform: scale(1.05); }
    }
}

/* ============================================================
   13. SKIP-LINK (a11y) — fonte única (auditoria D80): carregada por TODOS os
   documentos (casca, 500.html standalone e páginas públicas); antes clonado
   em app-shell.css e error.css.
   ============================================================ */

.skip-link {
    position: absolute;
    left: -10000px;
    top: 0;
    z-index: 200;
    padding: var(--sp-2) var(--sp-4);
    background: var(--accent);
    color: var(--on-accent);
    font-weight: var(--fw-semi);
    border-radius: 0 0 var(--r-2) 0;
}
.skip-link:focus {
    left: 0;
}

/* ============================================================
   14. MAIN content + FAB spacing
   ============================================================ */

main {
    min-height: calc(100dvh - var(--navbar-h));
    padding-bottom: env(safe-area-inset-bottom);
}

@media (min-width: 768px) {
    main {
        min-height: calc(100dvh - var(--navbar-h-desktop));
    }
}

/* ============================================================
   15. UTILITIES
   ============================================================ */

.hidden { display: none !important; }
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
}

/* Utilitários pontuais ainda em uso (CSP-safe, substituem style="") */
.text-subtle { color: var(--text-subtle); }
.justify-center { justify-content: center; }

/* NOTA: a .toolbar legada v1 (flex-direction:column + .toolbar-search/.toolbar-actions)
   foi removida — colidia com a .toolbar densa de components/forensic.css (mesma
   especificidade, resultado dependente da ordem de carregamento). Nenhum template
   usa as classes legadas; a toolbar real é a de forensic.css. */

/* ============================================================
   19. REDUCED MOTION
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}
