/* ============================================================================
   FVC — Componentes padrão partilhados
   ============================================================================
   Cada padrão de UI abaixo tem de ser usado sempre com a MESMA classe/marcação
   em toda a app, em vez de cada página inventar a sua própria variante (o que
   tem estado a acontecer e gera inconsistências sem motivo). Construídos sempre
   por cima de classes REAIS do template (Corporate UI Dashboard Pro / Bootstrap)
   ou do Radzen — nunca a reinventar o visual à mão quando já existe uma classe
   genuína para o efeito.

   Ficheiro partilhado entre Portal e PortalPatrimonio (carregado depois
   de corporate-theme.css, antes do tema próprio de cada app): as cores usam
   custom properties com um valor de recurso (fallback) igual ao que já existia
   no Portal, por isso nada muda visualmente enquanto nenhuma das duas
   apps as redefine. Cada app pode sobrepor essas variáveis no seu próprio
   ficheiro de tema para adaptar à sua marca.
   ============================================================================ */

/* ── 1. Barra de pesquisa ─────────────────────────────────────────────────
   O visual (borda, canto arredondado, espaço do ícone) vem inteiramente das
   classes reais do template — esta classe só fixa a largura, que é o único
   aspeto que legitimamente varia por contexto (barra de ferramentas cheia vs.
   filtro apertado dentro de uma tabela). Não criar mais nenhuma classe
   "-search-box" por página — usar esta, com o modificador --narrow quando
   for preciso menos espaço.

   Marcação:
   <div class="input-group fvc-search-box">
       <span class="input-group-text"><i class="fa-solid fa-magnifying-glass"></i></span>
       <input type="text" class="form-control" placeholder="Pesquisar..." />
   </div>
*/
.fvc-search-box {
    flex: 1;
    min-width: 220px;
}
.fvc-search-box--narrow {
    flex: none;
    min-width: 0;
    max-width: 280px;
}

/* ── 2. Chip de sub-ação dentro de um grupo ───────────────────────────────
   Ex: as tags de construção nos cartões de empreendimento ("Pista 1"), ou os
   botões "Logs"/"Comparar versões" no MTQ de concurso de uma obra. Construído
   sobre .badge/.badge-secondary/.border-radius-lg reais do template — só a
   borda (removida) e o hover (preenche com a cor de marca) são customizados.
   Funciona tanto em <a> (navegação) como em <button> (ação).

   Marcação:
   <a/button class="badge badge-secondary border-radius-lg fvc-chip">Texto</a>
*/
.fvc-chip {
    border-color: transparent !important;
    cursor: pointer;
}
.fvc-chip:hover:not(:disabled) {
    background: var(--fvc-chip-hover-bg, #5C4E63);
    color: #fff;
}
.fvc-chip:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* ── 3. Botão de ícone só (sem texto junto) ───────────────────────────────
   Ações de linha como editar/eliminar/gravar/cancelar/contactos/transferir.
   Já existia como .row-action-btn (Fornecedores, Especialidades) — mantido
   com o mesmo nome e valores de sempre (zero alterações de marcação nos
   sítios que já a usam bem); só passou a viver aqui em vez de duplicado
   como .cs-remove-btn/.sra-note-btn em ConstructionTab.razor, que devem
   passar a reutilizar esta em vez de terem a sua própria versão.

   Modificadores de cor:
     --edit / --contact / --neutral / --toggle  → neutro em repouso, realça a verde no hover
     --delete                                   → neutro em repouso, realça a vermelho no hover
     --save                                      → verde em repouso e no hover (ação já positiva)
     --cancel                                    → neutro em repouso, cinzento no hover
     --flag                                      → laranja em repouso e no hover (ex: erros e omissões)
     --toggle + .is-active                       → fica preenchido persistentemente enquanto ativo (ex:
                                                     ignorar); o hover verde continua igual às restantes
   Modificador de estado (combina com qualquer um dos acima):
     .has-note                       → cor de aviso persistente (tem nota/detalhe anexado)

   Marcação:
   <button class="row-action-btn row-action-btn--edit" title="Editar">
       <i class="fa-solid fa-pen"></i>
   </button>
*/
.row-action-btn {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    width: 30px;
    height: 30px;
    padding: 0;
    border-radius: 7px;
    border: 1px solid transparent !important;
    background: transparent !important;
    background-image: none !important;
    box-shadow: none !important;
    cursor: pointer;

    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    color: #94a3b8;
    /* Short enough that swiping the mouse quickly across two adjacent icons (e.g. Editar → Eliminar)
       never shows both mid-fade at once — a longer fade made that brief double-highlight look like a
       bug rather than a transition. */
    transition: background 0.05s, border-color 0.05s, color 0.05s;
    flex-shrink: 0;
}
.row-action-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* O <i> do ícone já herda line-height:1 (base do FontAwesome), mas isso só define a altura da caixa
   de linha — dentro dela o glifo continua posicionado pela baseline da fonte (ascent/descent), que
   não é simétrica à volta do centro, e por isso o ícone ficava visivelmente deslocado para cima
   dentro do quadrado 30×30, sobretudo notório no hover (fundo colorido a revelar a assimetria).
   Tornar o próprio <i> num flex container recentra o glifo pela geometria da caixa em vez da
   baseline da fonte. */
.row-action-btn i {
    display: flex;
    align-items: center;
    justify-content: center;
}

.row-action-btn--edit:hover:not(:disabled),
.row-action-btn--contact:hover:not(:disabled),
.row-action-btn--neutral:hover:not(:disabled),
.row-action-btn--toggle:hover:not(:disabled) {
    background: color-mix(in srgb, var(--fvc-icon-btn-accent, #A0DAB3) 25%, white) !important;
    color: color-mix(in srgb, var(--fvc-icon-btn-accent, #A0DAB3) 55%, black);
    border-color: var(--fvc-icon-btn-accent, #A0DAB3) !important;
}
.row-action-btn--contact.has-info {
    color: color-mix(in srgb, var(--fvc-icon-btn-accent, #A0DAB3) 55%, black);
}

.row-action-btn--delete:hover:not(:disabled) {
    background: #fee2e2 !important;
    color: #dc2626;
    border-color: #dc2626 !important;
}

.row-action-btn--save { color: #15803d; }
.row-action-btn--save:hover:not(:disabled) {
    background: #dcfce7 !important;
    border-color: #15803d !important;
}

.row-action-btn--cancel:hover:not(:disabled) {
    background: #f1f5f9 !important;
}

/* Indicador "tem nota" — estado persistente (não é só hover) de que a linha já tem uma nota/detalhe
   anexado, para o utilizador ver isso sem precisar de passar o rato. */
.row-action-btn.has-note { color: #b45309; }

/* Variante "de alerta" (ex: erros e omissões de uma proposta) — a cor de repouso já chama a atenção por
   si só, ao contrário das outras variantes que só reagem no hover. */
.row-action-btn--flag { color: #c2410c; }
.row-action-btn--flag:hover:not(:disabled) {
    background: #ffedd5 !important;
    color: #c2410c;
    border-color: #c2410c !important;
}
.row-action-btn--flag.has-note { color: #9a3412; }

/* Alternador (ex: ignorar fornecedor) — o estado "ativo" fica persistentemente preenchido, não só
   durante o hover. Sem a regra ":hover" abaixo, ".row-action-btn--toggle:hover" (especificidade
   0,3,0) ganhava a ".is-active" (0,2,0) e o botão "perdia" o aspeto de selecionado sempre que se
   lhe passava o rato por cima — esta regra iguala a especificidade do hover normal e mantém o
   preenchimento ativo em vez de reverter à cor de hover genérica. */
.row-action-btn--toggle.is-active {
    background: var(--rz-base-300, #e2e8f0) !important;
    color: #334155;
}
.row-action-btn--toggle.is-active:hover:not(:disabled) {
    background: var(--rz-base-300, #e2e8f0) !important;
    color: #334155;
    border-color: transparent !important;
}

/* ── 4. Ação principal (ícone + texto) ────────────────────────────────────
   Ex: "+ Novo", "+ Nova Especialidade", "Registar Envio", "Importar
   Proposta". Não precisa de nenhuma classe nova — usar sempre a classe real
   do Bootstrap .btn.btn-primary, com a cor de marca definida uma vez, via as
   custom properties nativas do Bootstrap 5.3 (ver .btn-primary em
   portal-theme.css / equivalente no Património). Quando esta ação convive
   numa barra de ferramentas com outras (ex: Comparar, Exportar Excel), essas
   outras usam .btn-outline-primary — preenchido só para a ação que
   cria/adiciona conteúdo. Nunca usar RadzenButton para este papel.

   Marcação:
   <button type="button" class="btn btn-primary mb-0">
       <i class="fa-solid fa-plus me-1"></i> Texto
   </button>
*/

/* ── 5. Ação secundária (ícone + texto), estilo claro/contornado ─────────
   Ex: "Testar email", "Cancelar"/"Fechar" de um diálogo. Também não precisa
   de nenhuma classe nova — é simplesmente o RadzenButton com
   ButtonStyle="ButtonStyle.Light" (o uso real em todo o Portal — 53 sítios
   contra 1 a usar "Secondary" —, e que corporate-theme.css já estiliza de
   forma idêntica a "Secondary": fundo branco, borda cinzenta, texto escuro,
   por isso não há diferença visual entre os dois hoje). Não embrulhar em
   IconButton nem inventar uma variante Bootstrap à parte para este papel.

   Marcação:
   <RadzenButton Text="Testar email" Icon="email" ButtonStyle="ButtonStyle.Light" />
*/

/* ── VirtualRadzenDataGrid: esqueleto do scroll infinito ──────────────────
   O virtual-data-grid.js põe nas variáveis do .rz-data-grid-data o desenho de
   uma linha-esqueleto (uma barra por coluna) e a área do tbody. O ::before
   fica por baixo da tabela: as linhas reais são opacas e tapam-no; onde ainda
   não há linhas (espaçadores do Virtualize, primeiro pedido, scroll mais
   rápido que o servidor/render) vê-se o esqueleto em vez de branco. */
[data-vgrid] > .rz-data-grid-data {
    position: relative;
    z-index: 0;
}

[data-vgrid] > .rz-data-grid-data::before {
    content: "";
    position: absolute;
    left: 0;
    top: var(--vgrid-skeleton-top, 0);
    width: var(--vgrid-skeleton-width, 100%);
    height: var(--vgrid-skeleton-height, 0);
    z-index: -1;
    pointer-events: none;
    background-image: var(--vgrid-skeleton-image, none);
    background-size: var(--vgrid-skeleton-width, 100%) var(--vgrid-skeleton-row, 40px);
    background-repeat: repeat-y;
    animation: vgrid-skeleton-pulse 1.4s ease-in-out infinite;
}

/* :where() sem especificidade: o hover/seleção/realces das próprias grids continuam a ganhar. */
:where([data-vgrid]) .rz-grid-table > tbody > tr {
    background-color: var(--rz-base-background-color, #fff);
}

/* À espera do primeiro bloco dos filtros atuais: só o esqueleto (sem linhas antigas nem "Sem registos"). */
[data-vgrid-loading]:not([data-vgrid-body]) .rz-grid-table > tbody {
    visibility: hidden;
}

/* RowHeight: altura fixa por linha, o Virtualize não salta quando as linhas trocam. */
[data-vgrid-fixed] .rz-grid-table > tbody > tr.rz-data-row > td {
    box-sizing: border-box;
    height: var(--vgrid-fixed-row-height);
    overflow: hidden;
}

/* ── Modo API: corpo próprio (VirtualGridBody) dentro da linha "sem registos" do Radzen ──
   Linhas em absoluto (top = índice × --vg-rh), células com a largura da coluna do cabeçalho (--vg-cN, posta pelo
   JS) e as fixas em sticky (--vg-lN / --vg-rN). O fundo do corpo é o esqueleto: vê-se onde ainda não há linha. */
[data-vgrid-body] > .rz-data-grid-data::before {
    display: none;
}

[data-vgrid-body] .rz-grid-table > tbody > tr.rz-datatable-emptymessage-row > td {
    padding: 0 !important;
    border: 0 !important;
    overflow: visible !important;
    text-align: start;
    white-space: nowrap;
    background: transparent !important;
}

.vg-body {
    position: relative;
    width: 100%;
    min-height: var(--vg-rh, 40px);
}

.vg-body::before {
    content: "";
    position: absolute;
    inset: 0;
    /* Até o JS desenhar as barras por coluna (milissegundos): faixas simples. */
    background-image: var(--vgrid-skeleton-image, linear-gradient(to bottom, transparent 35%, #e3e3e3 35%, #e3e3e3 65%, transparent 65%));
    background-size: var(--vgrid-skeleton-width, 100%) var(--vg-rh, 40px);
    background-repeat: repeat-y;
    animation: vgrid-skeleton-pulse 1.4s ease-in-out infinite;
    pointer-events: none;
}

.vg-body.vg-loading {
    min-height: var(--vg-viewport, 400px);
}

/* Até o JS medir as colunas do cabeçalho (--vg-cN) só se vê o esqueleto: sem as larguras as células desenhavam-se
   com tamanhos estranhos e sobrepostas durante um instante (ex.: ao abrir a grid ou trocar de modo). */
.vg-body:not([data-vg-ready]) > .vg-row,
.vg-body:not([data-vg-ready]) > .vg-detail {
    visibility: hidden;
}

.vg-row {
    position: absolute;
    left: 0;
    right: 0;
    height: var(--vg-rh, 40px);
    display: flex;
}

.vg-cell {
    flex: none;
    box-sizing: border-box;
    height: 100%;
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    padding: 0.3125rem 0.625rem;
    border-bottom: var(--rz-grid-cell-border, 1px solid #e5e7eb);
    font-size: var(--rz-grid-cell-font-size, 0.8125rem);
    line-height: var(--rz-grid-cell-line-height, 1rem);
    color: var(--rz-grid-cell-color, #1f2937);
    background-color: var(--rz-grid-background-color, #fff);
}

.vg-row-alt > .vg-cell {
    background-color: var(--rz-grid-stripe-background-color, #fafafa);
}

.vg-row:hover > .vg-cell {
    background-color: var(--rz-grid-hover-background-color, #f3f4f6);
}

.vg-cell > .rz-cell-data {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
}

.vg-right > .rz-cell-data {
    text-align: right;
}

.vg-center > .rz-cell-data {
    text-align: center;
}

.vg-frozen {
    position: sticky;
    z-index: 1;
}

.vg-frozen-left {
    box-shadow: 5px 0 5px -5px rgba(0, 0, 0, 0.12);
}

.vg-frozen-right {
    box-shadow: -5px 0 5px -5px rgba(0, 0, 0, 0.12);
}

/* Colunas estreitas (como as td.grid-check-cell / td.grid-icon-cell do portal-theme). */
.vg-cell.grid-check-cell {
    padding: 0;
    justify-content: center;
    overflow: visible;
}

.vg-cell.grid-check-cell > .rz-cell-data {
    flex: none;
    overflow: visible;
}

/* Checkbox em markup (sem o RadzenCheckBox) desativada: com o aspeto de desativada (o tema não o dá só pela classe). */
.vg-cell .rz-chkbox.rz-state-disabled,
.vg-cell .rz-chkbox-box.rz-state-disabled {
    cursor: default;
}

.vg-cell .rz-chkbox-box.rz-state-disabled {
    opacity: 0.4;
    background-color: var(--rz-base-200, #f1f3f5);
}

.vg-cell.grid-icon-cell {
    padding-left: 0.4rem;
    padding-right: 0;
}

/* ── Linhas expansíveis (Template da grid) ──
   Botão de expandir na coluna th.rz-col-icon do Radzen (--vg-cx); a área expandida em absoluto por baixo da linha,
   com o conteúdo colado à esquerda e a largura visível da grid (não anda com o scroll horizontal). */
.vg-body {
    width: var(--vg-table-w, 100%);
}

.vg-cell.vg-expander {
    width: var(--vg-cx, 2.5rem);
    padding: 0;
    justify-content: center;
}

.vg-toggler {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--rz-text-secondary-color, #6b7280);
    cursor: pointer;
}

.vg-toggler:hover {
    background: rgba(0, 0, 0, 0.06);
    color: var(--rz-text-color, #1f2937);
}

/* "Expandir todas" (desenhado pelo JS no cabeçalho da coluna do botão de expandir). O título escondido do Radzen
   ("EC") ocupava a largura da célula e empurrava o botão para debaixo da coluna seguinte. */
th:has(> .vg-expand-all) > .rz-column-title {
    display: none !important;
}

th:has(> .vg-expand-all) {
    padding: 0 !important;
    text-align: center;
}

.vg-expand-all.rz-button {
    width: 1.5rem;
    height: 1.5rem;
    min-width: 0;
    min-height: 0;
    padding: 0;
}

.vg-detail {
    position: absolute;
    left: 0;
    width: var(--vg-table-w, 100%);
    background: var(--rz-grid-background-color, #fff);
    border-bottom: var(--rz-grid-cell-border, 1px solid #e5e7eb);
    white-space: normal;
}

.vg-detail-inner {
    position: sticky;
    left: 0;
    box-sizing: border-box;
    width: var(--vg-viewport-w, 100%);
    max-width: 100%;
}

/* StickyDetail = false: a área expandida anda com as colunas (conteúdo alinhado com elas — VirtualGridAlignedRow). */
.vg-detail-flow > .vg-detail-inner {
    position: static;
    width: 100%;
}

/* Linha "à parte" com as colunas da grid (VirtualGridAlignedRow), no fluxo da área expandida. */
.vg-row.vg-row-static {
    position: relative;
    left: auto;
    right: auto;
}

.vg-empty {
    padding: 0.75rem 0.625rem;
    font-size: var(--rz-grid-cell-font-size, 0.8125rem);
    color: var(--rz-text-secondary-color, #6b7280);
    background: var(--rz-grid-background-color, #fff);
    position: relative;
}

@keyframes vgrid-skeleton-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .55; }
}

@media (prefers-reduced-motion: reduce) {
    .vg-body::before,
    [data-vgrid] > .rz-data-grid-data::before {
        animation: none;
    }
}
