/* ==========================================================================
   GERENCIADOR DE DOCUMENTOS — CSS Framework 
   Arquivo único. Nunca usar style inline.
   Ao criar novos estilos, sempre reutilizar classes existentes.
   Só criar algo novo se for de extrema necessidade.

   Índice:
    1.  Fontes
    2.  Design Tokens (tema padrão: green)
    3.  Temas alternativos (blue, violet, slate)
    4.  Dark mode
    5.  Base reset
    6.  Overlay (sidebar mobile)
    7.  Layout — App Shell
    8.  Sidebar
    9.  Sidebar colapsada
   10.  Sidebar mobile (drawer)
   11.  Navegação
   12.  Topbar
   13.  Searchbox
   14.  Icon button
   15.  User menu
   16.  Buttons
   17.  Forms
   18.  Cards
   19.  Badges
   20.  Alertas
   21.  Tabelas
   22.  Page header
   23.  Grids de conteúdo
   24.  Login
   25.  Table toolbar & paginação
   26.  Utilitários
   27.  Configurações (tema + switch)
   28.  Modal
   29.  Responsivo
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. FONTES — auto-hospedadas em wwwroot/fonts, sem CDN externo (ver
   wwwroot/css/CLAUDE.md "Fontes carregadas"). Só os subconjuntos latin/
   latin-ext do Inter (cobrem tudo que o app pt-BR precisa — acentuação,
   cedilha etc. já estão no Latin-1 Supplement; cyrillic/greek/vietnamese do
   Google Fonts nunca são usados aqui, app é só português) e uma única
   instância estática do Material Symbols Rounded, mesmos eixos fixos que o
   @import antigo pedia (opsz=24, wght=400, FILL=0, GRAD=0). Arquivos
   baixados uma vez de fonts.gstatic.com — não têm versão automática/
   atualização, trocar manualmente (mesmos nomes de arquivo) se precisar.
   -------------------------------------------------------------------------- */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url('/fonts/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url('/fonts/inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Material Symbols Rounded';
    font-style: normal;
    font-weight: 400;
    src: url('/fonts/material-symbols-rounded.woff2') format('woff2');
}

/* Regra base da ligadura de ícone — antes vinha embutida na resposta do
   @import do Google Fonts junto com o @font-face acima; precisa continuar
   existindo aqui agora que o @import saiu, senão todo ícone do app (span
   com o nome do ícone como texto) para de virar glifo. */
.material-symbols-rounded {
    font-family: 'Material Symbols Rounded';
    font-weight: normal;
    font-style: normal;
    font-size: 24px;
    line-height: 1;
    letter-spacing: normal;
    text-transform: none;
    display: inline-block;
    white-space: nowrap;
    word-wrap: normal;
    direction: ltr;
    -webkit-font-feature-settings: 'liga';
    -webkit-font-smoothing: antialiased;
}

/* --------------------------------------------------------------------------
   2. DESIGN TOKENS — tema padrão (green)
   Nunca usar valores de cor, espaçamento ou raio fora destas variáveis.
   -------------------------------------------------------------------------- */
:root {
    /* Superfícies */
    --color-bg:             #f5f7f4;
    --color-surface:        #ffffff;
    --color-surface-strong: #eef4ec;
    --color-text:           #172016;
    --color-text-muted:     #657064;
    --color-border:         #dfe7dc;

    /* Brand — sobrescrito por cada tema */
    --color-brand:        #246b43;
    --color-brand-strong: #164f31;
    --color-brand-soft:   #e4f4ea;
    --sidebar-from:       #0f3320;
    --sidebar-to:         #1a5535;
    --focus-ring:         rgba(36, 107, 67, .22);
    --color-brand-ghost:  rgba(36, 107, 67, .07);

    /* Semânticas */
    --color-danger:       #b42318;
    --color-danger-soft:  #fee4e2;
    --focus-ring-danger:  rgba(180, 35, 24, .22);
    --color-warning:        #b54708;
    --color-warning-soft:   #fef0c7;
    --focus-ring-warning:   rgba(181, 71, 8, .22);
    --color-success:     #027a48;
    --color-success-soft: #dcfae6;

    /* Validação de campo — vermelho no tema claro, amarelo/âmbar no dark
       (ver html.dark abaixo). Não usar --color-danger direto em campo de
       formulário; usar sempre estas variáveis. */
    --color-validation:      var(--color-danger);
    --color-validation-soft: var(--color-danger-soft);
    --focus-ring-validation: var(--focus-ring-danger);

    /* Sombras */
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, .07);
    --shadow-md: 0 4px 14px rgba(0, 0, 0, .09);
    --shadow-lg: 0 20px 50px rgba(0, 0, 0, .13);

    /* Raios */
    --radius-sm:   8px;
    --radius-md:  12px;
    --radius-lg:  20px;
    --radius-full: 999px;

    /* Tipografia — usados nos campos de formulário (label/input/input-sm) */
    --font-size-xs:  11px;
    --font-size-sm:  12px;

    /* Espaçamentos (escala 4 px) */
    --sp-1:  4px;
    --sp-2:  8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 20px;
    --sp-6: 24px;
    --sp-8: 32px;

    /* Estrutura */
    --sidebar-width:           260px;
    --sidebar-collapsed-width:  72px;
    --topbar-height:            54px;

    /* Transições */
    --transition:      140ms ease;
    --transition-slow: 220ms ease;

    /* Fundo decorativo (horizonte) — pedido explícito: um plano de fundo
       "muito leve" pra todas as páginas, reaproveitando o mesmo desenho já
       aprovado da carteira de sócio (colinas + sol nascente — ver
       RelatorioCarteiraSocioPdfService.cs, CampoInferiorSvg/SolCampoSvg).
       SVG inline (não PNG) de propósito — ~1,7KB de texto ao todo, direto
       neste arquivo, sem requisição HTTP extra nenhuma e sem perda de
       nitidez em qualquer resolução/zoom. Fixo (não tem tema por cor — é
       uma paisagem, não um elemento de UI, então não varia com os 25
       data-theme abaixo).

       DUAS camadas separadas (não um SVG só) — primeira tentativa combinava
       sol+colinas num único desenho com `background-size: auto <alturaPx>`,
       só que aí a largura ficava travada na proporção original (856:540) e
       a imagem inteira só ocupava uns 500px, presa no canto em vez de
       esticar pela tela (bug real, já reportado). As colinas (onda solta,
       sem forma "sensível" — esticar levemente uma onda não incomoda o
       olho) podem ir `width:100%` sem problema; o sol (círculo) não pode
       esticar do mesmo jeito, senão vira uma elipse. Solução: 2 imagens de
       fundo (CSS aceita várias, separadas por vírgula) — colinas esticam
       100% da largura, sol escala só como quadrado (mantém o círculo).
       `preserveAspectRatio="none"` nas colinas é o que permite o SVG
       obedecer um `background-size` com proporção diferente da original em
       vez de aplicar letterbox por conta própria. */
    --bg-horizon-hills: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4NTYgMzAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIj4KICA8cGF0aCBkPSJNMCw1NiBDMTYwLDMwIDI2MCw3MCA0MjAsNDAgQzU2MCwxNCA2NjAsNTAgODU2LDQiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjN0ZBODc4IiBzdHJva2Utb3BhY2l0eT0iMC4xNCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KICA8cGF0aCBkPSJNMCw5OCBDMTUwLDYwIDI2MCwxMDAgNDIwLDY0IEM1NjAsMzIgNjgwLDc4IDg1NiwzMCBMODU2LDMwMCBMMCwzMDAgWiIKICAgICAgICBmaWxsPSIjOUZDNzlBIiBmaWxsLW9wYWNpdHk9IjAuMTQiIC8+CiAgPHBhdGggZD0iTTAsOTggQzE1MCw2MCAyNjAsMTAwIDQyMCw2NCBDNTYwLDMyIDY4MCw3OCA4NTYsMzAiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNkU5QzY4IiBzdHJva2Utb3BhY2l0eT0iMC4yNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+CiAgPHBhdGggZD0iTTAsMTc2IEMxNzAsMTI4IDMwMCwxNzIgNDYwLDEyOCBDNjAwLDkwIDcyMCwxNDIgODU2LDk2IEw4NTYsMzAwIEwwLDMwMCBaIgogICAgICAgIGZpbGw9IiM3RkIzNzQiIGZpbGwtb3BhY2l0eT0iMC4xOSIgLz4KICA8cGF0aCBkPSJNMCwxNzYgQzE3MCwxMjggMzAwLDE3MiA0NjAsMTI4IEM2MDAsOTAgNzIwLDE0MiA4NTYsOTYiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNEM4QzQ2IiBzdHJva2Utb3BhY2l0eT0iMC4yOCIgc3Ryb2tlLXdpZHRoPSIyLjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KICA8cGF0aCBkPSJNMCwyNTggQzE5MCwyMDAgMzQwLDI1MiA1MDAsMjAyIEM2NTAsMTU4IDc2MCwyMTggODU2LDE2OCBMODU2LDMwMCBMMCwzMDAgWiIKICAgICAgICBmaWxsPSIjNEM5QTRGIiBmaWxsLW9wYWNpdHk9IjAuMjMiIC8+CiAgPHBhdGggZD0iTTAsMjU4IEMxOTAsMjAwIDM0MCwyNTIgNTAwLDIwMiBDNjUwLDE1OCA3NjAsMjE4IDg1NiwxNjgiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMkU3RDMyIiBzdHJva2Utb3BhY2l0eT0iMC4zMCIgc3Ryb2tlLXdpZHRoPSIyLjQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KPC9zdmc+Cg==");
    --bg-horizon-sun: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MCA2MCI+CiAgPGNpcmNsZSBjeD0iMzAiIGN5PSIzMCIgcj0iMjYiIGZpbGw9IiNGNEM3NjYiIGZpbGwtb3BhY2l0eT0iMC4zMiIgLz4KPC9zdmc+Cg==");

    /* Brilho difuso ao redor do disco do sol — só a tela de login usa (ver
       seção 24). É uma COR, não um SVG, porque quem desenha o halo é um
       `radial-gradient` do próprio CSS: o sol de --bg-horizon-sun é um
       círculo de borda dura, e esfumaçar dentro do SVG exigiria um
       <radialGradient> próprio (mais bytes no base64) pra um efeito que o
       CSS já faz de graça. Mesmo amarelo #F4C766 do disco, opacidade menor. */
    --bg-horizon-halo: rgba(244, 199, 102, .20);

    /* Cor das divisórias entre as fatias do gráfico de rosca (Chart.js
       desenha um "border" de 4px por fatia). Normalmente é a mesma cor do
       cartão, o que faz as fatias parecerem separadas por um vão — lido por
       wwwroot/js/chart.js, não aplicado por nenhum seletor CSS.
       html.sections-transparent troca por `transparent`, ver seção 20. */
    --chart-ring-gap: var(--color-surface);
}

/* --------------------------------------------------------------------------
   3. TEMAS ALTERNATIVOS
   Aplicados via atributo  data-theme  no <html> — 25 cores no total (a cor
   "green" é o padrão, definido em :root na seção 2 acima; as outras 24 têm
   um bloco :root[data-theme="x"] aqui). Lista completa em CLAUDE.md
   ("Sistema de temas") e em OpcoesDeTema (Features/Configuracoes/Index.razor,
   página onde o usuário escolhe a cor — a sidebar não tem mais seletor).
   Novo tema = novo bloco aqui + regra .theme-swatch[data-theme-value="x"]
   (seção 8) + item em OpcoesDeTema.
   -------------------------------------------------------------------------- */
:root[data-theme="blue"] {
    --color-brand:        #1a56db;
    --color-brand-strong: #1241a3;
    --color-brand-soft:   #dbeafe;
    --color-surface-strong: #eff6ff;
    --sidebar-from:       #0f1f5c;
    --sidebar-to:         #1a3ab8;
    --focus-ring:         rgba(26, 86, 219, .22);
    --color-brand-ghost:  rgba(26, 86, 219, .07);
}

:root[data-theme="violet"] {
    --color-brand:        #7c3aed;
    --color-brand-strong: #5b21b6;
    --color-brand-soft:   #ede9fe;
    --color-surface-strong: #f5f3ff;
    --sidebar-from:       #2e1065;
    --sidebar-to:         #5b21b6;
    --focus-ring:         rgba(124, 58, 237, .22);
    --color-brand-ghost:  rgba(124, 58, 237, .07);
}

:root[data-theme="slate"] {
    --color-brand:        #475569;
    --color-brand-strong: #1e293b;
    --color-brand-soft:   #f1f5f9;
    --color-surface-strong: #f8fafc;
    --sidebar-from:       #0f172a;
    --sidebar-to:         #1e293b;
    --focus-ring:         rgba(71, 85, 105, .22);
    --color-brand-ghost:  rgba(71, 85, 105, .07);
}

:root[data-theme="red"] {
    --color-brand:        #dc2626;
    --color-brand-strong: #991b1b;
    --color-brand-soft:   #fee2e2;
    --color-surface-strong: #fef2f2;
    --sidebar-from:       #450a0a;
    --sidebar-to:         #991b1b;
    --focus-ring:         rgba(220, 38, 38, .22);
    --color-brand-ghost:  rgba(220, 38, 38, .07);
}

:root[data-theme="orange"] {
    --color-brand:        #ea580c;
    --color-brand-strong: #9a3412;
    --color-brand-soft:   #ffedd5;
    --color-surface-strong: #fff7ed;
    --sidebar-from:       #431407;
    --sidebar-to:         #9a3412;
    --focus-ring:         rgba(234, 88, 12, .22);
    --color-brand-ghost:  rgba(234, 88, 12, .07);
}

:root[data-theme="teal"] {
    --color-brand:        #0d9488;
    --color-brand-strong: #115e59;
    --color-brand-soft:   #ccfbf1;
    --color-surface-strong: #f0fdfa;
    --sidebar-from:       #042f2e;
    --sidebar-to:         #115e59;
    --focus-ring:         rgba(13, 148, 136, .22);
    --color-brand-ghost:  rgba(13, 148, 136, .07);
}

:root[data-theme="indigo"] {
    --color-brand:        #4f46e5;
    --color-brand-strong: #3730a3;
    --color-brand-soft:   #e0e7ff;
    --color-surface-strong: #eef2ff;
    --sidebar-from:       #1e1b4b;
    --sidebar-to:         #3730a3;
    --focus-ring:         rgba(79, 70, 229, .22);
    --color-brand-ghost:  rgba(79, 70, 229, .07);
}

:root[data-theme="pink"] {
    --color-brand:        #db2777;
    --color-brand-strong: #9d174d;
    --color-brand-soft:   #fce7f3;
    --color-surface-strong: #fdf2f8;
    --sidebar-from:       #500724;
    --sidebar-to:         #9d174d;
    --focus-ring:         rgba(219, 39, 119, .22);
    --color-brand-ghost:  rgba(219, 39, 119, .07);
}

:root[data-theme="cyan"] {
    --color-brand:        #0891b2;
    --color-brand-strong: #155e75;
    --color-brand-soft:   #cffafe;
    --color-surface-strong: #ecfeff;
    --sidebar-from:       #083344;
    --sidebar-to:         #155e75;
    --focus-ring:         rgba(8, 145, 178, .22);
    --color-brand-ghost:  rgba(8, 145, 178, .07);
}

:root[data-theme="amber"] {
    --color-brand:        #d97706;
    --color-brand-strong: #92400e;
    --color-brand-soft:   #fef3c7;
    --color-surface-strong: #fffbeb;
    --sidebar-from:       #451a03;
    --sidebar-to:         #92400e;
    --focus-ring:         rgba(217, 119, 6, .22);
    --color-brand-ghost:  rgba(217, 119, 6, .07);
}

:root[data-theme="yellow"] {
    --color-brand:        #ca8a04;
    --color-brand-strong: #854d0e;
    --color-brand-soft:   #fef9c3;
    --color-surface-strong: #fefce8;
    --sidebar-from:       #422006;
    --sidebar-to:         #854d0e;
    --focus-ring:         rgba(202, 138, 4, .22);
    --color-brand-ghost:  rgba(202, 138, 4, .07);
}

:root[data-theme="lime"] {
    --color-brand:        #65a30d;
    --color-brand-strong: #3f6212;
    --color-brand-soft:   #ecfccb;
    --color-surface-strong: #f7fee7;
    --sidebar-from:       #1a2e05;
    --sidebar-to:         #3f6212;
    --focus-ring:         rgba(101, 163, 13, .22);
    --color-brand-ghost:  rgba(101, 163, 13, .07);
}

:root[data-theme="emerald"] {
    --color-brand:        #059669;
    --color-brand-strong: #065f46;
    --color-brand-soft:   #d1fae5;
    --color-surface-strong: #ecfdf5;
    --sidebar-from:       #022c22;
    --sidebar-to:         #065f46;
    --focus-ring:         rgba(5, 150, 105, .22);
    --color-brand-ghost:  rgba(5, 150, 105, .07);
}

:root[data-theme="sky"] {
    --color-brand:        #0284c7;
    --color-brand-strong: #075985;
    --color-brand-soft:   #e0f2fe;
    --color-surface-strong: #f0f9ff;
    --sidebar-from:       #082f49;
    --sidebar-to:         #075985;
    --focus-ring:         rgba(2, 132, 199, .22);
    --color-brand-ghost:  rgba(2, 132, 199, .07);
}

:root[data-theme="purple"] {
    --color-brand:        #9333ea;
    --color-brand-strong: #6b21a8;
    --color-brand-soft:   #f3e8ff;
    --color-surface-strong: #faf5ff;
    --sidebar-from:       #3b0764;
    --sidebar-to:         #6b21a8;
    --focus-ring:         rgba(147, 51, 234, .22);
    --color-brand-ghost:  rgba(147, 51, 234, .07);
}

:root[data-theme="fuchsia"] {
    --color-brand:        #c026d3;
    --color-brand-strong: #86198f;
    --color-brand-soft:   #fae8ff;
    --color-surface-strong: #fdf4ff;
    --sidebar-from:       #4a044e;
    --sidebar-to:         #86198f;
    --focus-ring:         rgba(192, 38, 211, .22);
    --color-brand-ghost:  rgba(192, 38, 211, .07);
}

:root[data-theme="rose"] {
    --color-brand:        #e11d48;
    --color-brand-strong: #9f1239;
    --color-brand-soft:   #ffe4e6;
    --color-surface-strong: #fff1f2;
    --sidebar-from:       #4c0519;
    --sidebar-to:         #9f1239;
    --focus-ring:         rgba(225, 29, 72, .22);
    --color-brand-ghost:  rgba(225, 29, 72, .07);
}

:root[data-theme="gray"] {
    --color-brand:        #4b5563;
    --color-brand-strong: #1f2937;
    --color-brand-soft:   #f3f4f6;
    --color-surface-strong: #f9fafb;
    --sidebar-from:       #030712;
    --sidebar-to:         #1f2937;
    --focus-ring:         rgba(75, 85, 99, .22);
    --color-brand-ghost:  rgba(75, 85, 99, .07);
}

:root[data-theme="zinc"] {
    --color-brand:        #52525b;
    --color-brand-strong: #27272a;
    --color-brand-soft:   #f4f4f5;
    --color-surface-strong: #fafafa;
    --sidebar-from:       #09090b;
    --sidebar-to:         #27272a;
    --focus-ring:         rgba(82, 82, 91, .22);
    --color-brand-ghost:  rgba(82, 82, 91, .07);
}

:root[data-theme="stone"] {
    --color-brand:        #57534e;
    --color-brand-strong: #292524;
    --color-brand-soft:   #f5f5f4;
    --color-surface-strong: #fafaf9;
    --sidebar-from:       #0c0a09;
    --sidebar-to:         #292524;
    --focus-ring:         rgba(87, 83, 78, .22);
    --color-brand-ghost:  rgba(87, 83, 78, .07);
}

:root[data-theme="brown"] {
    --color-brand:        #795548;
    --color-brand-strong: #4e342e;
    --color-brand-soft:   #d7ccc8;
    --color-surface-strong: #efebe9;
    --sidebar-from:       #3e2723;
    --sidebar-to:         #4e342e;
    --focus-ring:         rgba(121, 85, 72, .22);
    --color-brand-ghost:  rgba(121, 85, 72, .07);
}

:root[data-theme="navy"] {
    --color-brand:        #1e40af;
    --color-brand-strong: #1e3a8a;
    --color-brand-soft:   #dbeafe;
    --color-surface-strong: #eff6ff;
    --sidebar-from:       #172554;
    --sidebar-to:         #1e3a8a;
    --focus-ring:         rgba(30, 64, 175, .22);
    --color-brand-ghost:  rgba(30, 64, 175, .07);
}

:root[data-theme="maroon"] {
    --color-brand:        #7f1d1d;
    --color-brand-strong: #450a0a;
    --color-brand-soft:   #fee2e2;
    --color-surface-strong: #fef2f2;
    --sidebar-from:       #2a0505;
    --sidebar-to:         #450a0a;
    --focus-ring:         rgba(127, 29, 29, .22);
    --color-brand-ghost:  rgba(127, 29, 29, .07);
}

:root[data-theme="olive"] {
    --color-brand:        #556b2f;
    --color-brand-strong: #3d4d21;
    --color-brand-soft:   #e6ecd6;
    --color-surface-strong: #f4f7ec;
    --sidebar-from:       #2b3517;
    --sidebar-to:         #3d4d21;
    --focus-ring:         rgba(85, 107, 47, .22);
    --color-brand-ghost:  rgba(85, 107, 47, .07);
}

/* --------------------------------------------------------------------------
   4. DARK MODE
   Aplicado via  <html class="dark">
   Seletor usa  :root.dark  (não  html.dark ) de propósito: precisa empatar
   em especificidade com  :root[data-theme="..."]  (blue/violet/slate) e
   vencer no desempate por ordem de declaração — com  html.dark  (specificidade
   menor que a do seletor de atributo do tema) essas cores claras dos temas
   vazavam por cima do dark mode, deixando botões/hovers "brancos" no dark.
   -------------------------------------------------------------------------- */
:root.dark {
    --color-bg:             #111827;
    --color-surface:        #1f2937;
    --color-surface-strong: #374151;
    --color-text:           #f9fafb;
    --color-text-muted:     #9ca3af;
    --color-border:         #374151;
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, .4);
    --shadow-md: 0 4px 14px rgba(0, 0, 0, .5);
    --shadow-lg: 0 20px 50px rgba(0, 0, 0, .65);

    /* Validação de campo vira amarelo/âmbar no dark — vermelho puro rende
       menos legível/contrastante sobre os fundos escuros do que sobre os
       claros. --color-danger continua vermelho em qualquer tema (botões,
       badges, alertas de exclusão etc. não mudam). */
    --color-validation:      var(--color-warning);
    --color-validation-soft: var(--color-warning-soft);
    --focus-ring-validation: var(--focus-ring-warning);

    /* Mesmo horizonte da seção 2 (agora em 2 camadas — colinas + sol, ver
       comentário lá), cores/opacidades recalibradas pro fundo escuro
       (#111827) — os tons pastel do claro ficariam quase invisíveis aqui;
       verdes mais claros/saturados e um pouco mais de opacidade devolvem o
       mesmo contraste sutil, sem "gritar" no dark. */
    --bg-horizon-hills: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA4NTYgMzAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIj4KICA8cGF0aCBkPSJNMCw1NiBDMTYwLDMwIDI2MCw3MCA0MjAsNDAgQzU2MCwxNCA2NjAsNTAgODU2LDQiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjN0ZBODc4IiBzdHJva2Utb3BhY2l0eT0iMC4xMCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KICA8cGF0aCBkPSJNMCw5OCBDMTUwLDYwIDI2MCwxMDAgNDIwLDY0IEM1NjAsMzIgNjgwLDc4IDg1NiwzMCBMODU2LDMwMCBMMCwzMDAgWiIKICAgICAgICBmaWxsPSIjNUY4RjVBIiBmaWxsLW9wYWNpdHk9IjAuMTAiIC8+CiAgPHBhdGggZD0iTTAsOTggQzE1MCw2MCAyNjAsMTAwIDQyMCw2NCBDNTYwLDMyIDY4MCw3OCA4NTYsMzAiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOEZCRjg4IiBzdHJva2Utb3BhY2l0eT0iMC4xNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+CiAgPHBhdGggZD0iTTAsMTc2IEMxNzAsMTI4IDMwMCwxNzIgNDYwLDEyOCBDNjAwLDkwIDcyMCwxNDIgODU2LDk2IEw4NTYsMzAwIEwwLDMwMCBaIgogICAgICAgIGZpbGw9IiM0QzdBNDciIGZpbGwtb3BhY2l0eT0iMC4xMyIgLz4KICA8cGF0aCBkPSJNMCwxNzYgQzE3MCwxMjggMzAwLDE3MiA0NjAsMTI4IEM2MDAsOTAgNzIwLDE0MiA4NTYsOTYiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjN0NCMDc2IiBzdHJva2Utb3BhY2l0eT0iMC4xNiIgc3Ryb2tlLXdpZHRoPSIyLjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KICA8cGF0aCBkPSJNMCwyNTggQzE5MCwyMDAgMzQwLDI1MiA1MDAsMjAyIEM2NTAsMTU4IDc2MCwyMTggODU2LDE2OCBMODU2LDMwMCBMMCwzMDAgWiIKICAgICAgICBmaWxsPSIjM0E2NDM4IiBmaWxsLW9wYWNpdHk9IjAuMTYiIC8+CiAgPHBhdGggZD0iTTAsMjU4IEMxOTAsMjAwIDM0MCwyNTIgNTAwLDIwMiBDNjUwLDE1OCA3NjAsMjE4IDg1NiwxNjgiCiAgICAgICAgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNUZBMDVBIiBzdHJva2Utb3BhY2l0eT0iMC4yMCIgc3Ryb2tlLXdpZHRoPSIyLjQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgLz4KPC9zdmc+Cg==");
    --bg-horizon-sun: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MCA2MCI+CiAgPGNpcmNsZSBjeD0iMzAiIGN5PSIzMCIgcj0iMjYiIGZpbGw9IiNGNEM3NjYiIGZpbGwtb3BhY2l0eT0iMC4xOCIgLz4KPC9zdmc+Cg==");

    /* Halo mais discreto que no claro — sobre #111827 o mesmo amarelo a .20
       vira uma mancha perceptível em vez de um brilho. */
    --bg-horizon-halo: rgba(244, 199, 102, .12);

    --chart-ring-gap: var(--color-surface);
}

/* --------------------------------------------------------------------------
   5. BASE RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after {
    box-sizing: border-box;
}

html, body {
    min-height: 100%;
    margin: 0;
    font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    font-size: 14px;
    line-height: 1.6;
    background: var(--color-bg);
    color: var(--color-text);
    -webkit-font-smoothing: antialiased;

    /* Horizonte decorativo (--bg-horizon-hills/--bg-horizon-sun, seções
       2/4) — 2 camadas de fundo (CSS aceita várias, separadas por vírgula;
       a PRIMEIRA da lista fica por CIMA, a última por BAIXO — colinas na
       frente, sol atrás, "nascendo" atrás da 1ª colina, mesmo espírito do
       desenho original). Colinas esticam `100%` da largura da tela (onda
       solta, esticar não incomoda o olho) com altura fixa de 240px —
       independente da largura da janela, a faixa continua discreta, nunca
       vira um painel gigante. O sol NÃO estica junto (esticaria o círculo
       numa elipse) — escala só como quadrado (140x140), ancorado um pouco
       acima da base da faixa de colinas pra ficar parcialmente atrás delas.
       `fixed` mantém o horizonte parado enquanto a página rola; graceful no
       iOS Safari, que historicamente ignora esse valor (cai pra `scroll`,
       o único efeito é o fundo rolar junto — nunca quebra o layout). Sem
       custo de performance real: só 2 imagens de fundo do body, puro CSS,
       sem JS/repaint por scroll. */
    background-image: var(--bg-horizon-hills), var(--bg-horizon-sun);
    background-repeat: no-repeat, no-repeat;
    background-position: bottom center, right 48px bottom 130px;
    background-size: 100% 240px, 140px 140px;
    background-attachment: fixed, fixed;
}

h1, h2, h3, h4 {
    margin: 0 0 .25em;
    line-height: 1.15;
    font-weight: 800;
}

h1 { font-size: 19px; }
h2 { font-size: 15px; }
h3 { font-size: 13px; }

h1:focus, h2:focus, h3:focus, h4:focus, h5:focus, h6:focus { outline: none; }

p { margin: 0 0 .75em; }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-decoration: none; }

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

/* --------------------------------------------------------------------------
   6. OVERLAY — sidebar mobile
   -------------------------------------------------------------------------- */
.overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .52);
    z-index: 40;
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    animation: fadeIn 200ms ease;
}

.overlay--open {
    display: block;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* --------------------------------------------------------------------------
   7. LAYOUT — App Shell
   Flex em vez de grid: permite transição suave da sidebar.
   -------------------------------------------------------------------------- */
.app-shell {
    display: flex;
    min-height: 100vh;
}

.app-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.app-content {
    flex: 1;
    padding: var(--sp-6);
}

/* --------------------------------------------------------------------------
   8. SIDEBAR
   -------------------------------------------------------------------------- */
.sidebar {
    flex-shrink: 0;
    width: var(--sidebar-width);
    height: 100vh;
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    padding: var(--sp-5);
    background: linear-gradient(180deg, var(--sidebar-from) 0%, var(--sidebar-to) 100%);
    color: #fff;
    overflow: hidden;
    transition: width var(--transition-slow);
    z-index: 30;
}

/* Marca / brand */
.brand {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-5);
    padding-bottom: var(--sp-4);
    border-bottom: 1px solid rgba(255, 255, 255, .12);
    flex-shrink: 0;
    overflow: hidden;
}

/* Logo da entidade (wwwroot/images/logo.png) — já traz o nome desenhado,
   por isso substitui o antigo quadrado "GD" + wordmark "Gerenciador/Documentos"
   por inteiro, em vez de ficar ao lado do texto. max-height + max-width (com
   width/height:auto) escala a logo proporcionalmente sem distorcer.
   Duas variantes: a logo larga (.brand-logo-expandida) some quando a sidebar
   colapsa (não cabe em --sidebar-collapsed-width) e dá lugar ao símbolo do
   sol (.brand-logo-colapsada, wwwroot/images/sol.png), que é quadrado e
   continua legível nos 72px de largura. */
.brand-logo {
    max-height: 32px;
    max-width: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}

.brand-logo-colapsada {
    display: none;
}

html.sidebar-collapsed .brand-logo-expandida {
    display: none;
}

html.sidebar-collapsed .brand-logo-colapsada {
    display: block;
    margin: 0 auto;
}

.sidebar-close {
    display: none;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    border: 0;
    background: rgba(255, 255, 255, .12);
    color: rgba(255, 255, 255, .8);
    cursor: pointer;
    transition: background var(--transition);
    margin-left: auto;
    padding: 0;
}

.sidebar-close:hover { background: rgba(255, 255, 255, .22); }

.sidebar-close .material-symbols-rounded { font-size: 18px; line-height: 1; }

/* Rodapé da sidebar */
.sidebar-footer {
    margin-top: auto;
    padding-top: var(--sp-4);
    border-top: 1px solid rgba(255, 255, 255, .10);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    flex-shrink: 0;
    overflow: hidden;
}

/* Swatch de cor de tema — decorativo, usado dentro de .theme-option
   (Features/Configuracoes/Index.razor). O clique fica no .theme-option pai;
   o swatch só existe para mostrar a cor (ver seção 27. CONFIGURAÇÕES). */
.theme-swatch {
    width: 20px;
    height: 20px;
    border-radius: var(--radius-full);
    border: 2px solid rgba(0, 0, 0, .08);
    flex-shrink: 0;
}

.theme-swatch[data-theme-value="green"]  { background: #246b43; }
.theme-swatch[data-theme-value="blue"]   { background: #1a56db; }
.theme-swatch[data-theme-value="violet"] { background: #7c3aed; }
.theme-swatch[data-theme-value="slate"]  { background: #475569; }
.theme-swatch[data-theme-value="red"]    { background: #dc2626; }
.theme-swatch[data-theme-value="orange"] { background: #ea580c; }
.theme-swatch[data-theme-value="teal"]   { background: #0d9488; }
.theme-swatch[data-theme-value="indigo"] { background: #4f46e5; }
.theme-swatch[data-theme-value="pink"]   { background: #db2777; }
.theme-swatch[data-theme-value="cyan"]   { background: #0891b2; }
.theme-swatch[data-theme-value="amber"]  { background: #d97706; }
.theme-swatch[data-theme-value="yellow"] { background: #ca8a04; }
.theme-swatch[data-theme-value="lime"]   { background: #65a30d; }
.theme-swatch[data-theme-value="emerald"]{ background: #059669; }
.theme-swatch[data-theme-value="sky"]    { background: #0284c7; }
.theme-swatch[data-theme-value="purple"] { background: #9333ea; }
.theme-swatch[data-theme-value="fuchsia"]{ background: #c026d3; }
.theme-swatch[data-theme-value="rose"]   { background: #e11d48; }
.theme-swatch[data-theme-value="gray"]   { background: #4b5563; }
.theme-swatch[data-theme-value="zinc"]   { background: #52525b; }
.theme-swatch[data-theme-value="stone"]  { background: #57534e; }
.theme-swatch[data-theme-value="brown"]  { background: #795548; }
.theme-swatch[data-theme-value="navy"]   { background: #1e40af; }
.theme-swatch[data-theme-value="maroon"] { background: #7f1d1d; }
.theme-swatch[data-theme-value="olive"]  { background: #556b2f; }

/* --------------------------------------------------------------------------
   9. SIDEBAR COLAPSADA
   Controlada via  html.sidebar-collapsed  (JS grava em localStorage)
   -------------------------------------------------------------------------- */
html.sidebar-collapsed .sidebar {
    width: var(--sidebar-collapsed-width);
    padding-left: var(--sp-3);
    padding-right: var(--sp-3);
}

html.sidebar-collapsed .nav-link-label,
html.sidebar-collapsed .nav-section-label {
    display: none;
}

html.sidebar-collapsed .nav-link {
    justify-content: center;
    padding: 10px;
    gap: 0;
}

html.sidebar-collapsed .brand {
    justify-content: center;
    padding-bottom: var(--sp-3);
}

html.sidebar-collapsed .sidebar-close {
    display: none !important;
}

/* --------------------------------------------------------------------------
   10. SIDEBAR MOBILE (drawer)
   -------------------------------------------------------------------------- */
@media (max-width: 767px) {
    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        width: var(--sidebar-width) !important;
        transform: translateX(-110%);
        transition: transform var(--transition-slow);
        z-index: 50;
    }

    .sidebar--open {
        transform: translateX(0);
    }

    .sidebar-close {
        display: flex !important;
    }
}

/* --------------------------------------------------------------------------
   11. NAVEGAÇÃO
   -------------------------------------------------------------------------- */
.nav-menu {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
}

.nav-menu::-webkit-scrollbar { display: none; }

.nav-section-label {
    display: block;
    padding: var(--sp-3) var(--sp-2) var(--sp-1);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .38);
    white-space: nowrap;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 10px var(--sp-3);
    border-radius: var(--radius-md);
    color: rgba(255, 255, 255, .68);
    font-weight: 600;
    font-size: 13px;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    transition: background var(--transition), color var(--transition);
    text-decoration: none;
}

.nav-link .material-symbols-rounded {
    font-size: 20px;
    flex-shrink: 0;
    line-height: 1;
}

.nav-link-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nav-link:hover {
    background: rgba(255, 255, 255, .10);
    color: #fff;
}

.nav-link.active {
    background: rgba(255, 255, 255, .18);
    color: #fff;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .10) inset;
}

.nav-link-danger {
    justify-content: center;
    background: rgba(255, 90, 90, .10);
    border: 1px solid rgba(255, 90, 90, .22);
    color: rgba(255, 140, 140, .92);
}

.nav-link-danger:hover {
    background: rgba(255, 60, 60, .18);
    border-color: rgba(255, 90, 90, .4);
    color: #fff;
}

/* Item de menu pai de submenu (ex.: "Sindicato" → Delegacias/Diretoria) —
   mesma aparência de .nav-link (classes combinadas), só reseta o <button>
   nativo e acrescenta o chevron de expandir/colapsar, ver NavMenu.razor. */
.nav-link-parent {
    width: 100%;
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
}

.nav-link-chevron {
    margin-left: auto;
    font-size: 18px !important;
    transition: transform var(--transition);
}

.nav-link-parent--open .nav-link-chevron {
    transform: rotate(180deg);
}

.nav-submenu {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-left: var(--sp-6);
}

.nav-link-sub {
    font-size: 12px;
}

/* Sidebar colapsada é só ícones — não cabe indentação de submenu nem
   chevron; expandir/colapsar continua funcionando por baixo (estado no
   NavMenu), só não fica visível até a sidebar ser expandida de novo. */
html.sidebar-collapsed .nav-link-chevron,
html.sidebar-collapsed .nav-submenu {
    display: none;
}

/* --------------------------------------------------------------------------
   12. TOPBAR
   -------------------------------------------------------------------------- */
.topbar {
    height: var(--topbar-height);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: 0 var(--sp-6);
    border-bottom: 1px solid var(--color-border);
    background: rgba(255, 255, 255, .88);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    position: sticky;
    top: 0;
    z-index: 10;
}

html.dark .topbar {
    background: rgba(31, 41, 55, .92);
}

.topbar-left {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    flex-shrink: 0;
}


.topbar-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
    margin-left: auto;
    flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   13. TOPBAR LOCATION
   -------------------------------------------------------------------------- */
.topbar-location {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    flex: 1;
    max-width: 380px;
    height: 38px;
    padding: 0 var(--sp-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    background: var(--color-surface-strong);
}

.topbar-location .material-symbols-rounded {
    font-size: 18px;
    color: var(--color-text-muted);
    flex-shrink: 0;
    line-height: 1;
}

.topbar-location-text {
    flex: 1;
    font-size: 13px;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   14. ICON BUTTON
   -------------------------------------------------------------------------- */
.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 0;
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    flex-shrink: 0;
    position: relative;
    transition: background var(--transition), color var(--transition);
    padding: 0;
}

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

.btn-icon:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Ícone desabilitado (ex.: ação "Documentos" ainda não disponível em
   Features/Eventos/Detalhes.razor) — sem isso o botão fica com a mesma
   aparência de um ativo, mas não reage ao clique, o que é confuso.
   pointer-events:none também anula o :hover (evita ter que sobrescrever
   background/color de cada variante de botão desabilitada). */
.btn-icon:disabled {
    opacity: .35;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-icon .material-symbols-rounded {
    font-size: 22px;
    line-height: 1;
}

.btn-icon-dot::after {
    content: '';
    position: absolute;
    top: 7px;
    right: 7px;
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--color-danger);
    border: 2px solid var(--color-surface);
}

/* --------------------------------------------------------------------------
   15. USER MENU
   -------------------------------------------------------------------------- */
.user-menu {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-1);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--transition);
    max-width: 220px;
}

.user-menu:hover {
    background: var(--color-surface-strong);
}

.user-avatar {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-full);
    background: var(--color-brand-soft);
    color: var(--color-brand-strong);
    font-weight: 800;
    font-size: 11px;
    overflow: hidden;
}

.user-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.user-meta {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    min-width: 0;
    overflow: hidden;
}

.user-meta strong {
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-meta span {
    font-size: 10px;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-menu-chevron {
    font-size: 18px;
    color: var(--color-text-muted);
    flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   16. BUTTONS
   -------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-height: 40px;
    padding: 0 var(--sp-4);
    border: 0;
    /* --radius-sm (8px), não --radius-md (12px) — pedido explícito pra
       deixar botões/inputs menos arredondados que o resto do app (cards,
       modais etc. continuam em --radius-md/--radius-lg, só esses dois
       tipos de componente mudaram). .btn-icon fica de fora (--radius-full
       é a forma, circular por design, não "arredondamento" no mesmo
       sentido). */
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-weight: 700;
    font-size: 13px;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    box-shadow: var(--shadow-sm);
    transition: background var(--transition), color var(--transition), box-shadow var(--transition);
}

.btn:hover {
    box-shadow: var(--shadow-md);
}

.btn:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* Botão desabilitado (ex.: "Ações rápidas" ainda não implementadas em
   Features/Eventos/Detalhes.razor) — pointer-events:none anula o :hover de
   qualquer variante (.btn-primary/.btn-ghost/.btn-danger) sem precisar de
   uma regra por variante. */
.btn:disabled {
    opacity: .5;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-primary {
    background: var(--color-brand);
    color: #fff;
}

.btn-primary:hover { background: var(--color-brand-strong); }

.btn-ghost {
    background: var(--color-surface-strong);
    color: var(--color-brand-strong);
}

.btn-ghost:hover { background: var(--color-border); }

html.dark .btn-ghost { color: var(--color-text); }

.btn-danger {
    background: var(--color-danger-soft);
    color: var(--color-danger);
}

.btn-danger:hover { background: var(--color-danger); color: #fff; }

.btn-block { width: 100%; }
.btn-sm    { min-height: 32px; padding: 0 var(--sp-3); font-size: 12px; }
.btn-lg    { min-height: 48px; padding: 0 var(--sp-6); font-size: 15px; }

/* Toggle "Lista"/"Tabela" — Features/Financeiro/PagamentosSttrs.razor.
   Pedido explícito: um segmented control "contido num container maior", não
   2 botões soltos lado a lado. .view-toggle é o "trilho" (fundo neutro,
   --color-surface-strong — mesmo token que .btn-ghost já usa, então
   continua neutro em qualquer tema/dark mode sem override extra aqui);
   .view-toggle-btn é cada opção (transparente por padrão, mesmo espírito de
   .page-tab) e .view-toggle-btn.active ganha --color-surface + sombra, como
   se fosse uma peça solta "flutuando" dentro do trilho — leitura visual
   imediata de qual opção está ativa. */
.view-toggle {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    background: var(--color-surface-strong);
    border-radius: var(--radius-md);
}

.view-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    min-height: 28px;
    padding: 0 var(--sp-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), box-shadow var(--transition);
}

.view-toggle-btn:hover {
    color: var(--color-text);
}

.view-toggle-btn.active {
    background: var(--color-surface);
    color: var(--color-brand);
    box-shadow: var(--shadow-sm);
}

.view-toggle-btn .material-symbols-rounded {
    font-size: 18px;
}

/* --------------------------------------------------------------------------
   17. FORMS
   -------------------------------------------------------------------------- */
.form-stack {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.form-field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
}

/* Mesmo tratamento de .detail-list dt (seção 21, TABELAS) — rótulo em
   --color-text-muted, não --color-text cheio, pra o valor digitado (cor
   cheia dentro do .form-input) chamar mais atenção que a legenda do campo.
   font-weight:600 continua (mantém escaneável numa lista longa de campos),
   só a cor mudou. */
.form-label {
    font-size: var(--font-size-xs);
    font-weight: 600;
    color: var(--color-text-muted);
}

.form-input {
    width: 100%;
    min-height: 36px;
    padding: 0 var(--sp-3);
    border: 1px solid var(--color-border);
    /* --radius-sm (8px), mesma justificativa de .btn acima. */
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    outline: none;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.form-input:focus {
    border-color: var(--color-brand);
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.form-input::placeholder {
    color: var(--color-text-muted);
    opacity: .7;
}

.form-hint {
    font-size: 11px;
    color: var(--color-text-muted);
}

/* Divisor discreto dentro de um .form-grid/.form-grid-4 — separa dois grupos
   de campos na MESMA aba (ex.: campos que vieram de uma aba removida e
   passaram a viver no fim de outra, sem precisar de aba própria só pra
   eles). Ocupa a linha inteira (mesmo grid-column de .form-field.span-2,
   mas não é um .form-field — sem input/label, não participa de validação).
   Legenda é o próprio texto do elemento — opcional; sem texto, vira só uma
   linha fina com um vão pequeno no meio (ainda discreta, não quebra o
   layout). Usar <div class="form-divider">Texto</div> direto como filho do
   grid, no meio da lista de .form-field. */
.form-divider {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin: var(--sp-1) 0;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-weight: 600;
}

.form-divider::before,
.form-divider::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--color-border);
}

.autocomplete {
    position: relative;
}

.autocomplete-list {
    position: absolute;
    z-index: 10;
    top: calc(100% + var(--sp-1));
    left: 0;
    right: 0;
    max-height: 220px;
    overflow-y: auto;
    margin: 0;
    padding: var(--sp-1);
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
}

.autocomplete-item {
    display: block;
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text);
    font-size: var(--font-size-sm);
    text-align: left;
    cursor: pointer;
}

.autocomplete-item:hover,
.autocomplete-item:focus-visible {
    background: var(--color-surface-strong);
    outline: none;
}

.check-row {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    cursor: pointer;
    user-select: none;
}

.check-row input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: var(--color-brand);
    cursor: pointer;
    flex-shrink: 0;
}

.check-row span {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* Grid de checkboxes em 3 colunas fixas (FiltroTipoParticipanteModal, Tipo de
   participante — pedido explícito pra não ficar tudo empilhado numa lista
   única). Substitui .form-stack só nesse contexto de lista de checkbox —
   .form-stack continua sendo o empilhamento vertical padrão de campo de
   formulário. 3 colunas fixas (não auto-fill/minmax, que já tinha ficado só
   com 2 na largura padrão do .modal) — colapsa pra 1 coluna no mobile (ver
   media query mais abaixo). */
.check-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-2) var(--sp-4);
}

/* .form-input-sm é, na prática, o input/select padrão de toda barra de
   filtro/pesquisa de listagem (.table-filters — Socios/Usuarios/Eventos/
   Documentos/Index.razor, Eventos/Detalhes.razor, TamanhoPaginaSelector) —
   sempre ao lado de botões .btn-sm (Filtrar/Limpar/ordenar). min-height
   32px e font-size 12px (--font-size-sm, não mais --font-size-2xs) pra
   bater exatamente com .btn-sm (`min-height: 32px; font-size: 12px;`,
   acima) — pedido explícito ("mesma altura que os botões vizinhos"), esse
   é o padrão daqui pra frente em toda pesquisa/filtro. Ambos reduzidos 1px
   numa rodada geral de redução de fonte (ver "Tamanho dos campos de
   formulário" abaixo) — continuam do mesmo tamanho um do outro. */
.form-input-sm {
    min-height: 32px;
    padding: 0 var(--sp-2);
    font-size: var(--font-size-sm);
    width: auto;
    border: 1px solid var(--color-border);
    /* --radius-sm (8px), mesma justificativa de .btn/.form-input acima. */
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    outline: none;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.form-input-sm:focus {
    border-color: var(--color-brand);
    box-shadow: 0 0 0 3px var(--focus-ring);
}

select.form-input,
select.form-input-sm {
    appearance: auto;
    cursor: pointer;
    padding-right: var(--sp-4);
}

/* align-items: start evita que um .form-field seja esticado pra altura da
   linha inteira do grid — sem isso, dentro de .tab-panels (onde os painéis
   ficam empilhados na mesma célula e a linha é dimensionada pelo maior
   painel), um .form-field.autocomplete mais curto que o painel fica mais
   alto por dentro, e o dropdown (position:absolute, top:100% relativo à
   altura do .form-field) acaba aparecendo bem abaixo do input em vez de colado nele.

   align-content: start evita que as PRÓPRIAS LINHAS do grid se espalhem pra
   preencher a altura do container quando ele fica mais alto que o conteúdo —
   caso comum de novo dentro de .tab-panels: a linha única de .tab-panels é
   dimensionada pelo painel mais alto (ex.: "Dados pessoais"), e um painel
   mais curto (ex.: "Endereço") empilhado na mesma célula herda essa altura
   inteira (align-items:stretch, padrão do grid pai). Sem align-content aqui,
   o valor padrão ("normal") se comporta como "stretch" em Grid — as linhas
   internas desse painel mais curto cresciam pra preencher o espaço sobrando,
   e cada label/campo ficava visivelmente afastado do próximo, como se o
   formulário tentasse ocupar a tela inteira. Com align-content: start, as
   linhas do grid ficam grudadas no topo, na altura natural do conteúdo, e o
   espaço sobrando (se houver) fica em branco depois do último campo — nunca
   espalhado entre eles. Regra geral: nenhum grid/flex de formulário deve
   esticar filho pra preencher altura disponível — ver CLAUDE.md desta pasta. */
.form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    align-content: start;
    gap: var(--sp-4);
}

.form-field.span-2 { grid-column: 1 / -1; }

/* Só ocupa a linha inteira no mobile — em telas maiores entra no fluxo
   normal de 2 colunas do .form-grid (reduz a altura da modal em telas HD). */
.form-field.span-2-mobile { grid-column: auto; }

/* Variante de 4 colunas — usar junto de .form-grid (não no lugar), ex.:
   class="form-grid form-grid-4". Formulários muito extensos com muitos
   campos curtos (ex.: SocioModal, 8 abas) ficam mais compactos assim — a
   modal usa .modal-xl (860px+100px de folga, ver comentário na seção 28)
   pra sobrar largura de verdade pras 4 colunas, não só apertar o texto.
   .form-field.span-2 (acima) continua servendo pra campo de largura total
   (grid-column: 1 / -1 independe de quantas colunas o grid realmente tem) —
   o nome "span-2" é histórico (do tempo em que .form-grid só tinha 2
   colunas), mas o efeito ("ocupa a linha inteira") continua correto aqui.
   .col-2, abaixo, é o equivalente pra "metade da largura" (2 das 4
   colunas) — não existia até agora porque nenhum outro .form-grid do app
   precisou de um meio-termo entre 1 coluna e largura total. */
.form-grid-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.form-grid-4 .form-field.col-2 { grid-column: span 2; }

/* Abaixo de ~1024px a modal já não sobra largura suficiente pra 4 colunas
   legíveis — cai pra 2 (mesma contagem do .form-grid padrão, que já é
   comprovadamente usável em mobile, ver comentário da seção 29). Campos
   .col-2 (iam ocupar metade das 4) passam a ocupar a linha inteira sozinhos
   (metade de 2 = 2 de 2), sem precisar de uma classe "-mobile" própria. */
@media (max-width: 1024px) {
    .form-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Variante de 5 colunas — mesma regra de uso da de 4: sempre junto de
   .form-grid, nunca no lugar (class="form-grid form-grid-5").

   Existe porque 4 colunas só oferecem 3 larguras possíveis (25% / 50% via
   .col-2 / 100% via .span-2), e num formulário com muitos campos de tamanho
   MUITO diferente isso força escolhas ruins nas duas pontas: um "Ponto de
   referência" acaba ocupando a linha inteira porque metade seria pouco, e um
   "Data de expedição (RG)" fica espremido em 25% porque metade seria demais.
   Com 5 colunas a escala vira 20/40/60/80/100%, e cada campo consegue uma
   largura proporcional ao que ele realmente recebe de conteúdo.

   Primeiro (e por ora único) consumidor: Areas/Socios/Views/Socios/_Form.cshtml.
   Só criar uma variante de 6+ colunas se aparecer um formulário que
   comprovadamente precise — abaixo de ~134px por coluna (o que 5 colunas já
   dão dentro de uma .modal-xl-wide) o campo deixa de caber num valor curto
   como um CEP. */
.form-grid-5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

.form-grid-5 .form-field.col-2 { grid-column: span 2; }
.form-grid-5 .form-field.col-3 { grid-column: span 3; }

/* Mesmo corte de .form-grid-4 — abaixo de ~1024px não sobra largura pra 5
   colunas legíveis, cai pra 2.

   .col-2 vira linha inteira sozinho (span 2 de 2), como já acontece na
   variante de 4. Mas .col-3 PRECISA de reset explícito: `grid-column: span 3`
   num grid de 2 colunas não é ignorado — o navegador cria uma 3ª coluna
   implícita pra caber o item, estourando a largura do container e
   desalinhando todo o resto da aba. Por isso o `1 / -1` abaixo, que é a
   forma correta de dizer "linha inteira" independente de quantas colunas
   existem. */
@media (max-width: 1024px) {
    .form-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .form-grid-5 .form-field.col-3 { grid-column: 1 / -1; }
}

.form-input.invalid,
.form-input.modified.invalid,
select.form-input.invalid {
    border-color: var(--color-validation);
    background: var(--color-validation-soft);
    color: var(--color-validation);
}

.form-input.invalid:focus {
    border-color: var(--color-validation);
    box-shadow: 0 0 0 3px var(--focus-ring-validation);
}

.validation-message {
    display: block;
    font-size: 11px;
    color: var(--color-validation);
}

/* --------------------------------------------------------------------------
   18. CARDS
   -------------------------------------------------------------------------- */
.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.card-body { padding: var(--sp-5); }

.card-header {
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--color-border);
    font-weight: 700;
}

.page-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--sp-5);
}

/* Espaçamento entre .page-card empilhados fora de .content-grid. */
.page-card + .page-card {
    margin-top: var(--sp-4);
}

/* Preferência "Seções transparentes" (Configurações) — tira o fundo próprio
   dos .page-card pra deixar o horizonte de html/body aparecer por baixo (ver
   "Fundo decorativo" no CLAUDE.md desta pasta). Classe no <html>, mesmo
   mecanismo de .dark/.sidebar-collapsed: JS + localStorage, nada no servidor.

   A BORDA CONTINUA. Só o preenchimento e a sombra saem — sem nenhuma
   delimitação, várias seções empilhadas viram um bloco só de texto solto
   sobre o fundo, e a hierarquia da página se perde. A borda mantém o
   agrupamento legível sem esconder o que está atrás. A sombra sai junto
   porque sombra de um elemento sem fundo desenha um halo no vazio.

   Escopo deliberadamente estreito: SÓ .page-card. Modal, tabela, campo de
   formulário e cartão do app mobile continuam opacos — transparência ali
   custaria legibilidade sem nenhum ganho visual (o conteúdo é denso e
   precisa de fundo sólido pra contrastar). .chart-card não precisa de regra
   própria: sempre vem junto de .page-card no mesmo elemento. */
html.sections-transparent .page-card {
    background: transparent;
    box-shadow: none;
}

/* O cartão do gráfico já é coberto pela regra acima (.chart-card sempre vem
   junto de .page-card, e nem ele nem .chart-body/.app-chart têm fundo
   próprio). O que NÃO some sozinho é o desenho dentro do <canvas>: o gráfico
   de rosca separa as fatias com um "border" de 4px pintado da cor do cartão,
   e num cartão transparente essas divisórias viram riscos brancos (ou
   #1f2937, no dark) por cima do plano de fundo.

   `transparent` aqui mantém o vão entre as fatias — a separação continua
   existindo, só deixa o fundo aparecer no lugar de uma cor sólida.

   ATENÇÃO: quem lê este token é o JS (wwwroot/js/chart.js), no momento em que
   o gráfico é construído. Chart.js não reavalia cor depois de renderizado,
   então alternar a preferência só reflete nos gráficos da PRÓXIMA navegação.
   Na prática não incomoda porque a página de Configurações não tem gráfico
   nenhum; se um dia tiver, será preciso re-renderizar (AppCharts.render) ao
   alternar. */
html.sections-transparent {
    --chart-ring-gap: transparent;
}

/* Mesmo espaçamento quando um .page-card é seguido de um .content-grid. */
.page-card + .content-grid {
    margin-top: var(--sp-4);
}

/* Mesmo espaçamento quando um .page-card é seguido de um grid de gráficos. */
.page-card + .chart-grid {
    margin-top: var(--sp-4);
}

/* Mesmo espaçamento quando um .page-card é seguido de .page-tabs — sem isso
   as abas ficam coladas na section acima (.page-card não tem margin-bottom
   próprio, só .page-tabs tem margin-bottom, nunca margin-top). */
.page-card + .page-tabs {
    margin-top: var(--sp-4);
}

.page-card.narrow { max-width: 720px; }

.kpi-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--sp-5);
}

.kpi-card > span,
.kpi-card-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-muted);
}

.kpi-card > strong,
.kpi-card-value {
    display: block;
    font-size: 33px;
    font-weight: 800;
    line-height: 1.1;
    margin: var(--sp-2) 0 var(--sp-1);
    color: var(--color-brand);
}

.kpi-card > small,
.kpi-card-sub {
    display: block;
    font-size: 11px;
    color: var(--color-text-muted);
}

/* Variante de .kpi-card-value pra texto (datas, nomes) em vez de número curto
   — 34px/800 fica largo/estoura num card pequeno com texto longo. Seletor
   precisa de ".kpi-card >" (não só a classe) pra ganhar de ".kpi-card > span"
   em especificidade, senão o span cai na regra do label (13px) por engano. */
.kpi-card > .kpi-card-value-text {
    display: block;
    font-size: 17px;
    font-weight: 700;
    line-height: 1.3;
    margin: var(--sp-2) 0 var(--sp-1);
    color: var(--color-brand);
}

/* Lista de definição (rótulo + valor) pra dados completos dentro de um
   .page-card (ex.: "Informações do evento" em Features/Eventos/Detalhes.razor). */
.detail-list {
    display: grid;
    grid-template-columns: 180px 1fr;
    row-gap: var(--sp-3);
    column-gap: var(--sp-4);
    margin: var(--sp-4) 0 0;
}

.detail-list dt {
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-muted);
}

.detail-list dd {
    margin: 0;
    font-size: 13px;
    color: var(--color-text);
}

/* Variante de .detail-list com o rótulo (dt) bem mais destacado em relação
   ao valor (dd) — pedido explícito depois que dt (12px/600/muted) e dd
   (13px/400/texto cheio) ficavam parecidos demais quando empilhados em 1
   coluna (telas estreitas, ex.: Features/Mobile/Sindicato/Detalhes.razor e
   Features/Mobile/Eventos/Detalhes.razor). Sempre 1 coluna, independente do
   breakpoint mobile de .detail-list (a área útil do app mobile já é
   estreita por causa de .mobile-app-content, max-width 560px, mesmo numa
   janela de desktop) — dt vira um rótulo no estilo .eyebrow (uppercase,
   letter-spacing, ainda mais bold que o dt padrão) e o espaçamento agrupa
   cada par dt/dd (gap curto entre os dois, respiro maior — --sp-3 — antes
   do próximo rótulo), em vez do row-gap uniforme do .detail-list padrão.
   Seletor composto (.detail-list.detail-list--destaque, não só a classe
   solta) por causa da regra de especificidade do topo deste arquivo (ver
   CLAUDE.md, "Regras absolutas" nº 6) — garante que a variante vença o
   .detail-list base não importa a ordem das duas classes no HTML. Reutilizar
   (class="detail-list detail-list--destaque") em qualquer tela nova — WEB ou
   mobile — que precise do mesmo contraste rótulo/valor, não é exclusiva do
   app mobile. */
.detail-list.detail-list--destaque {
    grid-template-columns: 1fr;
    row-gap: 0;
}

.detail-list.detail-list--destaque dt {
    margin-top: var(--sp-3);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.detail-list.detail-list--destaque dt:first-child {
    margin-top: 0;
}

.detail-list.detail-list--destaque dd {
    margin-top: 2px;
    font-size: 14px;
    color: var(--color-text);
}

/* Estado vazio dentro de um .page-card, pra seções ainda sem dado real
   (ex.: "Participantes"/"Documentos" em Features/Eventos/Detalhes.razor). */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-8) var(--sp-4);
    text-align: center;
}

.empty-state .material-symbols-rounded {
    font-size: 36px;
    color: var(--color-text-muted);
    opacity: .6;
}

.empty-state-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--color-text);
}

.empty-state-description {
    max-width: 320px;
    font-size: 12px;
    color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   19. BADGES
   -------------------------------------------------------------------------- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.5;
    background: var(--color-brand-soft);
    color: var(--color-brand-strong);
}

.badge.success, .badge-success { background: var(--color-success-soft); color: var(--color-success); }
.badge.warning, .badge-warning { background: var(--color-warning-soft); color: var(--color-warning); }
.badge.danger,  .badge-danger  { background: var(--color-danger-soft);  color: var(--color-danger);  }
/* Cinza neutro de verdade — diferente do .badge sem modificador (que usa
   --color-brand-soft/--color-brand-strong, muda de cor com o tema). Usa
   --color-border/--color-text-muted, os únicos dois tokens de superfície que
   NÃO são sobrescritos por tema (só por dark mode) — ver "Design tokens" em
   wwwroot/css/CLAUDE.md. Criado pro status "Pendente" de
   Features/Financeiro/PagamentosSttrs.razor (StringHelpers.
   ObterSituacaoPagamentoSttr), pedido explícito de cor neutra/cinza. */
.badge.gray, .badge-gray { background: var(--color-border); color: var(--color-text-muted); }

/* --------------------------------------------------------------------------
   20. ALERTAS
   -------------------------------------------------------------------------- */
.alert {
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: 500;
    margin-bottom: var(--sp-4);
}

.alert-danger  { background: var(--color-danger-soft);  color: var(--color-danger);  border: 1px solid rgba(180, 35, 24, .18); }
.alert-success { background: var(--color-success-soft); color: var(--color-success); border: 1px solid rgba(2, 122, 72, .18);  }
.alert-warning { background: var(--color-warning-soft); color: var(--color-warning); border: 1px solid rgba(181, 71, 8, .18);  }

/* --------------------------------------------------------------------------
   21. TABELAS
   -------------------------------------------------------------------------- */
.table {
    width: 100%;
    border-collapse: collapse;
}

.table th,
.table td {
    padding: var(--sp-3) var(--sp-4);
    border-bottom: 1px solid var(--color-border);
    text-align: left;
    font-size: 13px;
}

.table th {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--color-text-muted);
}

.table tbody tr:hover { background: var(--color-brand-ghost); }

.table .btn-icon {
    width: 22px;
    height: 22px;
}

.table .btn-icon .material-symbols-rounded {
    font-size: 16px;
}

/* Agrupa múltiplos .btn-icon numa mesma célula "Ações" (ex.: Ver detalhes +
   Editar em Features/Eventos/Index.razor) — evita depender de espaço em
   branco incidental do HTML pra dar espaçamento entre os botões. */
.table-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-1);
}

/* Célula de tabela com título em destaque + linha secundária discreta
   (ex.: Título/Tema em Features/Eventos/Index.razor). O texto já chega
   truncado por código (com "..."), então aqui é só o empilhamento visual. */
.table-cell-primary {
    display: block;
    font-weight: 700;
    color: var(--color-text);
}

.table-cell-secondary {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    color: var(--color-text-muted);
}

/* Estreita uma coluna específica (ex.: Nome/CPF na aba Participantes de
   Features/Eventos/Detalhes.razor, abrindo espaço pra uma coluna nova ao
   lado) — aplicar no <th>, a tabela usa table-layout automático (não
   table-layout:fixed, que exigiria largura em toda coluna), então o
   navegador ainda negocia com o conteúdo real das células dessa coluna;
   é uma redução relativa, não uma largura exata. Dois tamanhos genéricos,
   reutilizar em qualquer tabela nova antes de criar outro. */
.table-col-md { width: 18%; }
.table-col-sm { width: 11%; }

/* Encolhe a coluna pro menor tamanho possível (não uma redução relativa como
   as duas acima) — truque clássico de table-layout automático: width:1% faz
   o navegador tratar a largura como "irrelevante" e encolher a coluna até o
   conteúdo, sobrando o espaço pras colunas sem width nenhuma (Nome/Regional
   na aba Participantes de Features/Eventos/Detalhes.razor, pedido explícito
   — "menor tamanho possível e com um pouco de margem apenas"). white-space:
   nowrap garante que não encolha ponto de quebrar o botão de ação ao meio.
   Usar só na coluna "Ações" (sempre a última, conteúdo sempre um grupo curto
   de .btn-icon) — não é um substituto genérico de table-col-sm/md. */
.table-col-acoes {
    width: 1%;
    white-space: nowrap;
}

/* Largura fixa (não relativa como .table-col-sm/.table-col-md acima) pra
   coluna CPF da aba Participantes de Features/Eventos/Detalhes.razor —
   pedido explícito: o CPF tem formato/tamanho sempre igual ("000.000.000-00",
   14 caracteres), então uma largura em px cabe melhor que um % que varia com
   a largura da tabela e estava quebrando o texto em duas linhas. white-space:
   nowrap é o que realmente impede a quebra (a largura sozinha não garante
   isso em table-layout automático). */
.table-col-cpf {
    width: 140px;
    white-space: nowrap;
}

/* Coluna de mês da matriz Sindicato x Mês (Features/Financeiro/
   PagamentosSttrs.razor, visão "Tabela") — mesmo truque de width:1% de
   .table-col-acoes (encolhe pro conteúdo mínimo, sobrando largura pra coluna
   de Sindicato ao lado, pedido explícito "deixar o nome dos sindicatos
   completos"), mas centralizado (o conteúdo é só um ícone de status, não
   texto alinhado à esquerda como Ações). Usada nas 12 colunas de mês, tanto
   no <th> quanto no <td>. */
.table-col-status-icon {
    width: 1%;
    white-space: nowrap;
    text-align: center;
}

/* Marcador "Em dia" da mesma matriz (StringHelpers.ObterSituacaoMatrizSttr,
   Chip=true) — disco cheio da cor do tema ativo com o ícone em branco por
   cima. Pedido explícito: "em dia" precisa vir sólido/preenchido, com o
   ícone branco, não um traço colorido só. Implementado com fundo CSS puro
   (não com o eixo variável FILL da fonte de ícones — tentativa anterior,
   revertida: o Google Fonts só serve a fonte de verdade variável pra
   navegadores que ele reconhece via User-Agent; sem esse reconhecimento cai
   num fallback estático por peso, sem nenhum dado de FILL, então não dava
   pra garantir que o eixo funcionaria em todo navegador) — mais simples e
   sempre confiável: fundo sólido + ícone comum ("check", sem círculo
   embutido no próprio glyph) branco por cima. */
.status-icon-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: var(--radius-full);
}

.status-icon-chip .material-symbols-rounded {
    font-size: 14px;
    color: #fff;
}

.status-icon-chip-brand { background: var(--color-brand); }

.table-loading {
    padding: var(--sp-8) var(--sp-4);
    text-align: center;
    color: var(--color-text-muted);
    font-size: 13px;
}

.table-empty {
    padding: var(--sp-8) var(--sp-4) !important;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 13px;
}

/* --------------------------------------------------------------------------
   22. PAGE HEADER
   -------------------------------------------------------------------------- */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-4);
    margin-bottom: var(--sp-5);
}

.page-header h1 {
    font-size: 19px;
    font-weight: 800;
    line-height: 1.2;
    margin: 0;
}

.page-header p {
    font-size: 12px;
    color: var(--color-text-muted);
    margin: 2px 0 0;
}

.eyebrow {
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--color-brand);
    margin-bottom: var(--sp-1);
}

.task-list {
    margin: var(--sp-3) 0 0;
    padding-left: var(--sp-5);
    color: var(--color-text-muted);
    font-size: 13px;
}

.task-list li + li { margin-top: var(--sp-2); }

/* --------------------------------------------------------------------------
   23. GRIDS DE CONTEÚDO
   -------------------------------------------------------------------------- */
.kpi-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-4);
}

.content-grid {
    display: grid;
    grid-template-columns: 1.4fr .8fr;
    gap: var(--sp-4);
}

/* --------------------------------------------------------------------------
   24. LOGIN
   -------------------------------------------------------------------------- */
/* Fundo próprio, sobrepondo o horizonte de `html, body` (seção 5) — não é
   duplicação: `.login-page` tem `min-height:100vh` e sempre pintaria por
   cima dele de qualquer forma. Antes eram só dois gradientes radiais
   verdes, e por isso o login era a ÚNICA tela do app sem o sol.

   Aqui o sol sai do canto inferior direito (posição que ele tem no resto do
   app, nascendo atrás da 1ª colina) e vai pro canto SUPERIOR direito,
   inteiro e destacado da borda, com um brilho difuso atrás
   (--bg-horizon-halo). As colinas continuam fechando a base, então a
   paisagem segue completa — só o sol mudou de lugar.

   Ordem das camadas: a PRIMEIRA da lista fica por CIMA. Colinas na frente,
   sol no meio, halo atrás — mesma convenção já usada em `html, body`.
   Como o sol está no topo e as colinas na base, os dois não se cruzam; a
   ordem é mantida só por consistência.

   Os dois gradientes verdes antigos saíram: com sol + halo + colinas, mais
   uma camada de cor deixava o fundo turvo. */
.login-page {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: var(--sp-6);
    background-color: var(--color-bg);
    background-image:
            var(--bg-horizon-hills),
            var(--bg-horizon-sun),
            radial-gradient(circle at calc(100% - 151px) 143px,
                            var(--bg-horizon-halo) 0%, transparent 62%);
    background-repeat: no-repeat;
    background-position:
            bottom center,
            right 56px top 48px,
            center;
    background-size:
            100% 240px,
            190px 190px,
            cover;
}

/* Em telas estreitas o sol encosta demais na borda e o halo (ancorado em px
   a partir da direita) sai de posição — encolhe os dois e aproxima do canto,
   mantendo a mesma leitura sem competir com o cartão, que no mobile ocupa
   quase toda a largura. */
@media (max-width: 767px) {
    .login-page {
        background-image:
                var(--bg-horizon-hills),
                var(--bg-horizon-sun),
                radial-gradient(circle at calc(100% - 92px) 92px,
                                var(--bg-horizon-halo) 0%, transparent 62%);
        background-position:
                bottom center,
                right 28px top 28px,
                center;
        background-size:
                100% 180px,
                128px 128px,
                cover;
    }
}

.login-card {
    width: min(100%, 440px);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-8);
}

.login-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-4);
    margin-bottom: var(--sp-6);
    padding-bottom: var(--sp-6);
    border-bottom: 1px solid var(--color-border);
}

/* Logo da entidade (wwwroot/images/logo.png) — já traz o nome desenhado,
   por isso substitui o antigo quadrado "GD" + textos "Gerenciador de
   Documentos"/"Sistema Web" por inteiro. Mesma técnica de escala proporcional
   de .brand-logo (Sidebar), só com altura máxima maior (mais espaço aqui). */
.login-brand-logo {
    max-height: 44px;
    max-width: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}

.login-title    { font-size: 21px; font-weight: 800; margin: 0 0 var(--sp-1); }
.login-subtitle { font-size: 13px; color: var(--color-text-muted); margin: 0 0 var(--sp-5); }

/* --------------------------------------------------------------------------
   25. TABLE TOOLBAR & PAGINAÇÃO
   -------------------------------------------------------------------------- */
.table-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    margin-bottom: var(--sp-4);
    padding-bottom: var(--sp-4);
    border-bottom: 1px solid var(--color-border);
    flex-wrap: wrap;
}

.table-filters {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

.table-search-input {
    min-width: 220px;
}

.page-size-selector {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.page-size-selector .form-label {
    margin: 0;
    white-space: nowrap;
    font-size: var(--font-size-xs);
}

.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    margin-top: var(--sp-4);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--color-border);
}

.pagination-info { font-size: 12px; color: var(--color-text-muted); }

.pagination-controls {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.pagination-page {
    min-width: 56px;
    text-align: center;
    font-size: 12px;
    font-weight: 600;
}

/* --------------------------------------------------------------------------
   26. UTILITÁRIOS
   -------------------------------------------------------------------------- */
.text-muted   { color: var(--color-text-muted); }
.text-brand   { color: var(--color-brand); }
.text-danger  { color: var(--color-danger); }
.text-warning { color: var(--color-warning); }
/* Anotação secundária na MESMA linha de um valor principal (ex.: Regional ao
   lado da Entidade de origem, Features/Eventos/Detalhes.razor) — combinar com
   .text-muted pra cor. Diferente de .table-cell-secondary (empilha numa linha
   nova via display:block); aqui o elemento (normalmente <span>) continua
   inline, só a fonte encolhe. */
.text-sm     { font-size: 11px; }
/* Ícone Material Symbols pequeno logo depois de um texto na MESMA linha (ex.:
   aviso "pago com atraso" ao lado do nome do Sindicato na Tabela de
   Features/Financeiro/PagamentosSttrs.razor) — combinar com .text-warning/
   .text-muted/etc. pra cor. 16px (menor que o padrão 24px da fonte de ícones)
   pra ficar discreto ao lado de texto de tabela; cursor:help sinaliza que o
   `title` tem mais contexto. */
.icon-sm-inline {
    font-size: 16px;
    vertical-align: text-bottom;
    margin-left: var(--sp-1);
    cursor: help;
}
.fw-medium   { font-weight: 500; }
.fw-bold     { font-weight: 700; }
.fw-black    { font-weight: 800; }
.mt-0        { margin-top: 0; }
.mb-0        { margin-bottom: 0; }
.mb-4        { margin-bottom: var(--sp-4); }
.mt-4        { margin-top: var(--sp-4); }
.text-center { text-align: center; }
.d-none      { display: none; }

/* .d-none perde por ORDEM (não por especificidade) pra qualquer classe que
   declare `display` e esteja definida DEPOIS desta linha — as duas são 0,0,1,0
   e vence a última do arquivo. Ver regra 6 em wwwroot/css/CLAUDE.md: a solução
   é seletor composto (0,0,2,0), não confiar na posição.

   Bug real: as telas MVC deixam a modal sempre no DOM (não existe circuito pra
   montá-la sob demanda) e a escondem com .d-none — como .modal-wrapper declara
   `display:flex` mais abaixo, o relatório do Financeiro abria sozinho ao entrar
   na tela, tanto no mobile quanto na Web. Mesmo efeito no overlay de progresso
   e na barra de zoom do visualizador, e no painel de filtros do mobile.

   Ao combinar .d-none com uma classe que declare `display`, conferir se ela
   está acima desta linha; se estiver abaixo, acrescentar aqui. */
.modal-wrapper.d-none,
.pdf-viewer-loading.d-none,
.pdf-viewer-controls.d-none,
.mobile-filter-panel.d-none { display: none; }

/* --------------------------------------------------------------------------
   27. CONFIGURAÇÕES (tema + switch)
   Cartões de cor e switch usados em Features/Configuracoes/Index.razor.
   -------------------------------------------------------------------------- */
.theme-options {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
    gap: var(--sp-3);
    margin-top: var(--sp-4);
}

.theme-option {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}

.theme-option:hover {
    border-color: var(--color-brand);
    background: var(--color-surface-strong);
}

.theme-option:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.theme-option[aria-checked="true"] {
    border-color: var(--color-brand);
    background: var(--color-brand-soft);
    box-shadow: 0 0 0 1px var(--color-brand) inset;
}

.theme-option .theme-swatch {
    width: 28px;
    height: 28px;
    pointer-events: none;
}

.theme-option-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text);
    text-align: center;
}

/* Switch (toggle) — preferências booleanas, ex.: menu lateral retraído */
.switch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-3) 0;
    cursor: pointer;
}

.switch-row-text strong {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text);
}

.switch-row-text small {
    display: block;
    font-size: 11px;
    color: var(--color-text-muted);
    margin-top: 2px;
}

.switch {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
    width: 44px;
    height: 26px;
}

.switch input {
    position: absolute;
    inset: 0;
    opacity: 0;
    margin: 0;
    cursor: pointer;
    z-index: 1;
}

.switch-track {
    position: absolute;
    inset: 0;
    border-radius: var(--radius-full);
    background: var(--color-border);
    transition: background var(--transition);
}

.switch-thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 20px;
    height: 20px;
    border-radius: var(--radius-full);
    background: #fff;
    box-shadow: var(--shadow-sm);
    transition: transform var(--transition);
}

.switch input:checked ~ .switch-track {
    background: var(--color-brand);
}

.switch input:checked ~ .switch-track .switch-thumb {
    transform: translateX(18px);
}

.switch input:focus-visible ~ .switch-track {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   28. MODAL
   Padrão oficial para telas de cadastro/edição rápida — não criar páginas
   cheias para isso. Ver CLAUDE.md > "Padrão de modal" e a implementação de
   referência em Features/Usuarios/UsuarioModal.razor.
   -------------------------------------------------------------------------- */
.modal-wrapper {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-4);
}

.modal {
    width: min(100%, 520px);
    max-height: calc(100vh - var(--sp-8));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    animation: modalIn var(--transition-slow);
}

/* O <form> do EditForm embrulha .modal-body + .modal-footer — sem isso ele
   vira um único bloco de altura livre dentro do .modal (flex column) e o
   .modal-body nunca fica realmente "constrangido" o bastante pra rolar,
   empurrando o footer (com os botões) pra fora da área visível, sobretudo
   no mobile. Com isso o form também vira flex column, só o body cresce/rola
   e o footer some. */
.modal-form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* Modal larga — formulários com muitos campos (ex.: UsuarioModal). Em
   telas HD (prioridade do layout, ~1333px) dá pra abrir mão da altura e usar
   2 colunas de verdade (nenhum campo em .span-2), o form fica bem mais baixo. */
.modal-lg {
    width: min(100%, 680px);
}

/* Modal larga+ — mesmo caso de uso de .modal-lg (formulário denso sem abas),
   mas quando 680px ainda deixa os campos apertados (ex.: EventoModal, com
   Título/Tema ocupando as 2 colunas inteiras). Não é o mesmo motivo de
   .modal-xl (que existe pra compensar a barra de abas lateral) — por isso é
   uma classe própria, não a reaproveita. Usar no lugar de .modal-lg (não
   junto), mesma regra de combinação de .modal-xl. */
.modal-lg-wide {
    width: min(100%, 760px);
}

/* Modal extra larga — formulários com abas (.modal-tabs na lateral, ver
   abaixo). A barra de abas fica à esquerda do .modal-body só nela, então
   precisa de mais largura que .modal-lg pra sobrar espaço de verdade pro
   .form-grid de 2 colunas ao lado da barra. Usar no lugar de .modal-lg (não
   junto) — ver Features/Eventos/ParticipanteModal.razor. */
.modal-xl {
    width: min(100%, 860px);
}

/* Modal extra larga+ — mesmo caso de uso de .modal-xl (formulário com abas
   laterais), só mais larga (+100px) pra folgar o .form-grid-4 de 4 colunas
   (ver seção 17, FORMS) ao lado da barra de abas — 860px já ficava justo
   pra 4 colunas de verdade. Usar no lugar de .modal-xl (não junto), mesma
   regra de combinação de .modal-lg-wide. Hoje só usada em
   Features/Socios/SocioModal.razor — se outro modal com abas precisar de 4
   colunas, reaproveitar esta classe em vez de criar uma terceira. */
.modal-xl-wide {
    width: min(100%, 960px);
}

/* Modal cheia — visualizador de documento (informações + preview do PDF
   lado a lado, ver .document-viewer-body abaixo). Usar só quando a modal
   precisa aproveitar boa parte da largura/altura da tela, não é o padrão
   comum de cadastro/edição — ver Features/Documentos/VisualizarArquivoModal.razor. */
.modal-full {
    width: min(96vw, 1400px);
    height: min(88vh, 880px);
}

.modal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
    border-bottom: 1px solid var(--color-border);
    flex-shrink: 0;
}

.modal-title    { font-size: 17px; font-weight: 800; margin: 0; }
.modal-subtitle { font-size: 12px; color: var(--color-text-muted); margin: var(--sp-1) 0 0; }

/* Abas laterais dentro de uma modal — usar quando o formulário tem campos
   demais pra caber confortavelmente numa rolagem só (ver CLAUDE.md > "Padrão
   de modal": "se a modal continuar muito alta, o próximo recurso é dividir em
   etapas/abas"). .modal-columns é o wrapper que embrulha .modal-tabs +
   .modal-body lado a lado (fica entre .modal-header e .modal-footer, os dois
   fora do wrapper); só .modal-body rola, a barra de abas fica fixa. Cada
   painel de campos é um .form-grid normal dentro de .tab-panels, alternando
   .tab-panel-hidden (ver essa classe mais abaixo — mantém todo campo sempre
   no DOM e a altura da modal constante entre abas) — assim a validação do
   formulário inteiro continua funcionando mesmo numa aba escondida (ver
   ParticipanteModal.razor, troca automática pra aba com erro em
   OnInvalidSubmit). No mobile a barra volta a ficar horizontal em cima (ver
   media query no fim do arquivo) — largura é o recurso escasso ali, não
   altura. */
.modal-columns {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
}

.modal-tabs {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    width: 176px;
    flex-shrink: 0;
    padding: var(--sp-4) var(--sp-3);
    border-right: 1px solid var(--color-border);
    overflow-y: auto;
}

/* Avatar no topo da barra de abas (ex.: SocioModal — foto do sócio acima do
   botão "Dados pessoais"). Envolve o .profile-avatar (foto) + os botões de
   ação (.modal-tabs-avatar-actions) num bloco só. .profile-avatar não
   estica nem centraliza sozinho dentro de um flex column (largura fixa,
   sem align-self próprio) — sem isso ficaria colado na borda esquerda da
   coluna de 176px em vez de centralizado. Os `.modal-tab` continuam com
   width:100% normalmente, align-self:center aqui não afeta os outros
   filhos do mesmo .modal-tabs. */
.modal-tabs-avatar {
    align-self: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
}

/* Variante retangular de .profile-avatar — só pra foto de sócio dentro da
   barra de abas (ver .modal-tabs-avatar acima); .profile-avatar sozinho
   continua circular (Perfil.razor, foto de usuário) — não mexer na classe
   base, só sobrescrever aqui o que muda. border-radius: var(--radius-md) —
   "rounded padrão" (pedido explícito), o mesmo raio usado em cards/badges/
   modal-tabs (seção 2, DESIGN TOKENS) — não --radius-sm (esse é só pra
   .btn/.form-input, ver comentário lá) nem 0 (retangular "cru", testado
   antes e trocado por pedido explícito). Altura 106px (era 136px, -30px
   por pedido explícito) — largura (104px) não mudou, só a altura.
   Seletor composto ".profile-avatar.profile-avatar-rect" (não só
   ".profile-avatar-rect" sozinha) de propósito — a classe base
   ".profile-avatar" (seção 35, PERFIL DO USUÁRIO) fica DEPOIS desta regra
   no arquivo; com a mesma especificidade (0,0,1,0 cada), a última regra do
   arquivo vencia e a variante retangular nunca aparecia (bug real, já
   aconteceu). Especificidade maior (0,0,2,0) aqui garante a vitória
   independente da ordem no arquivo — não depender de ordem é mais seguro
   que só mover o bloco pra depois da seção 35. */
.profile-avatar.profile-avatar-rect {
    width: 104px;
    height: 106px;
    border-radius: var(--radius-md);
}

/* Variante pequena (miniatura circular, 40px) de .profile-avatar — pra foto
   de sócio dentro de uma linha de lista, não um bloco de destaque isolado
   (primeiro uso: dirigentes do sindicato, .mobile-list-item em
   Features/Mobile/Sindicato/Detalhes.razor). Mesmo fallback com ícone
   "person" de .profile-avatar (sem iniciais — o dirigente não tem um
   "nome curto" pronto igual usuário/sócio no formulário grande), só o
   tamanho do ícone precisa de ajuste próprio pro círculo menor não ficar
   com o ícone maior que o próprio avatar. Seletor composto
   (.profile-avatar.profile-avatar-sm) pelo mesmo motivo de especificidade
   de .profile-avatar-rect acima (ver CLAUDE.md, "Regras absolutas" nº 6). */
.profile-avatar.profile-avatar-sm {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
}

.profile-avatar.profile-avatar-sm .material-symbols-rounded {
    font-size: 20px;
}

/* Botões de ação da foto (remover / capturar pelo celular / capturar pela
   webcam / enviar do computador). Eram 26px/ícone 16px (mesmo critério de
   redução de .table .btn-icon, seção 21) — aumentados por pedido explícito
   ("estão bem pequenos, pode deixá-los mais evidentes") pra 32px/ícone 18px,
   ainda menor que o .btn-icon padrão (38px/22px, ação de toolbar) porque
   continuam sendo 4 ações compactas empilhadas sobre uma foto pequena, não
   uma barra de ferramentas. "Remover" continua `disabled` (sem endpoint de
   remoção ainda, ver Features/Socios/CLAUDE.md) — `title` explica o motivo,
   mesmo padrão de `.btn-icon:disabled` documentado em app.css seção 14. */
.modal-tabs-avatar-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-1);
}

.modal-tabs-avatar-actions .btn-icon {
    width: 32px;
    height: 32px;
}

.modal-tabs-avatar-actions .btn-icon .material-symbols-rounded {
    font-size: 18px;
}

.modal-tab {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    border: 0;
    border-left: 2px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-muted);
    font-size: 12px;
    font-weight: 600;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    transition: color var(--transition), background-color var(--transition), border-color var(--transition);
}

.modal-tab:hover {
    color: var(--color-text);
    background: var(--color-surface-strong);
}

.modal-tab.active {
    color: var(--color-brand);
    background: var(--color-brand-soft);
    border-left-color: var(--color-brand);
}

.modal-tab .material-symbols-rounded {
    font-size: 18px;
}

.modal-tab:disabled {
    opacity: .5;
    cursor: not-allowed;
    pointer-events: none;
}

.modal-body {
    padding: var(--sp-5);
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
}

/* Empilha os painéis de uma modal com abas na mesma célula de grid — a
   .modal (e por consequência o .modal-body) precisa manter sempre a mesma
   altura ao trocar de aba, mesmo abas com quantidades de campo bem
   diferentes (ex.: Endereço tem 1 campo, Dados pessoais tem 7). Com todos
   os painéis na mesma célula, a linha do grid é dimensionada pelo maior
   painel o tempo todo, então a altura não pula ao trocar de aba. Por isso o
   painel oculto usa .tab-panel-hidden (visibility:hidden — some da tela mas
   continua ocupando espaço/participando do cálculo de altura), nunca
   .d-none (display:none tiraria o painel do cálculo e a altura voltaria a
   variar por aba). */
.tab-panels {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
}

.tab-panels > .form-grid {
    grid-column: 1;
    grid-row: 1;
}

.tab-panel-hidden {
    visibility: hidden;
}

.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5) var(--sp-5);
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
}

/* Corpo do visualizador de documento — informações (esquerda) + preview do
   PDF (direita) lado a lado, ver Features/Documentos/VisualizarArquivoModal.razor.
   Substitui o .modal-body padrão (que teria padding único pra tudo): aqui
   cada coluna cuida do próprio padding pra o preview poder ocupar a área
   inteira, sem margem em volta do PDF. */
.document-viewer-body {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
}

.document-viewer-info {
    flex: 0 0 240px;
    padding: var(--sp-5);
    overflow-y: auto;
    border-right: 1px solid var(--color-border);
}

.document-viewer-info .detail-list {
    grid-template-columns: 1fr;
    row-gap: var(--sp-1);
    margin-top: 0;
}

.document-viewer-info .detail-list dd {
    margin-bottom: var(--sp-3);
}

.document-viewer-preview {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    background: var(--color-surface-strong);
}

/* .empty-state, sozinho, só centraliza o próprio conteúdo — não a si mesmo
   dentro do pai. Aqui (nenhum documento selecionado ainda em
   DocumentosParticipanteModal) ele precisa esticar pra ocupar a coluna de
   preview inteira, senão fica colado no topo em vez de centralizado. */
.document-viewer-preview .empty-state {
    flex: 1 1 auto;
}

/* Visualizador de PDF via PDF.js (ver Components/Shared/PdfViewer.razor e
   wwwroot/js/pdf-viewer.js) — renderiza cada página num <canvas> criado pelo
   JS dentro de .pdf-viewer-canvas-wrap. Usado dentro de .document-viewer-preview,
   mas genérico o bastante pra qualquer outro lugar que precise mostrar um PDF. */
.pdf-viewer {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
}

/* Envolve o container que o JS manipula direto (.pdf-viewer-canvas-wrap) —
   fica relative pra .pdf-viewer-loading poder se posicionar por cima via
   absolute, sem entrar como filho Blazor daquele container (o JS já
   controla o innerHTML dele; misturar os dois causaria conflito de DOM). */
.pdf-viewer-canvas-area {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
}

/* Não usar display:flex + justify-content:center aqui — é um bug conhecido
   do Flexbox: quando o item centralizado fica maior que o container (canvas
   com zoom > 100%), o navegador só permite rolar até o fim de UM dos lados,
   deixando o outro lado do canvas inacessível mesmo com overflow:auto. Em
   layout de bloco normal, margin:0 auto no canvas (ver regra abaixo) centraliza
   igual quando ele cabe, e quando não cabe as margens auto colapsam pra 0 —
   o scroll passa a alcançar os dois lados normalmente. */
.pdf-viewer-canvas-wrap {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: var(--sp-4);
}

.pdf-viewer-canvas-wrap canvas {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0 auto;
    box-shadow: var(--shadow-md);
}

/* Acima de 100% de zoom (ver .pdf-viewer-zoom abaixo) o canvas precisa do
   tamanho real renderizado pelo PDF.js, maior que o container — sem isso o
   max-width:100% de cima encolheria a página de volta, anulando o zoom. O
   wrap já tem overflow:auto, então o excesso só passa a rolar. Classe
   alternada via JS (wwwroot/js/pdf-viewer.js, renderPagina). */
.pdf-viewer-canvas-wrap--zoom canvas {
    max-width: none;
}

.pdf-viewer-loading {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    background: var(--color-surface-strong);
}

.pdf-viewer-loading .material-symbols-rounded {
    font-size: 36px;
    color: var(--color-text-muted);
    opacity: .6;
}

.pdf-viewer-loading-text {
    margin: 0;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-muted);
}

/* Barra de progresso genérica (`<progress>` nativo) — usada no preview de PDF
   (download) e no modal de envio via FTP (upload). Nunca usar `style` inline
   pra largura da barra em si; `<progress>` já resolve isso via atributo
   `value`, só o container (largura/altura/cor) é CSS. */
.progress-bar {
    width: 220px;
    height: 6px;
    accent-color: var(--color-brand);
}

.pdf-viewer-empty {
    flex: 1 1 auto;
    min-height: 0;
}

.pdf-viewer-controls {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3);
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
}

.pdf-viewer-page {
    min-width: 120px;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-align: center;
}

.pdf-viewer-zoom {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.pdf-viewer-zoom-valor {
    min-width: 44px;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-align: center;
}

/* Separa o grupo de zoom do grupo de paginação dentro de .pdf-viewer-controls
   quando os dois aparecem juntos (documento com mais de 1 página). */
.pdf-viewer-divider {
    width: 1px;
    height: 20px;
    background: var(--color-border);
}

@keyframes modalIn {
    from { opacity: 0; transform: translateY(12px) scale(.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* --------------------------------------------------------------------------
   29. RESPONSIVO
   -------------------------------------------------------------------------- */

/* Notebook HD — 1333 × 760 */
@media (max-width: 1440px) {
    :root {
        --sidebar-width: 248px;
        --topbar-height: 50px;
    }

    .app-content { padding: var(--sp-5); }
    .kpi-grid    { gap: var(--sp-3); }
    .topbar-location { max-width: 300px; }
}

/* Tablet / notebook pequeno */
@media (max-width: 1024px) {
    .kpi-grid    { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .content-grid { grid-template-columns: 1fr; }
    .topbar-location { max-width: 220px; }
    .user-meta   { display: none; }
    .user-menu-chevron { display: none; }
}

/* Mobile */
@media (max-width: 767px) {
    :root { --topbar-height: 46px; }

    .app-content  { padding: var(--sp-4); }

    .kpi-grid     { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .content-grid { grid-template-columns: 1fr; }

    .detail-list  { grid-template-columns: 1fr; row-gap: var(--sp-1); }
    .detail-list dd { margin-bottom: var(--sp-2); }

    .page-header    { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }
    .section-header { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }

    .topbar-location { display: none; }

    .table-toolbar { flex-direction: column; align-items: stretch; }
    .table-filters { flex-direction: column; align-items: stretch; }
    .table-search-input { min-width: 0; width: 100%; }

    .table        { display: block; overflow-x: auto; }

    .pagination   { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }

    .user-meta    { display: none; }
    .user-menu-chevron { display: none; }

    .login-card   { padding: var(--sp-5); }

    /* Modal — mobile-first: manter 2 colunas nos campos curtos (não colapsar
       tudo pra 1 coluna, senão a modal fica bem mais alta no mobile do que
       no desktop) e reduzir os respiros verticais pra caber mais sem rolagem. */
    .modal-wrapper { padding: var(--sp-3); }
    .modal         { max-height: calc(100vh - var(--sp-6)); }
    .modal-header  { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
    .modal-body    { padding: var(--sp-4); }
    .modal-footer  { padding: var(--sp-3) var(--sp-4) var(--sp-4); }

    /* Abas: no mobile largura é o recurso escasso (não altura) — volta pra
       barra horizontal em cima do .modal-body, igual ao layout de desktop
       anterior a esta seção. */
    .modal-columns { flex-direction: column; }
    .modal-tabs {
        flex-direction: row;
        width: auto;
        padding: 0 var(--sp-4);
        border-right: 0;
        border-bottom: 1px solid var(--color-border);
        overflow-x: auto;
        overflow-y: visible;
    }
    /* .modal-tabs vira barra horizontal aqui (ver comentário acima) — um
       avatar de 120px alinhado como se fosse mais um item dessa linha
       deixaria a barra tão alta quanto ele. Foto some no mobile; a
       identificação do sócio continua disponível na aba "Dados pessoais"
       (nome, CPF etc.), que abre por padrão em modo edição. */
    .modal-tabs-avatar {
        display: none;
    }
    .modal-tab {
        width: auto;
        padding: var(--sp-3) var(--sp-2);
        border-left: 0;
        border-bottom: 2px solid transparent;
    }
    .modal-tab.active {
        border-bottom-color: var(--color-brand);
    }
    .form-field.span-2-mobile { grid-column: 1 / -1; }
    .form-grid     { gap: var(--sp-3); }
    .form-stack    { gap: var(--sp-3); }
    .check-grid    { grid-template-columns: 1fr; }

    /* Visualizador de documento: no mobile largura também é escassa, então
       info e preview empilham (info primeiro, com altura limitada e rolagem
       própria) em vez de ficarem lado a lado. */
    .modal-full { width: 100%; height: calc(100vh - var(--sp-6)); }
    .document-viewer-body { flex-direction: column; }
    .document-viewer-info {
        flex: 0 0 auto;
        max-height: 40vh;
        border-right: 0;
        border-bottom: 1px solid var(--color-border);
    }
    .document-viewer-preview { min-height: 280px; }
}

/* Mobile pequeno */
@media (max-width: 480px) {
    .kpi-grid { grid-template-columns: 1fr; }
    .topbar   { padding: 0 var(--sp-3); gap: var(--sp-2); }
}

/* --------------------------------------------------------------------------
   30. TABS DE PÁGINA
   Menu de abas horizontal no topo de uma seção inteira da página (diferente
   de .modal-tabs da seção 28, que é lateral e vive dentro de uma modal).
   Referência: Features/Eventos/Detalhes.razor (abas "Informações"/
   "Participantes" logo abaixo do .kpi-grid) — cada aba troca qual
   .page-card aparece embaixo via @if simples (não precisa do truque de
   grid empilhado usado nas abas de modal, já que aqui é uma página normal
   com rolagem própria, não uma caixa de altura limitada).
   -------------------------------------------------------------------------- */
.page-tabs {
    display: flex;
    gap: var(--sp-1);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--sp-4);
    overflow-x: auto;
    scrollbar-width: none;
}

.page-tabs::-webkit-scrollbar { display: none; }

.page-tab {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}

.page-tab:hover {
    color: var(--color-text);
}

.page-tab.active {
    color: var(--color-brand);
    border-bottom-color: var(--color-brand);
}

.page-tab .material-symbols-rounded {
    font-size: 18px;
}

/* Título (h2) + ação lado a lado dentro de um .page-card — mesma ideia do
   .page-header da seção 22, só que para o cabeçalho de uma seção dentro de
   um card (ex.: "Participantes" + botão "Cadastrar participante"), não o
   h1 da página inteira. */
.section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-4);
    margin-bottom: var(--sp-4);
}

.section-header h2 {
    margin: 0;
}

/* Linha de botões de ação dentro de um .page-card (ex.: "Ações rápidas" na
   aba Informações de Features/Eventos/Detalhes.razor) — quebra pra próxima
   linha em telas estreitas em vez de espremer os botões. */
.quick-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
}

/* Sanfona/accordion colapsada por padrão dentro de um .page-card WEB — mesmo
   espírito de .mobile-accordion-toggle (seção "APP MOBILE"), mas sem
   depender de .mobile-card (exclusivo do shell mobile, ver Features/Mobile/
   CLAUDE.md). Combinar sempre com .section-header (reseta a aparência de
   <button>, .section-header já dá o layout flex/space-between). Primeiro
   consumidor: Features/Sindicato/Detalhes.razor ("Dados principais"). */
.accordion-toggle {
    width: 100%;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 15px;
    font-weight: 800;
    color: var(--color-text);
    text-align: left;
    cursor: pointer;
}

.accordion-icon {
    color: var(--color-text-muted);
    transition: transform var(--transition);
    flex-shrink: 0;
}

.accordion-icon--open {
    transform: rotate(180deg);
}

/* --------------------------------------------------------------------------
   31. GRÁFICOS
   Gráfico de barras em SVG puro (sem lib JS), coordenadas calculadas em
   C# no code-behind — ver "### Gráfico de participantes por sexo e faixa
   etária" no CLAUDE.md. Cores sempre via var(--color-brand*)/--color-text-
   muted, nunca hex fixo, pra reagir ao tema de cor escolhido e ao dark mode
   automaticamente. Referência: Features/Eventos/Detalhes.razor.
   -------------------------------------------------------------------------- */
.chart-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-4);
}

.chart-svg {
    display: block;
    width: 100%;
    max-width: 480px;
    height: auto;
}

.chart-svg text {
    font-family: inherit;
}

.chart-eixo-label {
    fill: var(--color-text);
    font-size: 10px;
    font-weight: 600;
}

.chart-eixo-label-sub {
    fill: var(--color-text-muted);
    font-size: 9px;
    font-weight: 400;
}

.chart-bar-valor {
    fill: var(--color-text);
    font-size: 10px;
    font-weight: 600;
}

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--sp-4);
}

.chart-legend-item {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: 12px;
    color: var(--color-text-muted);
}

.chart-legend-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: var(--radius-sm);
}

/* Cores das 3 séries (Homens/Mulheres/Não informado) — a mesma classe
   colore o preenchimento da barra (rect.chart-cor-x) e o quadradinho da
   legenda (.chart-legend-swatch.chart-cor-x), cada seletor pegando a
   propriedade certa pro tipo de elemento (fill vs background). */
rect.chart-cor-homens {
    fill: var(--color-brand-strong);
}

rect.chart-cor-mulheres {
    fill: var(--color-brand);
}

rect.chart-cor-neutro {
    fill: var(--color-text-muted);
}

.chart-legend-swatch.chart-cor-homens {
    background: var(--color-brand-strong);
}

.chart-legend-swatch.chart-cor-mulheres {
    background: var(--color-brand);
}

.chart-legend-swatch.chart-cor-neutro {
    background: var(--color-text-muted);
}

.chart-pie-svg {
    width: min(100%, 260px);
    height: auto;
    display: block;
    margin: 0 auto var(--sp-4);
    overflow: visible;
}

.chart-pie-track {
    fill: none;
    stroke: var(--color-surface-strong);
    stroke-width: 18;
}

.chart-pie-segment {
    fill: none;
    stroke-width: 18;
    stroke-linecap: round;
    transition: opacity var(--transition);
}

.chart-pie-segment:hover {
    opacity: .86;
}

.chart-pie-segment.chart-cor-homens {
    stroke: var(--color-brand);
}

.chart-pie-segment.chart-cor-mulheres {
    stroke: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-pie-total {
    fill: var(--color-text);
    font-size: 17px;
    font-weight: 800;
}

.chart-pie-caption {
    fill: var(--color-text-muted);
    font-size: 6px;
    font-weight: 600;
    text-transform: uppercase;
}

.chart-cor-homens {
    fill: var(--color-brand);
}

.chart-cor-mulheres {
    fill: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-cor-neutro {
    fill: color-mix(in srgb, var(--color-text-muted) 70%, var(--color-brand));
}

.chart-legend-swatch.chart-cor-homens {
    background: var(--color-brand);
}

.chart-legend-swatch.chart-cor-mulheres {
    background: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-legend-swatch.chart-cor-neutro {
    background: color-mix(in srgb, var(--color-text-muted) 70%, var(--color-brand));
}

.event-overview-card .detail-list {
    margin-bottom: var(--sp-5);
}

.event-overview-footer {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-4);
    align-items: end;
    padding-top: var(--sp-4);
    border-top: 1px solid var(--color-border);
}

.event-overview-kpis {
    margin-bottom: 0;
}

.event-overview-actions {
    justify-content: flex-end;
    align-items: flex-end;
    flex-wrap: wrap;
}

.event-charts-grid {
    grid-template-columns: minmax(0, 1.45fr) minmax(280px, .55fr);
}

.chart-donut-wrap {
    display: grid;
    place-items: center;
    padding: var(--sp-3) 0 var(--sp-4);
}

.chart-donut-svg {
    width: min(100%, 260px);
    height: auto;
    display: block;
    overflow: visible;
}

.chart-donut-track {
    fill: none;
    stroke: var(--color-surface-strong);
    stroke-width: 20;
}

.chart-donut-segment {
    fill: none;
    stroke-width: 20;
    stroke-linecap: butt;
    transition: opacity var(--transition);
}

.chart-donut-segment:hover {
    opacity: .86;
}

.chart-donut-segment.chart-cor-homens {
    stroke: var(--color-brand);
}

.chart-donut-segment.chart-cor-mulheres {
    stroke: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-donut-total {
    fill: var(--color-text);
    font-size: 19px;
    font-weight: 800;
}

.chart-donut-caption {
    fill: var(--color-text-muted);
    font-size: 6px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.chart-cor-homens {
    fill: var(--color-brand);
}

.chart-cor-mulheres {
    fill: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-cor-neutro {
    fill: color-mix(in srgb, var(--color-text-muted) 70%, var(--color-brand));
}

.chart-legend-swatch.chart-cor-homens {
    background: var(--color-brand);
}

.chart-legend-swatch.chart-cor-mulheres {
    background: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-legend-swatch.chart-cor-neutro {
    background: color-mix(in srgb, var(--color-text-muted) 70%, var(--color-brand));
}

@media (max-width: 1024px) {
    .event-overview-footer {
        grid-template-columns: 1fr;
        align-items: stretch;
    }

    .event-overview-actions {
        justify-content: flex-start;
    }

    .event-charts-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 767px) {
    .event-overview-actions {
        flex-direction: column;
        align-items: stretch;
    }

    .event-overview-actions .btn {
        width: 100%;
        justify-content: flex-start;
    }
}

.event-overview-card {
    margin-bottom: var(--sp-4);
}

.event-overview-content {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 220px;
    gap: var(--sp-5);
    align-items: start;
}

.event-overview-list {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-4);
    margin: 0;
}

.event-overview-list div {
    min-width: 0;
}

.event-overview-list dt {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.event-overview-list dd {
    margin: var(--sp-1) 0 0;
    color: var(--color-text);
    font-size: 13px;
    font-weight: 650;
    line-height: 1.35;
}

.event-overview-metric {
    padding: var(--sp-3);
    border-radius: var(--radius-md);
    background: var(--color-brand-ghost);
}

.event-overview-metric dt {
    color: var(--color-brand-strong);
}

.event-overview-metric dd {
    color: var(--color-brand);
    font-size: 21px;
    font-weight: 800;
    line-height: 1;
}

.event-overview-actions {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding-left: var(--sp-5);
    border-left: 1px solid var(--color-border);
}

.event-overview-actions .btn {
    justify-content: flex-start;
    width: 100%;
}

.event-charts-grid {
    grid-template-columns: minmax(0, 1.45fr) minmax(300px, .55fr);
    align-items: stretch;
}

.event-charts-grid > .page-card {
    height: 100%;
}

.event-chart-card {
    display: flex;
    flex-direction: column;
}

.event-chart-body {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.event-chart-body .chart-legend {
    margin-top: auto;
}

.chart-donut-wrap {
    flex: 1;
    display: grid;
    place-items: center;
    padding: var(--sp-3) 0 var(--sp-4);
}

.chart-donut-svg {
    width: min(100%, 260px);
    height: auto;
    display: block;
    overflow: visible;
}

.chart-donut-hole {
    fill: var(--color-surface);
}

.chart-donut-segment {
    transition: opacity var(--transition), filter var(--transition);
}

.chart-donut-segment:hover {
    opacity: .9;
    filter: brightness(.98);
}

.chart-donut-segment.chart-cor-homens,
.chart-cor-homens {
    fill: var(--color-brand);
}

.chart-donut-segment.chart-cor-mulheres,
.chart-cor-mulheres {
    fill: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-cor-neutro {
    fill: color-mix(in srgb, var(--color-text-muted) 70%, var(--color-brand));
}

.chart-donut-total {
    fill: var(--color-text);
    font-size: 19px;
    font-weight: 800;
}

.chart-donut-caption {
    fill: var(--color-text-muted);
    font-size: 6px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.chart-legend-swatch.chart-cor-homens {
    background: var(--color-brand);
}

.chart-legend-swatch.chart-cor-mulheres {
    background: color-mix(in srgb, var(--color-brand) 58%, #ffffff);
}

.chart-legend-swatch.chart-cor-neutro {
    background: color-mix(in srgb, var(--color-text-muted) 70%, var(--color-brand));
}

@media (max-width: 1024px) {
    .event-overview-content {
        grid-template-columns: 1fr;
    }

    .event-overview-actions {
        padding-left: 0;
        padding-top: var(--sp-4);
        border-left: 0;
        border-top: 1px solid var(--color-border);
    }

    .event-charts-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 767px) {
    .event-overview-list {
        grid-template-columns: 1fr;
    }
}


/* --------------------------------------------------------------------------
   31. PAGE HEADER — Components/Shared/PageHeader.razor
   Cabeçalho padrão de páginas Blazor: título, subtítulo, badges, metadados e
   ações, mais o link "Voltar" opcional. Único bloco de regras pra
   .app-page-header* — havia um bloco inteiro duplicado aqui (mesmas
   propriedades, "final do arquivo pra sobrescrever" que nunca sobrescrevia
   nada de verdade), consolidado numa única fonte pra evitar as duas versões
   divergirem em silêncio no futuro.

   Botão "Voltar" (VoltarUrl) — no sistema WEB fica acima do bloco
   título/subtítulo (padrão de sempre, `.app-page-header-back`). O padrão
   "ao lado do título, alinhado verticalmente" existe só no app MOBILE
   (`.mobile-header-row`/`.mobile-back-link`, ver seção "APP MOBILE" mais
   abaixo) — pedido explícito pra não aplicar essa mudança de layout no WEB.
   -------------------------------------------------------------------------- */

.app-page-header {
    display: block;
    width: 100%;
    margin-bottom: var(--sp-5);
}

.app-page-header-main {
    width: 100%;
    min-width: 0;
}

.app-page-header-content-row {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-5);
}

.app-page-header-title-block {
    min-width: 0;
    flex: 1 1 auto;
}

.app-page-header-title-block h1 {
    margin: 0;
    font-size: 21px;
    font-weight: 800;
    line-height: 1.15;
    color: var(--color-text);
}

.app-page-header-subtitle-row {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
    margin-top: var(--sp-1);
}

.app-page-header-subtitle-row p {
    margin: 0;
    color: var(--color-text-muted);
    font-size: 12px;
    line-height: 1.35;
}

.app-page-header-badges {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
}

.app-page-header-badges .badge {
    line-height: 1.3;
}

.app-page-header-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sp-2);
    flex: 0 0 auto;
    margin-left: auto;
}

.app-page-header-meta {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-wrap: wrap;
    margin-top: var(--sp-3);
    color: var(--color-text-muted);
    font-size: 12px;
}

.app-page-header-meta span {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
}

.app-page-header-back {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-1);
    min-height: 32px;
    padding: 0 var(--sp-2);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    text-decoration: none;
    transition: background var(--transition), color var(--transition);
}

.app-page-header-back:hover {
    background: var(--color-surface-strong);
    color: var(--color-text);
}

.app-page-header-back:focus-visible {
    outline: 3px solid var(--focus-ring);
    outline-offset: 2px;
}

.app-page-header-back .material-symbols-rounded {
    font-size: 20px;
    line-height: 1;
}

@media (max-width: 767px) {
    .app-page-header-content-row {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--sp-3);
    }

    .app-page-header-actions {
        justify-content: flex-start;
        flex-wrap: wrap;
        width: 100%;
        margin-left: 0;
    }

    .app-page-header-actions .btn {
        width: 100%;
        justify-content: flex-start;
    }
}

/* Tabs de página: permite rolagem horizontal quando necessário, mas impede
   o scrollbar vertical fino que estava aparecendo na tela de detalhes. */
.page-tabs {
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
}

.page-tabs::-webkit-scrollbar {
    display: none;
}

.page-tab {
    flex-shrink: 0;
}

/* Card de informações do evento. */
.event-overview-card {
    margin-bottom: var(--sp-4);
}

.event-overview-content {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 220px;
    gap: var(--sp-5);
    align-items: start;
}

.event-overview-list {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-4);
    margin: 0;
}

.event-overview-list div {
    min-width: 0;
}

.event-overview-list dt {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.event-overview-list dd {
    margin: var(--sp-1) 0 0;
    color: var(--color-text);
    font-size: 13px;
    font-weight: 650;
    line-height: 1.35;
}

.event-overview-metric {
    padding: var(--sp-3);
    border-radius: var(--radius-md);
    background: var(--color-brand-ghost);
}

.event-overview-metric dt {
    color: var(--color-brand-strong);
}

.event-overview-metric dd {
    color: var(--color-brand);
    font-size: 21px;
    font-weight: 800;
    line-height: 1;
}

.event-overview-actions {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding-left: var(--sp-5);
    border-left: 1px solid var(--color-border);
}

.event-overview-actions .btn {
    justify-content: flex-start;
    width: 100%;
}



/* --------------------------------------------------------------------------
   CHARTS
   Componentes genéricos para gráficos com Chart.js.
   -------------------------------------------------------------------------- */

.chart-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4);
    align-items: stretch;
}

.chart-grid-main-aside {
    grid-template-columns: minmax(0, 1.45fr) minmax(340px, .55fr);
}

.chart-grid > .chart-card {
    height: 100%;
    align-self: stretch;
}

.chart-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 440px;
}

.chart-card-sm {
    min-height: 340px;
}

.chart-card-md {
    min-height: 440px;
}

.chart-card-lg {
    min-height: 500px;
}

.chart-header {
    flex: 0 0 auto;
    margin-bottom: var(--sp-4);
}

.chart-body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.chart-empty {
    flex: 1 1 auto;
    min-height: 280px;
}

.app-chart {
    position: relative;
    width: 100%;
    height: 320px;
    min-height: 320px;
    max-height: 320px;
    flex: 0 0 auto;
}

.app-chart-sm {
    height: 260px;
    min-height: 260px;
    max-height: 260px;
}

.app-chart-md {
    height: 320px;
    min-height: 320px;
    max-height: 320px;
}

.app-chart-lg {
    height: 380px;
    min-height: 380px;
    max-height: 380px;
}

.app-chart-xl {
    height: 440px;
    min-height: 440px;
    max-height: 440px;
}

.app-chart canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
}

@media (max-width: 1024px) {
    .chart-grid,
    .chart-grid-main-aside {
        grid-template-columns: 1fr;
    }

    .chart-card,
    .chart-card-md,
    .chart-card-lg {
        min-height: 380px;
    }
}

@media (max-width: 767px) {
    .chart-card,
    .chart-card-md,
    .chart-card-lg {
        min-height: 340px;
    }

    .app-chart,
    .app-chart-md,
    .app-chart-lg,
    .app-chart-xl {
        height: 280px;
        min-height: 280px;
        max-height: 280px;
    }

    .app-chart-sm {
        height: 240px;
        min-height: 240px;
        max-height: 240px;
    }
}

/* --------------------------------------------------------------------------
   SUMMARY CARD
   Card genérico para resumo de entidade/registro: dados, métricas e ações.
   -------------------------------------------------------------------------- */

.summary-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.summary-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 220px;
    gap: var(--sp-5);
    align-items: stretch;
}

.summary-main {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    min-width: 0;
}

.summary-data-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-4);
}

.summary-data-item {
    min-width: 0;
}

.summary-data-item dt {
    margin: 0;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.summary-data-item dd {
    margin: var(--sp-1) 0 0;
    font-size: 13px;
    font-weight: 700;
    line-height: 1.35;
    color: var(--color-text);
}

.summary-metric-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-3);
}

.summary-metric {
    padding: var(--sp-3);
    border-radius: var(--radius-md);
    background: var(--color-brand-ghost);
    min-width: 0;
}

.summary-metric dt {
    margin: 0;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--color-brand-strong);
}

.summary-metric dd {
    margin: var(--sp-1) 0 0;
    font-size: 23px;
    font-weight: 800;
    line-height: 1;
    color: var(--color-brand);
}

.summary-actions {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding-left: var(--sp-5);
    border-left: 1px solid var(--color-border);
}

.summary-actions .btn {
    width: 100%;
    justify-content: flex-start;
}

@media (max-width: 1200px) {
    .summary-data-grid,
    .summary-metric-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 1024px) {
    .summary-layout {
        grid-template-columns: 1fr;
    }

    .summary-actions {
        padding-left: 0;
        padding-top: var(--sp-4);
        border-left: 0;
        border-top: 1px solid var(--color-border);
    }
}

@media (max-width: 767px) {
    .summary-data-grid,
    .summary-metric-grid {
        grid-template-columns: 1fr;
    }
}

/* --------------------------------------------------------------------------
   32. OVERRIDES FINAIS — COMPONENTES GENÉRICOS DE RESUMO E CHARTS
   --------------------------------------------------------------------------
   Esta seção prevalece sobre regras antigas de gráficos SVG e classes antigas
   específicas de Eventos. O padrão novo é genérico e deve ser usado em qualquer
   página: chart-grid, chart-card, chart-header, chart-body, app-chart e
   summary-card.
   -------------------------------------------------------------------------- */

/* TABS: horizontal quando precisar, sem scrollbar vertical. */
.page-tabs {
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
}

.page-tabs::-webkit-scrollbar {
    display: none;
}

.page-tab {
    flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   CHART GRID / CARD — genérico
   -------------------------------------------------------------------------- */

.chart-grid {
    display: grid;
    width: 100%;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4);
    align-items: stretch;
}

.page-card + .chart-grid {
    margin-top: var(--sp-4);
}

.chart-grid-main-aside {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
}

.chart-grid > .page-card + .page-card {
    margin-top: 0;
}

.chart-grid > .chart-card,
.chart-grid > .page-card.chart-card {
    align-self: stretch;
}

.chart-card {
    --chart-height: 330px;

    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 0;
    min-width: 0;
    overflow: hidden;
}

.chart-body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
}

.chart-empty {
    flex: 1 1 auto;
    min-height: 0;
}

/* Chart.js precisa de uma caixa com altura fechada. Não usar height:100%
   aqui, porque isso pode gerar crescimento infinito dentro de flex/grid. */
.app-chart {
    position: relative;
    display: block;
    width: 100%;
    height: var(--chart-height, 330px);
    min-height: var(--chart-height, 330px);
    max-height: var(--chart-height, 330px);
    flex: 0 0 var(--chart-height, 330px);
    overflow: hidden;
}

.app-chart-sm {
    --chart-height: 250px;
}

.app-chart-md {
    --chart-height: 330px;
}

.app-chart-lg {
    --chart-height: 350px;
}

.app-chart-xl {
    --chart-height: 420px;
}

.app-chart canvas {
    display: block;
    width: 100% !important;
    height: 100% !important;
    max-width: 100%;
    max-height: 100%;
}

@media (max-width: 1024px) {
    .chart-grid,
    .chart-grid-main-aside,
    .chart-grid-3 {
        grid-template-columns: 1fr;
    }

    .chart-card,
    .chart-card-md,
    .chart-card-lg,
    .chart-card-xl {
        --chart-height: 310px;
    }
}

@media (max-width: 767px) {
    .chart-card,
    .chart-card-md,
    .chart-card-lg,
    .chart-card-xl {
        --chart-height: 250px;
    }

    .chart-card-sm {
        --chart-height: 220px;
    }
}

/* --------------------------------------------------------------------------
   SUMMARY CARD — genérico
   -------------------------------------------------------------------------- */

.summary-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.summary-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 240px;
    gap: var(--sp-5);
    align-items: stretch;
}

.summary-main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.summary-data-grid,
.summary-metric-grid {
    margin: 0;
}

.summary-data-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-4);
}

.summary-data-item {
    min-width: 0;
}

.summary-data-item dt {
    margin: 0;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.summary-data-item dd {
    margin: var(--sp-1) 0 0;
    color: var(--color-text);
    font-size: 13px;
    font-weight: 700;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

.summary-metric-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-3);
}

.summary-metric {
    min-width: 0;
    padding: var(--sp-3);
    border-radius: var(--radius-md);
    background: var(--color-brand-ghost);
}

.summary-metric dt {
    margin: 0;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--color-brand-strong);
}

.summary-metric dd {
    margin: var(--sp-1) 0 0;
    font-size: 23px;
    font-weight: 800;
    line-height: 1;
    color: var(--color-brand);
}

.summary-actions {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--sp-2);
    padding-left: var(--sp-5);
    border-left: 1px solid var(--color-border);
}

.summary-actions .eyebrow {
    text-align: left;
}

.summary-actions .btn {
    width: 100%;
    justify-content: flex-start;
}

@media (max-width: 1200px) {
    .summary-data-grid,
    .summary-metric-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 1024px) {
    .summary-layout {
        grid-template-columns: 1fr;
    }

    .summary-actions {
        justify-content: flex-start;
        padding-left: 0;
        padding-top: var(--sp-4);
        border-left: 0;
        border-top: 1px solid var(--color-border);
    }
}

@media (max-width: 767px) {
    .summary-data-grid,
    .summary-metric-grid {
        grid-template-columns: 1fr;
    }
}


/* --------------------------------------------------------------------------
   32. BUSCA DE PARTICIPANTE POR CPF / LISTAS ESTÁTICAS DE ITEM + AÇÃO
   Origem: aba "Iniciar" do cadastro de participante (Features/Eventos/
   ParticipanteModal.razor, modo cadastro) — lista estática de candidatos encontrados
   (cadastro em outro evento / sócio), diferente de .autocomplete-list (que é
   um dropdown posicionado em cima de um input). Reaproveitada também pela
   lista de documentos anexados em Features/Eventos/
   DocumentosParticipanteModal.razor — qualquer lista curta de "item com
   nome/detalhe + ação" pode reusar essas mesmas classes.
   -------------------------------------------------------------------------- */
.participante-busca-form-row {
    display: flex;
    gap: var(--sp-2);
}

.participante-busca-form-row .form-input {
    flex: 1 1 auto;
}

.participante-busca-lista {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.participante-busca-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
}

/* Item "selecionável" (DocumentosParticipanteModal — escolhe qual documento
   aparece no preview ao lado). A área clicável é um <button> em vez do
   .participante-busca-item inteiro porque o item também tem um <a> de ação
   ("abrir em nova guia") — um <button> não pode conter um <a> (aninhamento
   de elementos interativos é inválido em HTML). */
.participante-busca-item.selecionado {
    border-color: var(--color-brand);
    background: var(--color-brand-soft);
    box-shadow: 0 0 0 1px var(--color-brand) inset;
}

.participante-busca-item-select {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.participante-busca-info {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    min-width: 0;
}

.participante-busca-nome {
    font-weight: 600;
    color: var(--color-text);
}

.participante-busca-detalhe {
    font-size: 12px;
    color: var(--color-text-muted);
}

@media (max-width: 767px) {
    .participante-busca-form-row {
        flex-direction: column;
    }

    .participante-busca-item {
        flex-direction: column;
        align-items: stretch;
    }
}

/* --------------------------------------------------------------------------
   33. DASHBOARD — CARROSSEL DE EVENTOS
   Carrossel simples (sem lib JS) pros últimos eventos no Dashboard — rolagem
   nativa com scroll-snap, dois .btn-icon de navegação chamam scrollCarrossel()
   (wwwroot/js/app.js) pra deslocar a trilha. Reaproveitar essa mesma estrutura
   pro próximo carrossel que precisar de "cards roláveis + setas".
   -------------------------------------------------------------------------- */
.carousel {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.carousel-nav {
    flex-shrink: 0;
}

.carousel-track {
    display: flex;
    flex: 1 1 auto;
    gap: var(--sp-4);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    padding: var(--sp-1);
}

.carousel-item {
    display: flex;
    flex: 0 0 480px;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: inherit;
    text-decoration: none;
    scroll-snap-align: start;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.carousel-item:hover,
.carousel-item:focus-visible {
    border-color: var(--color-brand);
    box-shadow: var(--shadow-sm);
    outline: none;
}

.carousel-item-titulo {
    font-weight: 600;
    color: var(--color-text);
}

.carousel-item-detalhe {
    font-size: 12px;
    color: var(--color-text-muted);
}

@media (max-width: 767px) {
    .carousel-item {
        flex-basis: 400px;
    }
}

/* --------------------------------------------------------------------------
   34. CAPTURA MOBILE POR QR CODE
   QR Code exibido em Components/Shared/MobileCaptureQrCode.razor (desktop,
   aponta pra /mobile/captura-foto/{token}). A página mobile em si
   (Features/Mobile/CapturaFoto.razor) reaproveita .login-page/.login-card
   (mesmo layout de página cheia centralizada do Login), sem precisar de
   classe de página nova. Reaproveitar .mobile-capture-qr-image pro próximo
   QR Code que a aplicação precisar exibir.
   -------------------------------------------------------------------------- */
.mobile-capture {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-3);
}

.mobile-capture-qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
}

.mobile-capture-qr-image {
    width: 220px;
    max-width: 100%;
    height: auto;
    padding: var(--sp-3);
    background: #fff;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
}

.mobile-capture-preview {
    width: 160px;
    height: 160px;
    object-fit: cover;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
}

/* --------------------------------------------------------------------------
   35. PERFIL DO USUÁRIO (FOTO)
   Features/Configuracoes/Perfil.razor — avatar grande (foto real ou iniciais
   como fallback, mesmo cálculo de .user-avatar da Topbar) ao lado dos dois
   jeitos de trocar a foto (upload direto ou MobileCaptureQrCode). Reaproveitar
   .profile-avatar pro próximo lugar que precisar mostrar uma foto de usuário
   em tamanho grande (hoje também usada em Features/Socios/SocioModal.razor,
   foto do sócio — ver Features/Socios/CLAUDE.md).
   Dimensões sempre fixas (120x120, flex-shrink:0 — nunca espreme nem estica,
   não importa o layout ao redor) e moldura sutil (border: 1px solid
   --color-border) sempre visível, com foto real ou com o fallback (ícone
   dentro do fundo --color-brand-soft) — a moldura marca o contorno do avatar
   mesmo antes/sem a foto carregar, não só depois.
   -------------------------------------------------------------------------- */
.profile-avatar-card {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--sp-6);
}

.profile-avatar {
    flex-shrink: 0;
    width: 120px;
    height: 120px;
    display: grid;
    place-items: center;
    overflow: hidden;
    border-radius: var(--radius-full);
    border: 1px solid var(--color-border);
    background: var(--color-brand-soft);
    color: var(--color-brand-strong);
    font-weight: 800;
    font-size: 36px;
}

.profile-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.profile-avatar-actions {
    flex: 1 1 260px;
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

@media (max-width: 767px) {
    .profile-avatar-card {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }
}

/* --------------------------------------------------------------------------
   36. APP MOBILE (SIGA_MOBILE)
   Shell próprio do app simplificado do dirigente sindical — usuário com
   Aplicação SIGA_MOBILE (coluna usuario.ModuloSistema, sem mudança física
   nessa coluna) cai aqui em vez do .app-shell/Sidebar
   do sistema WEB (ver Components/Layout/MobileLayout.razor e a guarda em
   MainLayout.razor). Sem sidebar lateral: hero fixo no topo (usa o mesmo
   gradiente --sidebar-from/--sidebar-to de cada um dos 25 temas, pra
   "puxar" a identidade visual do tema escolhido pro app mobile) + navegação
   inferior fixa (.mobile-bottom-nav, padrão "app nativo") no lugar de menu
   lateral. Conteúdo sempre centralizado numa largura de celular mesmo em
   telas maiores (tablet/desktop abrindo o app mobile). Duas páginas usam
   esse layout: Features/Mobile/Inicio.razor (/mobile-app, vitrine de
   .mobile-tile) e Features/Mobile/Configuracoes.razor (/mobile-app/
   configuracoes, foto de perfil + tema/dark mode — reaproveita
   .theme-options/.theme-option/.switch* da seção 27, mesmo JS de sempre).
   Reaproveitar todas essas classes pro próximo card/ação desse app, não
   criar variação.
   -------------------------------------------------------------------------- */
.mobile-app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    /* Sem "background" próprio de propósito — "html, body" (seção 5) já
       define --color-bg, e é lá que mora o horizonte decorativo
       (--bg-horizon-hills/--bg-horizon-sun); um fundo opaco aqui esconderia
       esse fundo em toda página do app mobile. Removido quando o horizonte
       foi adicionado. */
}

.mobile-app-topbar {
    position: sticky;
    top: 0;
    z-index: 10;
    /* Era --sp-5/--sp-6 (topo/base) — reduzido em ~16px de altura total no
       hero (pedido explícito, "diminuir mais um pouco a altura, aprox.
       15px"), trocando por --sp-3/--sp-4, os dois tokens de espaçamento
       imediatamente abaixo na escala (nunca valor "mágico" solto, ver
       CLAUDE.md "Regras absolutas" nº 5). */
    padding: var(--sp-3) var(--sp-4) var(--sp-4);
    background: linear-gradient(135deg, var(--sidebar-from) 0%, var(--sidebar-to) 100%);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.mobile-app-topbar-row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.mobile-app-avatar {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-full);
    background: rgba(255, 255, 255, .16);
    color: #fff;
    font-weight: 800;
    font-size: 14px;
    overflow: hidden;
}

.mobile-app-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.mobile-app-topbar-info {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.35;
    color: #fff;
}

.mobile-app-topbar-info strong {
    font-size: 16px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mobile-app-topbar-info span {
    font-size: 11px;
    color: rgba(255, 255, 255, .72);
}

.mobile-app-topbar .btn-icon {
    flex-shrink: 0;
    color: #fff;
}

.mobile-app-topbar .btn-icon:hover {
    background: rgba(255, 255, 255, .16);
}

.mobile-app-content {
    flex: 1 1 auto;
    width: 100%;
    max-width: 560px;
    margin-inline: auto;
    padding: var(--sp-6) var(--sp-4) calc(var(--sp-6) + 72px + env(safe-area-inset-bottom));
}

.mobile-section-title {
    font-size: 19px;
    font-weight: 800;
    margin: 0;
}

.mobile-section-sub {
    color: var(--color-text-muted);
    margin: var(--sp-1) 0 0;
}

/* Navegação inferior fixa — substitui o menu lateral do sistema WEB nesse
   app; NavLink já aplica a classe "active" sozinho ao bater com a rota. */
.mobile-bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10;
    display: flex;
    background: var(--color-surface-strong);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -4px 16px rgba(0, 0, 0, .06);
    padding-bottom: env(safe-area-inset-bottom);
}

.mobile-bottom-nav-link {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: var(--sp-2) 0;
    font-size: 10px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-decoration: none;
}

.mobile-bottom-nav-link .material-symbols-rounded {
    font-size: 22px;
}

.mobile-bottom-nav-link.active {
    color: var(--color-brand);
}

.mobile-tile-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-4);
    margin-top: var(--sp-6);
}

.mobile-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    text-align: left;
    cursor: pointer;
    transition: box-shadow var(--transition), transform var(--transition);
}

.mobile-tile:not(:disabled):hover {
    box-shadow: var(--shadow-md);
}

.mobile-tile:not(:disabled):active {
    transform: scale(.97);
}

.mobile-tile:disabled {
    opacity: .6;
    cursor: not-allowed;
}

.mobile-tile-badge {
    position: absolute;
    top: var(--sp-3);
    right: var(--sp-3);
}

.mobile-tile-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: var(--radius-full);
    background: var(--color-brand-soft);
    color: var(--color-brand);
    font-size: 24px;
}

.mobile-tile-title {
    font-weight: 700;
}

.mobile-tile-sub {
    font-size: 11px;
    color: var(--color-text-muted);
}

/* Ícone grande de confirmação (ex.: "Pagamento confirmado!" em
   Features/Mobile/Socios/Pagamento.razor, ver Services/Mobile/CLAUDE.md) —
   círculo verde com um ícone de check, bem mais expressivo que só o texto do
   alerta; pedido explícito ("bem expressiva a confirmação"). Mesmo espírito
   de .mobile-tile-icon (círculo com ícone centralizado), só maior e com a
   cor de sucesso (--color-success/--color-success-soft) em vez de
   --color-brand — reaproveitável por qualquer outra tela mobile que precise
   de uma confirmação de sucesso parecida, não criar variação nova. */
.mobile-success-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
    margin: 0 auto var(--sp-3);
    border-radius: var(--radius-full);
    background: var(--color-success-soft);
    color: var(--color-success);
}

.mobile-success-icon .material-symbols-rounded {
    font-size: 44px;
}

/* Agrupa o botão "Voltar" (.mobile-back-link) com o bloco título/subtítulo
   de uma sub-página do app mobile — align-items:center alinha o ícone
   verticalmente com esse bloco (h1 + .mobile-section-sub, sempre 2 linhas,
   em Index.razor/Participantes.razor). Pedido explícito: esse alinhamento é
   só do MOBILE — o PageHeader do sistema WEB continua com o "Voltar" no
   formato de sempre (ver seção 31, PAGE HEADER, mais acima). */
.mobile-header-row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

/* Variante pra quando o "bloco" ao lado do Voltar é título + chip na MESMA
   linha (.mobile-title-row, ex.: Detalhes.razor) em vez de título+subtítulo
   empilhados — pedido explícito: aqui o ícone deve se alinhar só com o
   título, não com o bloco título+chip inteiro. Como o chip normalmente
   divide a linha com o h1 (flex-wrap só desce o chip pra uma 2ª linha em
   títulos muito longos, ver .mobile-title-row), align-items:flex-start
   ancora o ícone na primeira linha (o h1) sempre — inclusive nesse caso raro
   de wrap, em que align-items:center (padrão acima) centralizaria o ícone
   contra as DUAS linhas (h1 + chip), descentralizando-o do título. */
.mobile-header-row--titulo {
    align-items: flex-start;
}

/* Botão "Voltar" no topo de uma sub-página do app mobile (ex.:
   Features/Mobile/Eventos/Index.razor) — MobileLayout não tem cabeçalho
   contextual por página (o hero é sempre "Olá, Nome"), então cada
   sub-página resolve a própria volta com este link simples. Reaproveita
   .btn-icon (ver "Icon button", seção 14) — ícone `arrow_back` sozinho, sem
   texto, com aria-label/title explicando o destino; antes ficava acima do
   título com texto ("Eventos"/"Início"/etc.), agora fica ao lado dele via
   .mobile-header-row. */
.mobile-back-link {
    flex-shrink: 0;
}

/* Fundo sutil pros ícones "Voltar"/"Filtrar"/"Imprimir" do app mobile —
   pedido explícito, sem isso ficam com o mesmo fundo da página (.btn-icon
   puro só ganha fundo no :hover, ver seção 14 ICON BUTTON). `.mobile-back-link`
   sozinha (não só dentro de `.mobile-header-row`) porque em
   Features/Mobile/Eventos/Detalhes.razor o link também aparece solto, sem
   título ao lado, nos ramos "Carregando"/"Evento não encontrado" — precisa
   do mesmo fundo nos três casos. `.mobile-header-actions .btn-icon` (não
   `.mobile-section-header > .btn-icon`, que era o filtro como filho direto
   antes de o botão "Imprimir" entrar — ver .mobile-header-actions abaixo)
   cobre qualquer ícone dentro do agrupamento de ações à direita. Escopado só
   ao mobile — não muda .btn-icon em nenhum outro lugar do app (Topbar,
   tabelas, modais). */
.mobile-back-link,
.mobile-header-actions .btn-icon {
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
}

/* Agrupa os ícones do lado oposto ao título (ex.: "Imprimir"/"Filtrar" em
   Features/Mobile/Eventos/Participantes.razor) — permite mais de um ícone
   nesse lado sem quebrar o space-between de duas colunas de
   .mobile-section-header (título+voltar de um lado, ações do outro). */
.mobile-header-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

/* Botão flutuante (FAB) — canto inferior direito, acima da
   .mobile-bottom-nav (mesmo respiro reservado por .mobile-app-content:
   72px + safe-area, mais um --sp-4 de folga). Primeiro consumidor:
   "Cadastrar participante" em Features/Mobile/Eventos/Participantes.razor —
   só visual por pedido explícito (sem @onclick ainda), ver
   Features/Mobile/CLAUDE.md. Reaproveitável por qualquer ação mobile futura
   do tipo "criar novo item" — não criar uma variação por Feature. */
.mobile-fab {
    position: fixed;
    right: var(--sp-4);
    bottom: calc(72px + env(safe-area-inset-bottom) + var(--sp-4));
    z-index: 15;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--color-brand);
    color: #fff;
    box-shadow: var(--shadow-lg);
    cursor: pointer;
    transition: box-shadow var(--transition), transform var(--transition);
}

.mobile-fab:hover {
    box-shadow: var(--shadow-md);
}

.mobile-fab:active {
    transform: scale(.96);
}

.mobile-fab .material-symbols-rounded {
    font-size: 26px;
}

/* Listagem em cartões empilhados (não tabela) — primeira consumidora:
   Features/Mobile/Eventos/Index.razor. Reaproveitar pra qualquer outra
   listagem mobile futura (Financeiro/Sócios/Sindicatos) em vez de criar
   variação nova. */
.mobile-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    margin-top: var(--sp-6);
}

/* Sempre um <a> (linha clicável levando pro detalhe do registro) — mesmo
   reset global de âncora (app.css topo, "a { color:inherit; text-decoration:
   none; }") já deixa igual a um <div>, só acrescenta cursor/hover/active
   pra ficar claro que é clicável, mesmo espírito de .mobile-tile. */
.mobile-list-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    transition: box-shadow var(--transition), transform var(--transition);
}

.mobile-list-item:hover {
    box-shadow: var(--shadow-md);
}

.mobile-list-item:active {
    transform: scale(.98);
}

.mobile-list-item .badge {
    flex-shrink: 0;
}

.mobile-list-item-main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.mobile-list-item-main strong {
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mobile-list-item-sub {
    font-size: 11px;
    color: var(--color-text-muted);
}

/* Agrupa avatar (.profile-avatar.profile-avatar-sm) + texto
   (.mobile-list-item-main) lado a lado, como um bloco só, dentro de um
   .mobile-list-item — sem esse wrapper, o justify-content:space-between do
   pai trataria avatar e texto como dois blocos distintos (tipo "conteúdo x
   badge") e afastaria um do outro em vez de mantê-los colados. min-width:0
   deixa o nome truncar (ellipsis, .mobile-list-item-main strong) dentro do
   espaço restante. Primeiro uso: dirigentes do sindicato
   (Features/Mobile/Sindicato/Detalhes.razor) — reaproveitar em qualquer
   listagem mobile futura que precise de foto/avatar + texto na mesma linha. */
.mobile-list-item-avatar-row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

/* Bloco de metadado curto no lado direito de um .mobile-list-item (ícone +
   texto, ex.: gênero + idade do sócio) — flex-shrink:0 pra nunca espremer
   quando .mobile-list-item-avatar-row precisar de todo o espaço restante
   pro nome truncar. Primeiro uso: Features/Mobile/Socios/Index.razor.
   Reaproveitar em qualquer listagem mobile futura que precise de um dado
   curto e discreto do lado oposto ao avatar/texto. */
.mobile-list-item-meta {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 2px;
    font-size: 11px;
    color: var(--color-text-muted);
}

.mobile-list-item-meta .material-symbols-rounded {
    font-size: 16px;
}

/* Miniatura do logo institucional (sol, wwwroot/images/brand-icon.svg — SVG
   leve, ~700 bytes, não o sol.png de ~4,3KB usado no colapso da sidebar)
   dentro de um .mobile-list-item — mesmo espírito de .profile-avatar-sm,
   mas pra um ícone estático (mesma imagem em toda a lista, sem foto/
   fallback), não uma foto de pessoa. 28px — ainda menor que o avatar de
   pessoa (40px), decorativo/institucional, não precisa transmitir
   identidade individual. Primeiro uso: Features/Mobile/Sindicato/
   Index.razor, dentro de .mobile-list-item-avatar-row (agrupa com
   .mobile-list-item-main, mesmo wrapper já usado por avatar de pessoa). */
.mobile-list-item-logo {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    object-fit: contain;
}

/* Centraliza um .profile-avatar (foto grande, sem nada ao lado) dentro de
   um .mobile-card, no topo de uma página de detalhe mobile de uma pessoa
   (ex.: dirigente do sindicato) — diferente de .profile-avatar-card (linha
   flex, avatar + ações ao lado, usada na WEB), aqui não há ação nenhuma ao
   lado da foto. Sempre centralizado, independente de viewport (não depende
   do breakpoint mobile de .profile-avatar-card) — primeiro uso:
   Features/Mobile/Sindicato/Dirigente.razor. */
.mobile-detail-avatar {
    display: flex;
    justify-content: center;
    padding: var(--sp-2) 0;
}

.mobile-load-more {
    margin-top: var(--sp-4);
}

/* Cabeçalho de seção mobile — bloco "Voltar" + título à esquerda
   (.mobile-header-row) + acessório à direita (ícone de filtro em
   Features/Mobile/Eventos/Index.razor/Participantes.razor). align-items:center
   (pedido explícito) alinha o acessório verticalmente com o bloco inteiro à
   esquerda (botão "Voltar" + título/subtítulo), não só com a primeira linha
   do título — era flex-start antes de .mobile-header-row existir. */
.mobile-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
}

/* Cabeçalho de uma página de detalhe mobile (ex.:
   Features/Mobile/Eventos/Detalhes.razor) — título + subtítulo, com respiro
   antes do próximo cartão (sem isso o título fica colado na seção seguinte,
   já que .mobile-section-title/.mobile-section-sub não têm margin-bottom
   próprio). */
.mobile-event-header {
    margin-bottom: var(--sp-6);
}

/* Título + badge (ex.: status do evento) na mesma linha, "dando
   continuidade" ao texto em vez de ficarem em pontas opostas — diferente de
   .mobile-section-header (space-between). flex-wrap pra o badge descer pra
   uma segunda linha se o título for longo demais pra caber ao lado. */
.mobile-title-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-2);
}

/* Cartão genérico de conteúdo mobile (fundo/borda/raio/sombra comuns) — pra
   qualquer bloco que não seja um item de .mobile-list nem um .mobile-tile
   (ex.: painel de filtro, dados do evento, gráficos em Detalhes.razor). */
.mobile-card {
    padding: var(--sp-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

/* Sanfona/accordion colapsada por padrão (ex.: "Informações do evento" em
   Features/Mobile/Eventos/Detalhes.razor) — mesmo padrão simples de
   expandir/colapsar de .nav-link-parent/.nav-submenu (só @if, sem animação
   de altura), aqui dentro de um .mobile-card. */
.mobile-accordion-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    color: var(--color-text);
    cursor: pointer;
}

.mobile-accordion-icon {
    color: var(--color-text-muted);
    transition: transform var(--transition);
}

.mobile-accordion-icon--open {
    transform: rotate(180deg);
}

/* Botões de ação lado a lado (ex.: "Participantes"/"Imprimir listas" em
   Features/Mobile/Eventos/Detalhes.razor) — .btn já centraliza o próprio
   conteúdo (ícone + texto), só falta esticar os dois igualmente no grid. */
.mobile-quick-actions {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-3);
    margin-top: var(--sp-4);
}

.mobile-quick-actions .btn {
    width: 100%;
}

/* Painel de filtro que expande/recolhe ao clicar no ícone do
   .mobile-section-header — mesmo padrão simples de expandir/colapsar de
   .nav-link-parent/.nav-submenu (só @if, sem animação de altura). */
.mobile-filter-panel {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    margin-top: var(--sp-4);
}

.mobile-filter-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-2);
}

/* Subseção dentro de uma página de detalhe mobile (ex.: "Participantes" em
   Features/Mobile/Eventos/Detalhes.razor) — .eyebrow já dá o rótulo
   pequeno/uppercase, só falta o respiro acima do bloco anterior. */
.mobile-subsection {
    margin-top: var(--sp-6);
}

/* Cabeçalho de uma .mobile-subsection quando ela também tem uma ação (ex.:
   "Ver todos" levando pra Features/Mobile/Eventos/Participantes.razor) —
   .eyebrow à esquerda, link à direita, mesma linha. */
.mobile-subsection-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.mobile-subsection-link {
    display: inline-flex;
    align-items: center;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-brand);
}

.mobile-subsection-link .material-symbols-rounded {
    font-size: 16px;
}

.mobile-stats-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-3);
    margin-top: var(--sp-2);
}

/* Variante de .mobile-stats-grid pra 3 KPIs numa linha só (em vez do padrão
   2×2) — primeiro uso: Features/Mobile/Socios/Index.razor (Total/Mulheres/
   Homens, acima dos gráficos). Seletor composto
   (.mobile-stats-grid.mobile-stats-grid--3col) pelo mesmo motivo de
   especificidade de .profile-avatar-rect (ver CLAUDE.md, "Regras
   absolutas" nº 6). */
.mobile-stats-grid.mobile-stats-grid--3col {
    grid-template-columns: repeat(3, 1fr);
}

.mobile-stat-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: var(--sp-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    text-align: center;
}

/* Variante compacta de .mobile-stat-card — padding bem menor (a versão
   padrão, --sp-4, é pensada pra um KPI sozinho de destaque; aqui o card
   precisa conviver com gráficos logo abaixo, na mesma aba — pedido
   explícito, "ocupem uma altura vertical menor") — primeiro uso:
   Features/Mobile/Socios/Index.razor (aba "Dados", 3 KPIs acima dos
   gráficos). Seletor composto (.mobile-stat-card.mobile-stat-card--compact)
   pelo mesmo motivo de especificidade de sempre (CLAUDE.md, "Regras
   absolutas" nº 6); os dois filhos (`.mobile-stat-value`/`.mobile-stat-label`)
   são sobrescritos via descendente, não precisam de classe própria. */
.mobile-stat-card.mobile-stat-card--compact {
    padding: var(--sp-2) var(--sp-3);
    gap: 0;
}

.mobile-stat-card--compact .mobile-stat-value {
    font-size: 18px;
}

.mobile-stat-card--compact .mobile-stat-label {
    font-size: 10px;
}

.mobile-stat-value {
    font-size: 22px;
    font-weight: 800;
    color: var(--color-brand);
}

.mobile-stat-label {
    font-size: 11px;
    color: var(--color-text-muted);
}

/* Cartão de sindicato na visão "Tabela" (matriz Sindicato x Mês) migrada de
   Features/Financeiro/PagamentosSttrs.razor pro mobile — cada card reproduz
   uma linha da tabela WEB (13 colunas: Sindicato + 12 meses), impossível de
   caber numa tela estreita como tabela de verdade. Consumidor:
   Features/Mobile/Financeiro/Index.razor. */
.mobile-financeiro-card-header {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: 14px;
    font-weight: 700;
}

/* Grade 6x2 (Jan-Dez) — os mesmos ícones/classes de status da matriz WEB
   (.status-icon-chip/.status-icon-chip-brand/.text-muted, seção 21
   TABELAS) são reaproveitados tal e qual, nenhuma classe de ícone nova. */
.mobile-financeiro-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: var(--sp-3) var(--sp-1);
    margin-top: var(--sp-3);
}

.mobile-financeiro-mes {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-1);
}

.mobile-financeiro-mes-label {
    font-size: 10px;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
}

/* Chip informativo de tema/modo atual — Features/Mobile/Inicio.razor (nível
   69). Valores lidos via JS (window.AppTheme, wwwroot/js/app.js — tema/dark
   mode não têm estado nenhum acessível direto pelo C#), por isso só aparecem
   depois do primeiro render (OnAfterRenderAsync). */
.mobile-theme-info {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-top: var(--sp-6);
    padding: var(--sp-3) var(--sp-4);
    background: var(--color-surface-strong);
    border-radius: var(--radius-md);
    font-size: 12px;
    color: var(--color-text-muted);
}

.mobile-theme-info .material-symbols-rounded {
    font-size: 18px;
    color: var(--color-brand);
}

.mobile-theme-info strong {
    color: var(--color-text);
    font-weight: 700;
}

/* Foto de perfil — Features/Mobile/Configuracoes.razor. Toque no círculo
   abre a câmera/galeria (label associado ao InputFile oculto por .d-none),
   mesmo truque de "input file estilizado" usado em qualquer upload custom. */
.mobile-avatar-edit-wrap {
    display: flex;
    justify-content: center;
    margin: var(--sp-4) 0;
}

.mobile-avatar-edit {
    position: relative;
    display: inline-block;
    cursor: pointer;
}

.mobile-avatar-circle {
    position: relative;
    display: grid;
    place-items: center;
    width: 96px;
    height: 96px;
    border-radius: var(--radius-full);
    background: var(--color-brand-soft);
    color: var(--color-brand-strong);
    font-size: 30px;
    font-weight: 800;
    overflow: hidden;
}

.mobile-avatar-circle img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.mobile-avatar-edit-badge {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-full);
    background: var(--color-brand);
    color: #fff;
    font-size: 16px;
    border: 3px solid var(--color-surface);
}

.mobile-avatar-hint {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 12px;
}

/* --------------------------------------------------------------------------
   37. RECORTE DE FOTO (crop) + CAPTURA VIA WEBCAM — Components/Shared/
       RecorteFotoOverlay.razor / WebcamCaptureOverlay.razor
   -------------------------------------------------------------------------- */

/* Diferente dos modais comuns (.overlay + .modal-wrapper, escondidos via @if
   condicional do Blazor), este overlay é sempre renderizado no DOM e
   mostrado/escondido via JS puro (wwwroot/js/image-crop.js) — o fluxo de
   escolher/cortar foto não pode depender do circuito Blazor (ver CLAUDE.md
   "Foto de perfil no módulo MOBILE"). Por isso backdrop + centralização vêm
   de uma única classe, alternada por JS, em vez de reaproveitar
   .overlay/.modal-wrapper (que assumem renderização condicional). */
.crop-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 60;
    align-items: center;
    justify-content: center;
    padding: var(--sp-4);
    background: rgba(0, 0, 0, .52);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}

.crop-overlay--open {
    display: flex;
}

.crop-modal {
    width: min(100%, 420px);
}

.crop-modal-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-4);
}

.crop-canvas-wrap {
    position: relative;
    width: 100%;
    max-width: 320px;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--color-surface-strong);
}

/* Foto de sócio (220x228, ver Features/Socios/SocioModal.razor/CLAUDE.md) —
   quadro de recorte na mesma proporção da saída real (quase quadrada, mas não
   exatamente), menor que os 320px do avatar porque a imagem final também é
   pequena; largura maior que isso só deixaria o zoom/arraste com uma precisão
   de pixel que a foto salva nem tem. `max-width: 220px` bate por coincidência
   com a largura de saída (220px) — são medidas independentes (uma é o
   tamanho da caixa de edição na tela, a outra é resolução real do arquivo
   salvo, ver `image-crop.js`), não a mesma coisa. */
.crop-canvas-wrap--socio {
    max-width: 220px;
    aspect-ratio: 220 / 228;
}

.crop-canvas {
    display: block;
    width: 100%;
    height: 100%;
    touch-action: none;
    cursor: grab;
}

.crop-canvas:active {
    cursor: grabbing;
}

/* Guia circular — o canvas em si continua quadrado (é o que é salvo); o
   círculo é só uma pista visual de como a foto fica no avatar, que já é
   redondo via .profile-avatar/.mobile-avatar-circle/.user-avatar. box-shadow
   com spread gigante escurece tudo fora do círculo sem precisar desenhar
   máscara dentro do canvas. */
.crop-frame {
    position: absolute;
    inset: 0;
    border-radius: var(--radius-full);
    box-shadow: 0 0 0 9999px rgba(15, 23, 42, .55);
    border: 2px solid rgba(255, 255, 255, .85);
    pointer-events: none;
}

/* Guia retangular — foto de sócio, exibida em .profile-avatar-rect (não
   redonda), então o guia de recorte não deve sugerir um resultado circular
   como o do avatar. Mesmo truque de box-shadow gigante pra escurecer fora do
   quadro, só troca o border-radius. */
.crop-frame--retangulo {
    border-radius: var(--radius-md);
}

.crop-zoom-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3);
    width: 100%;
    max-width: 320px;
}

.crop-zoom-range {
    flex: 1 1 auto;
    accent-color: var(--color-brand);
}

/* Acompanha .crop-canvas-wrap--socio — mesma largura da caixa de recorte
   menor, pra não sobrar slider bem mais largo que a imagem acima dele. */
.crop-zoom-row--socio {
    max-width: 220px;
}

/* Overlay de captura via webcam (WebcamCaptureOverlay.razor,
   wwwroot/js/webcam-capture.js) — reaproveita .crop-overlay/.crop-modal
   acima como moldura (backdrop, largura 420px, z-index); só o corpo (vídeo
   ao vivo, não canvas de recorte) é próprio, ver Components/Shared/CLAUDE.md. */
.webcam-modal-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-4);
}

/* Mesma largura máxima de .crop-canvas-wrap (320px) — consistência visual
   entre "capturar" e "recortar", já que o fluxo passa de um pro outro em
   seguida. scaleX(-1) espelha só a PRÉVIA (efeito "espelho", como qualquer
   app de webcam) — o frame realmente capturado (canvas.drawImage no JS) usa
   os pixels reais do <video>, sem o transform, então a foto final não sai
   espelhada. */
.webcam-video {
    width: 100%;
    max-width: 320px;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-md);
    background: #000;
    object-fit: cover;
    transform: scaleX(-1);
}

/* --------------------------------------------------------------------------
   38. UI DE RECONEXÃO — Components/App.razor (#blazor-error-ui)
   -------------------------------------------------------------------------- */

/* Barra padrão que o próprio blazor.web.js mostra/esconde (classe .show)
   quando o circuito Server cai por exceção não tratada ou perda de conexão.
   Sem esse elemento no DOM, uma exceção não tratada no servidor derruba o
   circuito sem deixar rastro nenhum na tela — sintoma "trava e não faz mais
   nada" já visto em handlers @oninput sem catch (ver CLAUDE.md, "O try
   sempre precisa de catch (SqlException)..."). */
#blazor-error-ui {
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9999;
    padding: var(--sp-3) var(--sp-4);
    background: var(--color-danger);
    color: #fff;
    box-shadow: var(--shadow-lg);
}

#blazor-error-ui.show {
    display: block;
}

#blazor-error-ui .reload {
    color: #fff;
    text-decoration: underline;
    margin-left: var(--sp-2);
}

#blazor-error-ui .dismiss {
    float: right;
    cursor: pointer;
    margin-left: var(--sp-4);
}

/* --------------------------------------------------------------------------
   39. ÁRVORE DE IMPORTAÇÃO FTP — Features/ImportacaoFtp/Index.razor
   -------------------------------------------------------------------------- */

/* Célula "Nome" de cada linha da árvore — botão de expandir/recolher (pasta)
   ou espaçador (arquivo, mantém o texto alinhado com o das pastas) + ícone +
   nome, tudo numa linha só. */
.ftp-tree-cell {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

/* Indentação por nível de subpasta — mesmo incremento (--sp-6) do
   .nav-submenu da sidebar. Capado em 4 níveis (ver Math.Min em
   ArvoreLinhas.razor): profundidade real de pasta de FTP não costuma passar
   disso, e uma classe por nível evita valor "mágico" calculado em C#. */
.ftp-tree-nivel-1 { padding-left: var(--sp-6); }
.ftp-tree-nivel-2 { padding-left: calc(var(--sp-6) * 2); }
.ftp-tree-nivel-3 { padding-left: calc(var(--sp-6) * 3); }
.ftp-tree-nivel-4 { padding-left: calc(var(--sp-6) * 4); }

.ftp-tree-toggle-placeholder {
    width: 22px;
    height: 22px;
    flex: none;
}

.ftp-tree-icon {
    font-size: 18px;
    color: var(--color-text-muted);
}

.ftp-tree-icon-pasta {
    color: var(--color-brand);
}

/* --------------------------------------------------------------------------
   40. TOASTS — Components/Shared/ToastContainer.razor
   -------------------------------------------------------------------------- */

/* Canto superior direito, sempre por cima de qualquer `.modal-wrapper`
   (z-index 50) — mas abaixo de `#blazor-error-ui` (9999, banner crítico de
   reconexão do próprio framework, seção 38). Empilha várias toasts com
   `gap`; `pointer-events:none` no container (a pilha em si não deve
   bloquear clique em nada por trás dela) com `pointer-events:auto`
   devolvido em cada `.toast` individual (senão o botão de fechar também
   ficaria inclicável). */
.toast-container {
    position: fixed;
    top: var(--sp-4);
    right: var(--sp-4);
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    pointer-events: none;
    max-width: min(360px, calc(100vw - var(--sp-8)));
}

@keyframes toast-entrar {
    from { opacity: 0; transform: translateX(16px); }
    to   { opacity: 1; transform: translateX(0); }
}

.toast {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    font-size: 13px;
    font-weight: 500;
    pointer-events: auto;
    animation: toast-entrar 180ms ease;
    transition: opacity 180ms ease, transform 180ms ease;
}

/* Classe adicionada só depois da montagem (ToastContainer.FecharAsync),
   nunca já presente no primeiro render — é o que garante que a saída seja
   uma TRANSIÇÃO de verdade (troca de classe), não a mesma `animation` de
   entrada rodando ao contrário; remover o elemento da lista só acontece
   depois do tempo dessa transição (ver `AnimacaoSaidaMs` no code-behind). */
.toast-saindo {
    opacity: 0;
    transform: translateX(16px);
}

.toast-sucesso { background: var(--color-success-soft); color: var(--color-success); border: 1px solid rgba(2, 122, 72, .18); }
.toast-erro    { background: var(--color-danger-soft);  color: var(--color-danger);  border: 1px solid rgba(180, 35, 24, .18); }

.toast-texto {
    flex: 1 1 auto;
}

/* Botão de fechar — mesmo `.btn-icon` de sempre, só reduzido (28px/ícone
   16px) pra não dominar uma toast pequena; sem fundo/sombra própria, herda
   a cor do texto da toast (currentColor) em vez de `--color-text`. */
.toast .btn-icon {
    width: 28px;
    height: 28px;
    color: inherit;
    flex: none;
}

.toast .btn-icon .material-symbols-rounded {
    font-size: 16px;
}

/* --------------------------------------------------------------------------
   41. AVISO DE PERFIL (BALÃO) — Components/Layout/Topbar.razor
   -------------------------------------------------------------------------- */

.notification-bell-wrap {
    position: relative;
}

@keyframes notification-balloon-entrar {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* z-index abaixo de .modal-wrapper (50) de propósito — se uma modal abrir
   enquanto o balão ainda está visível, a modal deve cobri-lo, não o
   contrário. Acima do fluxo normal da página (sem z-index), que é o único
   outro caso relevante. */
.notification-balloon {
    position: absolute;
    top: calc(100% + var(--sp-2));
    right: 0;
    z-index: 45;
    width: 260px;
    padding: var(--sp-4);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-lg);
    animation: notification-balloon-entrar 180ms ease;
}

/* Setinha apontando pro sino — dois triângulos sobrepostos (CSS puro, sem
   imagem): o de baixo (maior, cor da borda) forma o contorno; o de cima
   (1px menor, cor do fundo do balão) cobre o miolo, simulando borda só
   nas duas laterais do triângulo. */
.notification-balloon::before,
.notification-balloon::after {
    content: '';
    position: absolute;
    bottom: 100%;
    right: var(--sp-4);
    border: 7px solid transparent;
    border-bottom-color: var(--color-border);
}

.notification-balloon::after {
    right: calc(var(--sp-4) + 1px);
    border-width: 6px;
    border-bottom-color: var(--color-surface);
}

.notification-balloon-texto {
    font-size: 13px;
    color: var(--color-text);
    margin: 0 0 var(--sp-3);
    padding-right: var(--sp-6);
}

/* Botão de fechar no canto do balão — mesma redução de .btn-icon já usada
   em .toast (28px/ícone 16px). */
.notification-balloon .btn-icon {
    position: absolute;
    top: var(--sp-1);
    right: var(--sp-1);
    width: 28px;
    height: 28px;
}

.notification-balloon .btn-icon .material-symbols-rounded {
    font-size: 16px;
}

/* --------------------------------------------------------------------------
   42. IDENTIFICAÇÃO DO AMBIENTE DEV — somente em Staging
   -------------------------------------------------------------------------- */

body.ambiente-dev {
    padding-top: 36px;
}

.ambiente-dev-banner {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 1000;

    min-height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);

    padding: var(--sp-2) var(--sp-4);

    background: var(--color-warning);
    color: #fff;

    font-size: 12px;
    line-height: 1.2;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;

    box-shadow: var(--shadow-md);
}

.ambiente-dev-banner .material-symbols-rounded {
    font-size: 18px;
}

.ambiente-dev-banner span:last-child {
    opacity: .85;
}

@media (max-width: 600px) {
    body.ambiente-dev {
        padding-top: 40px;
    }

    .ambiente-dev-banner {
        min-height: 40px;
        padding-inline: var(--sp-2);
        font-size: 10px;
    }
}
