/**
 * Design System do Portal do Cliente Eutbem
 *
 * Vocabulário visual único do portal (área do cliente). Substitui as pilhas de
 * utilitários Tailwind escritas caractere a caractere nas views por classes
 * semânticas em português.
 *
 * REGRA DE OURO — TRANSCRIÇÃO, NÃO DESIGN: cada classe declara EXATAMENTE o que
 * o elemento de origem entregava no commit ce5721d, nem uma propriedade a mais.
 * Onde os usos divergem, a propriedade sai da base e vira modificador aplicado
 * só nos elementos que a tinham; ela nunca fica na base "porque o componente
 * deveria ter". Quando a classe legada (btn-primary, payment-span, card-padding,
 * contrato-card, resgate-card, notice-block, bid-title…) continua no markup e já
 * entrega a propriedade, esta folha NÃO a repete.
 *
 * Responsabilidades:
 * - Publicar em :root os tokens de cor, escala tipográfica, peso, tracking e
 *   leading do portal, como custom properties nomeadas em português
 * - Oferecer um par de tokens de tema (--tema-cor-primaria / --tema-cor-secundaria)
 *   como único ponto de personalização por parceiro
 * - Definir as famílias de componente do portal: página, cartão, rótulo/valor,
 *   tabela, etiqueta de status, aviso, botão, link, formulário, anexo, passos,
 *   navegação, autenticação, abas, lance, boleto, grade e histórico
 *
 * Convenções:
 * - Nome de classe: portal-<componente>[-<parte>][--<variante>]
 * - Mobile primeiro: a regra base é a versão mobile; o desktop entra em
 *   @media (min-width: 1024px), que é o breakpoint `lg` do portal
 * - `background-color` quando a origem era um utilitário `bg-*`; o atalho
 *   `background` só onde a origem também usava o atalho
 * - `border-width` + `border-color` quando a origem era `border-1`/`border-*`;
 *   o atalho `border` só onde a origem declarava a borda inteira
 * - CSS puro, sem aninhamento e sem dependência de build
 *
 * @package Portal\Recursos\CSS
 * @llmdoc
 */

/* ==========================================================================
   1. TOKENS
   Custom properties derivadas de tailwind.config.js (theme.colors, fontSize,
   fontWeight, letterSpacing, lineHeight). Só entram aqui os tokens realmente
   consumidos pelas telas do portal.
   ========================================================================== */

:root {
    /* --- Paleta rosa (marca secundária) --- */
    --cor-rosa-900: #380434;
    --cor-rosa-800: #5B0755;
    --cor-rosa-700: #800A78;
    --cor-rosa-600: #A70D9D;
    --cor-rosa-500: #D010C4;
    --cor-rosa-400: #FF28F1;
    --cor-rosa-300: #FE55F0;
    --cor-rosa-200: #FF79F4;
    --cor-rosa-100: #FF97F7;
    --cor-rosa-50:  #FFE8FE;

    /* --- Paleta verde (marca primária, sucesso) --- */
    --cor-verde-900: #002312;
    --cor-verde-800: #014926;
    --cor-verde-700: #02723C;
    --cor-verde-600: #029F52;
    --cor-verde-500: #02CE6A;
    --cor-verde-400: #00FF83;
    --cor-verde-300: #69FB9B;
    --cor-verde-200: #81FFB3;
    --cor-verde-100: #A2FFC8;
    --cor-verde-50:  #E0FFF0;

    /* --- Paleta amarela (atenção / ação necessária) --- */
    --cor-amarelo-900: #391A07;
    --cor-amarelo-800: #5D4218;
    --cor-amarelo-700: #826D25;
    --cor-amarelo-600: #A99B33;
    --cor-amarelo-500: #D1CB42;
    --cor-amarelo-400: #FBFE51;
    --cor-amarelo-300: #FEFE76;
    --cor-amarelo-200: #FFFE96;
    --cor-amarelo-100: #FFFFB5;
    --cor-amarelo-50:  #FEFFE4;

    /* --- Escala tipográfica de cinza (hierarquia de texto) --- */
    --cor-texto-900: #232323;
    --cor-texto-800: #3A3A3A;
    --cor-texto-700: #515151;
    --cor-texto-600: #686868;
    --cor-texto-500: #7F7F7F;
    --cor-texto-400: #979797;
    --cor-texto-300: #AEAEAE;
    --cor-texto-200: #C5C5C5;
    --cor-texto-100: #DCDCDC;
    --cor-texto-50:  #F3F3F3;

    /* --- Escala de cinza de borda --- */
    --cor-borda-900: #232323;
    --cor-borda-800: #3A3A3A;
    --cor-borda-700: #515151;
    --cor-borda-600: #686868;
    --cor-borda-500: #7F7F7F;
    --cor-borda-400: #979797;
    --cor-borda-300: #AEAEAE;
    --cor-borda-200: #C5C5C5;
    --cor-borda-100: #DCDCDC;
    --cor-borda-50:  #F3F3F3;

    /* --- Escala de cinza de fundo (superfícies) --- */
    --cor-fundo-900: #232323;
    --cor-fundo-800: #3A3A3A;
    --cor-fundo-700: #515151;
    --cor-fundo-600: #686868;
    --cor-fundo-500: #7F7F7F;
    --cor-fundo-400: #979797;
    --cor-fundo-300: #AEAEAE;
    --cor-fundo-200: #D5D5D5;
    --cor-fundo-100: #EFEFEF;
    --cor-fundo-50:  #FAFAFA;

    /* --- Vermelho (erro / atraso / cancelamento) --- */
    --cor-vermelho-50: #FFD2D2;
    --cor-vermelho-alerta: #E41919;

    /* --- Neutros avulsos --- */
    --cor-branco: #FFFFFF;
    --cor-cinza-discreto: #66758B;
    --cor-cinza-escuro: #0C0C0D;

    /* --- Papéis de tema ---
       ÚNICO ponto de personalização por parceiro. O bloco <style> que hoje é
       injetado em dashboard/base.blade.php e base-bg.blade.php sobrescreve
       utilitários por nome (.bg-white, .text-pink-400, .btn-primary…); depois
       da conversão ele deve passar a definir apenas --tema-cor-* em :root. */
    --cor-primaria: var(--tema-cor-primaria, var(--cor-verde-500));
    --cor-primaria-escura: var(--tema-cor-primaria-escura, var(--cor-verde-600));
    --cor-secundaria: var(--tema-cor-secundaria, var(--cor-rosa-400));

    /* --- Família tipográfica --- */
    --fonte-portal: "Baloo 2", sans-serif;

    /* --- Escala de fonte: desktop (dt-ms-*) --- */
    --fonte-desktop-h4: 20px;
    --fonte-desktop-h5: 18px;
    --fonte-desktop-h6: 16px;
    --fonte-desktop-corpo-1: 16px;
    --fonte-desktop-corpo-2: 16px;
    --fonte-desktop-pequeno-1: 14px;
    --fonte-desktop-pequeno-2: 12px;
    --fonte-desktop-pequeno-3: 12px;
    --fonte-desktop-pequeno-4: 12px;
    --fonte-desktop-botao: 16px;
    --fonte-desktop-botao-link: 16px;
    --fonte-desktop-botao-link-mini: 12px;

    /* --- Escala de fonte: mobile (mb-ms-*) --- */
    --fonte-mobile-h4: 18px;
    --fonte-mobile-h5: 16px;
    --fonte-mobile-h6: 14px;
    --fonte-mobile-corpo-1: 14px;
    --fonte-mobile-corpo-2: 14px;
    --fonte-mobile-pequeno-1: 12px;
    --fonte-mobile-pequeno-2: 12px;
    --fonte-mobile-pequeno-3: 10px;
    --fonte-mobile-pequeno-4: 10px;
    --fonte-mobile-botao: 14px;
    --fonte-mobile-botao-link: 14px;
    --fonte-mobile-botao-link-mini: 10px;

    /* --- Altura de linha: desktop --- */
    --altura-desktop-h4: 28px;
    --altura-desktop-h5: 22px;
    --altura-desktop-h6: 22px;
    --altura-desktop-corpo-1: 22px;
    --altura-desktop-corpo-2: 20px;
    --altura-desktop-pequeno-1: 20px;
    --altura-desktop-pequeno-2: 20px;
    --altura-desktop-pequeno-3: 18px;
    --altura-desktop-pequeno-4: 16px;
    --altura-desktop-botao: 20px;
    --altura-desktop-botao-link: 20px;
    --altura-desktop-botao-link-mini: 18px;

    /* --- Altura de linha: mobile --- */
    --altura-mobile-h4: 26px;
    --altura-mobile-h5: 20px;
    --altura-mobile-h6: 20px;
    --altura-mobile-corpo-1: 20px;
    --altura-mobile-corpo-2: 18px;
    --altura-mobile-pequeno-1: 16px;
    --altura-mobile-pequeno-2: 16px;
    --altura-mobile-pequeno-3: 14px;
    --altura-mobile-pequeno-4: 14px;
    --altura-mobile-botao: 18px;
    --altura-mobile-botao-link: 18px;
    --altura-mobile-botao-link-mini: 16px;

    /* --- Pesos --- */
    --peso-leve: 300;
    --peso-normal: 400;
    --peso-medio: 500;
    --peso-semi: 600;
    --peso-negrito: 700;
    --peso-h4: 600;
    --peso-h5: 600;
    --peso-h6: 600;
    --peso-corpo-1: 400;
    --peso-corpo-2: 600;
    --peso-pequeno-1: 500;
    --peso-pequeno-2: 400;
    --peso-pequeno-3: 400;
    --peso-pequeno-4: 700;
    --peso-botao: 600;

    /* --- Espaçamento entre letras --- */
    --tracking-titulo: 0.2px;
    --tracking-corpo: 0.1px;
    --tracking-pequeno: 0.2px;

    /* --- Medidas estruturais --- */
    --raio-cartao: 6px;
    --raio-caixa: 5px;
    --raio-etiqueta: 4px;
    --raio-bloco: 8px;
    --sombra-cartao: 0 4px 8px rgba(0, 0, 0, 0.04);
    --sombra-elevada: 0 3px 6px rgba(0, 0, 0, 0.14);
    --sombra-botao: 0 3px 3px rgba(0, 0, 0, 0.18);
    --espaco-cartao-lateral: 35px;
}

/* ==========================================================================
   2. LAYOUT DE PÁGINA
   Casca comum de TODAS as telas internas: assembleia, home, lances, pagamento,
   resgate, detalhes e perfil. Absorve payment-container, payment-card e
   fix-padding-mobile.
   ========================================================================== */

/* Casca externa da página; centraliza a coluna e ocupa a altura restante.
   Usada em: dashboard/{assembleia,home,lances,pagamento,resgate,details},
   profile/{index,formularioEmail}. As margens não entram aqui: `payment-container`
   continua no markup dos onze elementos e já as entrega, com o mesmo par de
   breakpoints da origem (`max-width: 1023px` → -50px/64px, `min-width: 1024px`
   → -79px). Duplicá-las criava um `margin-bottom: 0` no desktop que nenhuma
   origem tinha e que apagava o `mb-16` das duas telas de perfil. */
.portal-pagina {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    width: 100%;
    flex-grow: 1;
}

/* Faixa de largura máxima da página (substitui o `container` do Bootstrap
   quando ele existia só para limitar largura). Transcreve
   `flex flex-row container flex-grow`. As origens divergiam em duas coisas —
   três telas não traziam `pb-8` e quatro traziam `lg:flex-grow` em vez de
   `lg:flex-grow-0` — então recuo inferior e travamento no desktop são
   modificadores. */
.portal-pagina-faixa {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    width: 100%;
}

/* Origem com `pb-8`. */
.portal-pagina-faixa--rodape {
    padding-bottom: 2rem;
}

/* Origem com `lg:flex-grow-0`. */
@media (min-width: 1024px) {
    .portal-pagina-faixa--desktop-fixo {
        flex-grow: 0;
    }
}

/* Coluna única de conteúdo dentro da faixa. */
.portal-pagina-coluna {
    display: flex;
    flex-direction: column;
    width: 100%;
    flex-grow: 1;
}

@media (min-width: 1024px) {
    .portal-pagina-coluna {
        flex-grow: 0;
    }
}

/* Cartão branco que embrulha a tela inteira (título + corpo).
   Absorve payment-card + fix-padding-mobile. */
.portal-cartao-pagina {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    background: var(--cor-branco);
    box-shadow: var(--sombra-cartao);
    border-radius: var(--raio-cartao);
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    padding: 0;
}

@media (min-width: 1024px) {
    .portal-cartao-pagina {
        flex-grow: 0;
        border-radius: var(--raio-cartao);
        padding: 55px;
    }
}

/* Título do cartão de página, com linha inferior. Absorve payment-title.
   Usada em: "Meus pagamentos", "Assembleias", "Lances", "Editar dados
   cadastrais", "Boleto pagamento de parcela". */
.portal-cartao-titulo {
    display: flex;
    flex-direction: row;
    align-items: center;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--cor-borda-300);
    font-size: var(--fonte-mobile-corpo-2);
    line-height: var(--altura-mobile-corpo-2);
    font-weight: var(--peso-h6);
    letter-spacing: var(--tracking-titulo);
    color: var(--cor-texto-900);
}

@media (min-width: 1024px) {
    .portal-cartao-titulo {
        font-size: var(--fonte-desktop-h6);
        line-height: var(--altura-desktop-h6);
    }
}

/* Origem com `justify-between`. Três das onze telas não traziam, por isso o
   afastamento entre título e ação é modificador. */
.portal-cartao-titulo--entre {
    justify-content: space-between;
}

/* Corpo do cartão (área entre título/cabeçalho e rodapé).
   O acolchoamento continua vindo de .card-padding (painel.css), que só existe
   acima de 1024px: a origem não tinha padding nenhum no mobile. */
.portal-cartao-corpo {
    display: flex;
    flex-direction: column;
}

/* Corpo em largura total (formulário de solicitação por e-mail). */
.portal-cartao-corpo--plena {
    width: 100%;
}

/* Rodapé cinza do cartão (filtro de ano à esquerda, links de documento à
   direita). Absorve a classe `footer` do contrato-card. */
.portal-cartao-rodape {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    margin-top: auto;
    padding: 1.25rem;
    border-top: 1px solid var(--cor-borda-100);
    border-bottom-left-radius: var(--raio-cartao);
    border-bottom-right-radius: var(--raio-cartao);
}

.portal-cartao-rodape--centro {
    justify-content: center;
}

/* ==========================================================================
   3. CARTÕES DE ITEM
   Cartão de contrato (home), de assembleia, de contemplados (JS), de documento
   (detalhes), de opção de resgate. Absorve contrato-card, resgate-card,
   detail-card, payment-box.
   ========================================================================== */

/* Cartão genérico de item. A superfície (fundo, borda, raio, box-sizing) segue
   vindo da classe legada que continua no markup — contrato-card, resgate-card,
   payment-box, bg-white, border-1 — porque cada uma delas entregava um conjunto
   diferente e nenhuma origem tinha todas. */
.portal-cartao {
    display: flex;
    flex-direction: column;
}

/* Cartão com elevação (contrato na home, contemplados, opção de resgate). */
.portal-cartao--sombra {
    box-shadow: var(--sombra-elevada);
}

/* Cartão em destaque: assembleia vigente e próxima parcela a vencer.
   Transcreve `border-green-500 border-2 box-border p-6`; a espessura e a cor
   entram separadas porque o preflight já fixa border-style: solid. */
.portal-cartao--destaque {
    box-sizing: border-box;
    border-width: 2px;
    border-color: var(--cor-primaria);
    padding: 1.5rem;
}

/* Cartão com o acolchoamento interno grande (opção de resgate). */
.portal-cartao--acolchoado {
    padding: 15px;
}

@media (min-width: 1024px) {
    .portal-cartao--acolchoado {
        padding: 40px;
    }
}

/* Cartão selecionável de documento (detalhes do contrato). */
.portal-cartao--selecionavel {
    border-width: 1.5px;
    box-shadow: var(--sombra-elevada);
}

.portal-cartao--selecionavel.portal-cartao--ativo {
    border: 2px solid var(--cor-secundaria);
}

/* Cabeçalho de um cartão de item (data + número à esquerda, ação à direita).
   A origem era `flex px-6 py-8 flex-row justify-between w-full items-center`:
   nunca houve linha inferior, e o acolchoamento vinha em longhand. */
.portal-cartao-cabecalho {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
}

/* Acolchoamento `px-6 py-8` do cabeçalho do cartão de assembleia. */
.portal-cartao-cabecalho--acolchoado {
    width: 100%;
    padding-left: 1.5rem;
    padding-right: 1.5rem;
    padding-top: 2rem;
    padding-bottom: 2rem;
}

/* Variante cinza do cabeçalho, com título e contador (cartões de lance).
   O fundo, o peso, o `p-6`, a cor da borda e o `box-border` seguem nos
   utilitários do markup; aqui ficam o tamanho da fonte e o `style` inline com
   os cantos superiores e a espessura da linha de baixo.
   Aparece SEM a classe base nos dois cabeçalhos de lances/form.blade.php: lá a
   origem não trazia `flex flex-row justify-between items-center`. */
.portal-cartao-cabecalho--cinza {
    font-size: var(--fonte-desktop-h6);
    border-top-left-radius: var(--raio-cartao);
    border-top-right-radius: var(--raio-cartao);
    border-bottom-width: 1px;
}

/* Título de um cartão de item (documento, opção de resgate).
   A origem era só `text-dt-ms-h6` (font-size), sem leading nem tracking. */
.portal-cartao-titulo-item {
    font-size: var(--fonte-desktop-h6);
    color: var(--cor-texto-900);
}

/* Descrição cinza sob o título do cartão de item.
   A origem era só `text-dt-ms-small-2` (font-size), sem leading nem tracking. */
.portal-cartao-descricao {
    margin-top: 0.5rem;
    font-size: var(--fonte-desktop-pequeno-2);
    color: var(--cor-texto-500);
}

/* Faixa horizontal de pares rótulo/valor no topo do cartão (cota, grupo,
   carta de crédito, total pago). Rola lateralmente no mobile.
   Absorve contrato-infos e a classe `header` do contrato-card. */
.portal-faixa-dados {
    display: flex;
    flex-direction: row;
    align-items: center;
    width: 100%;
}

/* Extremos afastados (as três faixas que traziam justify-between). */
.portal-faixa-dados--entre {
    justify-content: space-between;
}

/* Faixa que rola lateralmente (transcreve overflow-x-scroll). */
.portal-faixa-dados--rolavel {
    overflow-x: scroll;
}

/* Fundo cinza da faixa (transcreve bg-typo-gray-50). */
.portal-faixa-dados--fundo {
    background-color: var(--cor-texto-50);
}

/* Acolchoamento p-2/lg:p-6 da faixa do cartão de assembleia. */
.portal-faixa-dados--acolchoada {
    padding: 0.5rem;
}

@media (min-width: 1024px) {
    .portal-faixa-dados--acolchoada {
        padding: 1.5rem;
    }
}

/* Coluna de um par rótulo/valor dentro da faixa de dados ou do cartão. Só
   metade das origens trazia `flex-shrink-0`, e o `pl-3 pr-6` não existia nas
   colunas do cartão de assembleia — os dois viraram modificador. */
.portal-campo {
    display: flex;
    flex-direction: column;
}

/* Coluna que não encolhe na faixa rolável (`flex-shrink-0`). */
.portal-campo--rigido {
    flex-shrink: 0;
}

/* Acolchoamento lateral `pl-3 pr-6`. */
.portal-campo--recuado {
    padding-left: 0.75rem;
    padding-right: 1.5rem;
}

/* Acolchoamento lateral `pl-5 pr-6` da primeira coluna do cartão no mobile. */
.portal-campo--recuado-largo {
    padding-left: 1.25rem;
    padding-right: 1.5rem;
}

/* Variante com afastamento à esquerda em vez de padding (cartão de assembleia). */
.portal-campo--espacado {
    margin-left: 1.5rem;
}

/* Afastamento menor `ml-5`. */
.portal-campo--espacado-curto {
    margin-left: 1.25rem;
}

/* Par rótulo/valor que empilha no mobile e vira linha no desktop
   (faixa de identificação do contrato: "Cota: 123"). */
.portal-campo-inline {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    align-items: flex-start;
    padding-left: 0.75rem;
    padding-right: 0.5rem;
}

@media (min-width: 1024px) {
    .portal-campo-inline {
        flex-direction: row;
        align-items: center;
        padding-right: 1.5rem;
    }
}

/* ==========================================================================
   4. RÓTULOS, VALORES E LINHAS DE DADO
   Três escalas distintas de par rótulo/valor, medidas nos inventários.
   ========================================================================== */

/* Rótulo pequeno e leve acima do valor (faixa de dados, <th> de tabela).
   Escala pequeno-3 / peso 300 / cinza 500. */
.portal-rotulo {
    font-size: var(--fonte-desktop-pequeno-3);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-leve);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-500);
}

.portal-rotulo--direita {
    text-align: right;
}

/* Valor em negrito logo abaixo do rótulo. Escala pequeno-1 / bold / cinza 900. */
.portal-valor {
    font-size: var(--fonte-desktop-pequeno-1);
    line-height: var(--altura-desktop-pequeno-1);
    font-weight: var(--peso-negrito);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

.portal-valor--direita {
    text-align: right;
}

.portal-valor--fim {
    align-self: flex-end;
}

/* Valor no estado cancelado (contrato cancelado na home). */
.portal-valor--alerta {
    color: var(--cor-vermelho-alerta);
}

/* Valor que precisa concatenar partes em linha (cota + sequência). */
.portal-valor--linha {
    display: flex;
    flex-direction: row;
}

/* Rótulo empilhado dentro dos cartões de assembleia
   ("Data da assembleia:", "Cota contemplada", "Lance ganhador (%)"). */
.portal-rotulo-empilhado {
    display: inline-flex;
    align-items: center;
    width: 100%;
    margin-top: 0.5rem;
    padding-right: 1rem;
    font-size: var(--fonte-desktop-pequeno-1);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-pequeno-3);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-500);
}

@media (min-width: 1024px) {
    .portal-rotulo-empilhado {
        width: auto;
    }
}

/* Valor sob o rótulo empilhado; também é a descrição principal de uma
   cobrança ("Parcela (3/60)"). Escala corpo-2. */
.portal-valor-empilhado {
    display: inline-block;
    width: 100%;
    margin-top: 0.25rem;
    font-size: var(--fonte-mobile-corpo-2);
    line-height: var(--altura-mobile-corpo-2);
    font-weight: var(--peso-corpo-2);
    letter-spacing: var(--tracking-corpo);
}

@media (min-width: 1024px) {
    .portal-valor-empilhado {
        font-size: var(--fonte-desktop-corpo-2);
        line-height: var(--altura-desktop-corpo-2);
    }
}

/* Rótulo do lado esquerdo de uma linha de dado (resumo do lance, resumo do
   contrato). Escala h6 / peso 300 / cinza 500. */
.portal-rotulo-linha {
    font-size: var(--fonte-desktop-h6);
    color: var(--cor-texto-500);
}

.portal-rotulo-linha--pequeno {
    font-size: var(--fonte-desktop-pequeno-2);
}

/* Valor do lado direito da linha de dado. Par obrigatório de
   .portal-rotulo-linha. */
.portal-valor-linha {
    font-size: var(--fonte-desktop-h6);
    color: var(--cor-texto-900);
}

.portal-valor-linha--pequeno {
    font-size: var(--fonte-desktop-pequeno-2);
}

/* Linha de total / destaque em negrito dentro do cartão. */
.portal-valor-linha--total {
    font-weight: var(--peso-semi);
}

/* Contador/observação discreta à direita do cabeçalho ("3 ofertas registradas").
   A origem era `text-dt-ms-small-2 font-weight-normal text-typo-gray-500`: não
   trazia `leading-*`, então a classe não declara `line-height`. */
.portal-contador {
    font-size: var(--fonte-desktop-pequeno-2);
    font-weight: var(--peso-normal);
    color: var(--cor-texto-500);
}

/* Linha de dado: rótulo à esquerda, valor à direita. A divisória, o recuo e a
   cor da borda vinham cada um de um lugar diferente (`py-5`,
   `border-background-gray-100` e `style` inline), então cada um virou o seu
   modificador em vez de entrar todo na base. */
.portal-linha-dado {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
}

/* Recuo vertical `py-5`. */
.portal-linha-dado--espacada {
    padding-top: 1.25rem;
    padding-bottom: 1.25rem;
}

/* Só o recuo de cima (`style="padding-top: 1.25rem"`). */
.portal-linha-dado--recuo-topo {
    padding-top: 1.25rem;
}

/* Só o recuo de baixo (`style="padding-bottom: 1.25rem"`). */
.portal-linha-dado--recuo-base {
    padding-bottom: 1.25rem;
}

/* Cor da divisória (`border-background-gray-100`). Sozinha não pinta nada: o
   preflight deixa border-width em 0, exatamente como na origem. */
.portal-linha-dado--divisor {
    border-color: var(--cor-fundo-100);
}

/* Divisória visível embaixo (`style="border-bottom-width: 1px"`). */
.portal-linha-dado--linha-inferior {
    border-bottom-width: 1px;
}

/* Linha de dado avulsa, fora de cartão (data do lance, data da assembleia). */
.portal-linha-dado--solta {
    align-items: center;
    margin-bottom: 1rem;
}

/* Rodapé de ação do cartão, separado por linha tracejada (botão principal).
   A largura e o estilo da linha vêm em longhand de propósito: a cor continua
   sendo a de `border-background-gray-200` (#D5D5D5), que segue no markup; o
   shorthand `border-top` resetaria a cor para a do design system. */
.portal-cartao-acoes {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    padding-top: 1.5rem;
    padding-bottom: 1.5rem;
    padding-left: var(--espaco-cartao-lateral);
    padding-right: var(--espaco-cartao-lateral);
    border-top-width: 1px;
    border-top-style: dashed;
}

/* ==========================================================================
   5. TÍTULOS E TEXTOS
   ========================================================================== */

/* Título de seção dentro da página ("Assembleia vigente", "Ganhadores por
   lance", "Cancelados do grupo"). Escala h5. */
/* A origem trazia só `text-mb-ms-h5 lg:text-dt-ms-h5 font-weight-600`: font-size
   e peso, sem leading, tracking nem cor. */
.portal-titulo-secao {
    display: flex;
    flex-direction: column;
    width: 100%;
    font-size: var(--fonte-mobile-h5);
    font-weight: var(--peso-h5);
}

@media (min-width: 1024px) {
    .portal-titulo-secao {
        font-size: var(--fonte-desktop-h5);
    }
}

/* Respiro superior de "Assembleia vigente" (transcreve o `mt-6`). */
.portal-titulo-secao--espacado {
    margin-top: 1.5rem;
}

/* Respiro largo das seções de ganhadores e cancelados (transcreve o
   `style="margin-top: 56px"` que estava inline nas três). */
.portal-titulo-secao--afastado {
    margin-top: 56px;
}

/* Faixa do título de bloco com sublinhado colorido ("LANCES", "RESGATE
   LIBERADO", "ASSEMBLEIA", "NÚMEROS DA SORTE"). O sublinhado e o recuo inferior
   continuam vindo de bid-title / next-bid-title / resgate-title, que seguem no
   markup: a origem nunca declarou display, tipografia nem cor aqui. */
.portal-titulo-bloco {
    flex-direction: row;
    align-items: center;
    width: 100%;
}

/* Bloco em estado cancelado. */
.portal-titulo-bloco--alerta {
    color: var(--cor-vermelho-alerta);
}

/* Título tipográfico escala h6 dentro do cartão de contrato ("CONTEMPLAÇÃO
   PENDENTE", "RESGATE LIBERADO"). Transcreve
   `text-dt-ms-h6 font-weight-ms-h6 tracking-ms-h6 leading-dt-ms-h6`; a cor
   segue vindo de text-typo-gray-900 no markup. */
.portal-titulo-cartao {
    font-size: var(--fonte-desktop-h6);
    line-height: var(--altura-desktop-h6);
    font-weight: var(--peso-h6);
    letter-spacing: var(--tracking-titulo);
}

/* Título de seção de formulário ("Informe os dados do fornecedor",
   "Digite o valor que quer resgatar"). A origem era só `text-dt-ms-h6`. */
.portal-titulo-formulario {
    font-size: var(--fonte-desktop-h6);
    color: var(--cor-texto-600);
}

.portal-titulo-formulario--intercalado {
    margin-top: 1rem;
    margin-bottom: 0.5rem;
}

/* Título de formulário que traz ícone de ajuda ao lado. */
.portal-titulo-formulario--com-ajuda {
    display: flex;
    flex-direction: column;
    margin-bottom: 0.5rem;
}

@media (min-width: 1024px) {
    .portal-titulo-formulario--com-ajuda {
        flex-direction: row;
    }
}

/* Título de destaque, escala h4 ("Como deseja resgatar?", "Sua solicitação já
   está em análise", título de campo do formulário de lance). */
/* A origem era `text-dt-ms-h4 font-weight-600`: tamanho e peso, sem leading
   nem tracking. */
/* As sete origens eram `text-dt-ms-h4 font-weight-600`, que valia 20px em
   qualquer largura — não havia `text-mb-ms-h4`, logo não há breakpoint. Cor
   também não entra: quatro das origens não traziam classe de cor nenhuma, e as
   outras três seguem com `text-typo-gray-900` no markup. */
.portal-titulo-destaque {
    font-size: var(--fonte-desktop-h4);
    font-weight: var(--peso-h4);
}

.portal-titulo-destaque--centro {
    text-align: center;
}

/* Parágrafo explicativo logo abaixo do título de bloco ("Parabéns! Sua cota
   foi contemplada…"). */
.portal-texto-secao {
    margin-top: 0.5rem;
    font-size: var(--fonte-desktop-pequeno-2);
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-pequeno-2);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

.portal-texto-secao--forte {
    font-weight: var(--peso-negrito);
}

/* Linha em negrito com dado de destaque (assembleia, números da sorte,
   chamada do lance no mobile). */
.portal-texto-destaque {
    margin-top: 0.5rem;
    font-size: var(--fonte-mobile-pequeno-2);
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-negrito);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

/* Texto de apoio cinza e leve, centrado ("Em até 3 dias úteis…",
   "Agora você pode acessar sua conta com a nova senha"). */
/* As quatro origens só tinham `text-center` em comum: o tamanho variava
   (16px, 14px inline, nenhum), o recuo superior variava (mt-3, mt-4, 8px
   inline, nenhum) e só uma trazia peso. Tudo isso volta pro elemento. */
.portal-texto-apoio {
    text-align: center;
}

/* Nota discreta abaixo de um cartão ou campo ("Importante: você pode ajustar
   seu lance…", "Este valor é calculado automaticamente"). */
/* Origem `text-dt-ms-small-2 font-weight-normal mt-4 mb-1`: sem `leading-*`,
   logo sem `line-height`. */
.portal-nota {
    margin-top: 1rem;
    margin-bottom: 0.25rem;
    font-size: var(--fonte-desktop-pequeno-2);
    font-weight: var(--peso-normal);
    color: var(--cor-texto-600);
}

/* Mensagem de lista vazia ("Nenhum lance registrado ainda"). */
.portal-lista-vazia {
    padding-top: 1.25rem;
    padding-bottom: 1.25rem;
    text-align: center;
    color: var(--cor-texto-500);
}

/* Trecho grifado dentro de um texto corrido. */
.portal-texto-grifo {
    font-weight: var(--peso-negrito);
}

/* Caixa com contorno vermelho do texto legal do contrato cancelado. Transcreve
   `mt-4 p-4`: a espessura vem de `border-1` e a cor de `border-red-alert`, que
   seguem no markup, e a origem não tinha canto arredondado. */
.portal-caixa-legal {
    margin-top: 1rem;
    padding: 1rem;
}

.portal-caixa-legal-titulo {
    font-size: var(--fonte-desktop-pequeno-2);
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-negrito);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

.portal-caixa-legal-texto {
    margin-top: 0.5rem;
    font-size: var(--fonte-desktop-pequeno-3);
    line-height: var(--altura-desktop-pequeno-3);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

/* ==========================================================================
   6. TABELAS
   Tabelas de contemplados/cancelados (assembleia e contemplacoes.js).
   ========================================================================== */

/* Faixa que rola lateralmente no mobile e segura a tabela ou a linha de
   colunas de um contemplado. */
/* Transcreve `mt-3 flex flex-row overflow-x-scroll lg:overflow-x-hidden
   overflow-y-hidden`: a origem nunca teve acolchoamento. */
.portal-faixa-rolavel {
    display: flex;
    flex-direction: row;
    margin-top: 0.75rem;
    overflow-x: scroll;
    overflow-y: hidden;
}

@media (min-width: 1024px) {
    .portal-faixa-rolavel {
        overflow-x: hidden;
    }
}

.portal-faixa-rolavel--branca {
    background-color: var(--cor-branco);
}

/* Tabela de cotas contempladas / canceladas. A origem era `w-full
   border-background-gray-200`: largura e cor de borda, sem espessura. A
   colapsagem já vem do preflight (`table { border-collapse: collapse }`). */
.portal-tabela {
    width: 100%;
}

/* Célula de cabeçalho da tabela (<th>) — usa a tipografia de .portal-rotulo. */
.portal-tabela-cabecalho-celula {
    padding: 0.75rem 1rem;
    text-align: left;
    white-space: nowrap;
}

/* Célula de dado da tabela (<td>) — usa a tipografia de .portal-valor. */
.portal-tabela-celula {
    padding: 0.75rem 1rem;
    text-align: left;
    white-space: nowrap;
}

/* ==========================================================================
   7. ETIQUETAS DE STATUS
   Selo curto de estado da cobrança/contemplação. Absorve payment-span,
   bid-notice e resgate-notice.
   ========================================================================== */

/* Só a tipografia: o acolchoamento e o raio seguem vindo de .payment-span, que
   continua no markup, e a espessura da borda de `border-1`. A origem não punha
   display, alinhamento nem centralização de texto na etiqueta. */
.portal-etiqueta {
    font-size: var(--fonte-mobile-pequeno-2);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-pequeno);
}

@media (min-width: 1024px) {
    .portal-etiqueta {
        font-size: var(--fonte-desktop-pequeno-3);
    }
}

/* Etiqueta que a origem punha em caixa flexível centrada
   (`flex items-center justify-center`). */
.portal-etiqueta--flex {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Texto centrado (`text-center`). */
.portal-etiqueta--centralizada {
    text-align: center;
}

/* Etiqueta ancorada no início da coluna (`self-start`). */
.portal-etiqueta--inicio {
    align-self: flex-start;
}

/* Respiro `mt-1 lg:mt-0` da etiqueta na linha de cobrança. */
.portal-etiqueta--respiro {
    margin-top: 0.25rem;
}

@media (min-width: 1024px) {
    .portal-etiqueta--respiro {
        margin-top: 0;
    }
}

/* Respiro `mt-2`. */
.portal-etiqueta--espacada {
    margin-top: 0.5rem;
}

/* Cobrança em aberto dentro do prazo (Pendente, Aguardando).
   As origens eram utilitários `bg-*`, que declaram background-color: manter o
   atalho `background` acrescentaria background-image/position/repeat. */
.portal-etiqueta--aguardando {
    background-color: var(--cor-rosa-50);
    border-color: var(--cor-rosa-200);
    color: var(--cor-rosa-600);
}

/* Cobrança liquidada (Pago, Pago via boleto/pix, Contemplação efetivada). */
.portal-etiqueta--pago {
    background-color: var(--cor-verde-50);
    border-color: var(--cor-verde-300);
    color: var(--cor-verde-700);
}

/* Divergência de valor / ação necessária / aguardando pagamento do lance. */
.portal-etiqueta--atencao {
    background-color: var(--cor-amarelo-50);
    border-color: var(--cor-amarelo-500);
    color: var(--cor-amarelo-800);
}

/* Parcela em atraso, cancelada ou pagamento expirado.
   Correção deliberada: `bg-red-light` nunca existiu em CSS nenhum — o fundo
   vermelho passa a pintar de verdade em 7 pontos do portal. */
.portal-etiqueta--atraso {
    background-color: var(--cor-vermelho-50);
    border-color: var(--cor-vermelho-alerta);
    color: var(--cor-vermelho-alerta);
}

/* Selo neutro branco (contagem regressiva, "Grupo sem data de assembleia").
   Transcreve `text-dt-ms-body-2 tracking-ms-body-2 font-weight-ms-body-2
   leading-dt-ms-body-2 text-green-500`; fundo, raio, acolchoamento e o
   max-width do desktop seguem vindo de bg-white, bid-notice, py-1/px-5 e
   span-notice, todos ainda no markup. */
.portal-etiqueta--contagem {
    font-size: var(--fonte-desktop-corpo-2);
    line-height: var(--altura-desktop-corpo-2);
    font-weight: var(--peso-corpo-2);
    letter-spacing: var(--tracking-corpo);
    color: var(--cor-primaria);
}

/* Selo cinza neutro. */
.portal-etiqueta--neutro {
    background-color: var(--cor-branco);
    border-color: var(--cor-borda-100);
    color: var(--cor-texto-900);
}

/* Marcação "(mais recente)" na oferta válida do histórico. A origem era só
   `text-green-600 font-weight-600` — não é uma etiqueta, não tem caixa. */
.portal-marca-recente {
    font-weight: var(--peso-semi);
    color: var(--cor-verde-600);
}

/* Chip clicável que preenche o campo com um valor pronto (Mínimo, 50%,
   Máximo, Zerar) no formulário de lance. */
.portal-etiqueta-acao {
    font-size: var(--fonte-mobile-pequeno-2);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-pequeno);
    cursor: pointer;
    transition: background 100ms;
}

@media (min-width: 1024px) {
    .portal-etiqueta-acao {
        font-size: var(--fonte-desktop-pequeno-3);
    }
}

/* Chip que vem depois do primeiro da faixa (transcreve o `ml-2`). */
.portal-etiqueta-acao--afastado {
    margin-left: 0.5rem;
}

.portal-etiqueta-acao--valor {
    background-color: var(--cor-amarelo-50);
    border-color: var(--cor-amarelo-500);
    color: var(--cor-amarelo-800);
}

.portal-etiqueta-acao--valor:hover {
    background-color: var(--cor-amarelo-100);
}

/* Chip "Zerar". Correção deliberada: hoje bg-red-100/text-red-700/
   border-red-300 não pintam nada e o chip parece texto solto. */
.portal-etiqueta-acao--limpar {
    background-color: var(--cor-vermelho-50);
    border-color: var(--cor-vermelho-alerta);
    color: var(--cor-vermelho-alerta);
}

.portal-etiqueta-acao--limpar:hover {
    background-color: var(--cor-vermelho-50);
    filter: brightness(0.95);
}

/* Estado "valor excedido", aplicado por JS. Correção deliberada: a paleta do
   portal não tem laranja; o estado de bloqueio passa a usar a escala amarela,
   que é a cor de atenção real do produto. */
.portal-etiqueta-acao--bloqueado {
    background-color: var(--cor-amarelo-50);
    border-color: var(--cor-amarelo-500);
    color: var(--cor-amarelo-900);
    cursor: not-allowed;
    opacity: 0.7;
}

.portal-etiqueta-acao--bloqueado:hover {
    background-color: var(--cor-amarelo-50);
}

/* ==========================================================================
   8. AVISOS
   Duas famílias distintas: a FAIXA fina (uma linha, ícone + texto + link) e o
   BLOCO grande do cartão da home (notice-block, 32px de padding).
   O `style="padding: 15px !important"` das views existia só para vencer o
   padding de .payment-span — aqui a faixa já nasce com o padding certo.
   ========================================================================== */

/* Só a tipografia da escala pequeno-3, que era o único traço comum às faixas
   que vinham de payment-span. A espessura da borda continua em `border-1` /
   `border` no markup; caixa e espaçamento entram por modificador. */
.portal-faixa-aviso {
    font-size: var(--fonte-mobile-pequeno-2);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-pequeno-3);
    letter-spacing: var(--tracking-pequeno);
}

@media (min-width: 1024px) {
    .portal-faixa-aviso {
        font-size: var(--fonte-desktop-pequeno-3);
    }
}

/* Faixa em linha (transcreve `flex flex-row`). */
.portal-faixa-aviso--linha {
    display: flex;
    flex-direction: row;
}

/* Conteúdo centrado no eixo transversal (transcreve `items-center`). */
.portal-faixa-aviso--centrada {
    align-items: center;
}

/* Respiro superior `mt-2`. */
.portal-faixa-aviso--espacada {
    margin-top: 0.5rem;
}

/* Acolchoamento de 15px e raio de 4px que vinham do `style` inline junto de
   .payment-span. */
.portal-faixa-aviso--acolchoada {
    padding: 15px;
    border-radius: var(--raio-etiqueta);
}

/* Faixa de sucesso do cartão de contrato: `p-3 mt-3` e raio inline de 4px. */
.portal-faixa-aviso--compacta {
    margin-top: 0.75rem;
    padding: 0.75rem;
    border-radius: var(--raio-etiqueta);
}

/* Erro: parcela atrasada, pagamento não realizado, erros de validação do
   formulário de resgate, notificação de erro do lance.
   Correção deliberada: border-red-400 e text-red-700 não existiam. */
.portal-faixa-aviso--erro {
    background-color: var(--cor-vermelho-50);
    border-color: var(--cor-vermelho-alerta);
    color: var(--cor-vermelho-alerta);
}

/* Sucesso: "Você já pode fazer seu resgate!", "Contrato já contemplado". */
.portal-faixa-aviso--sucesso {
    background-color: var(--cor-verde-50);
    border-color: var(--cor-verde-300);
    color: var(--cor-verde-700);
    font-weight: var(--peso-medio);
}

/* Atenção: pagou a menos / pagou a mais, "CNPJ deve ser o mesmo da NF",
   "Crédito disponível: R$ X". */
.portal-faixa-aviso--atencao {
    background-color: var(--cor-amarelo-50);
    border-color: var(--cor-amarelo-500);
    color: var(--cor-amarelo-800);
}

/* Neutro: lembrete do rodapé ("é preciso estar em dia com as parcelas").
   Transcreve o `style` inline do footer-alert: fundo branco, sombra de cartão,
   raio de 6px e 15px de acolchoamento. Não tinha borda nem cor própria. */
.portal-faixa-aviso--neutro {
    background-color: var(--cor-branco);
    box-shadow: var(--sombra-cartao);
    border-radius: var(--raio-cartao);
    padding: 15px;
}

/* Notificação flutuante no canto superior direito. */
.portal-faixa-aviso--flutuante {
    position: fixed;
    top: 1rem;
    right: 1rem;
    box-shadow: var(--sombra-elevada);
}

/* Corpo de texto da faixa: empilha no mobile, alinha em linha no desktop. */
.portal-faixa-aviso-texto {
    display: flex;
    flex-direction: column;
}

@media (min-width: 1024px) {
    .portal-faixa-aviso-texto {
        flex-direction: row;
    }
}

/* Lista com marcadores dos erros de validação dentro da faixa. */
.portal-faixa-aviso-lista {
    margin-top: 0.5rem;
    list-style-type: disc;
    list-style-position: inside;
}

/* Bloco de aviso do cartão da home, com ícone à esquerda e conteúdo à direita.
   Absorve notice-block. */
/* O raio e o acolchoamento seguem vindo de .notice-block, que continua no
   markup; a espessura da borda, de `border-1` nos ramos que a traziam. */
.portal-bloco-aviso {
    display: flex;
    flex-direction: row;
    align-items: center;
    width: 100%;
    margin-top: 0.5rem;
}

/* Lance em aberto. O fundo continua no utilitário `bg-green-50` do markup. */
.portal-bloco-aviso--lance {
    background-color: var(--cor-verde-50);
}

/* Contemplação pendente (aguardando pagamento do lance). Transcreve o
   `style="border: 1px solid #f59e0b; border-radius: 8px"` inline. */
.portal-bloco-aviso--pendente {
    border: 1px solid #f59e0b;
    border-radius: var(--raio-bloco);
}

/* Crédito disponível para resgate. */
.portal-bloco-aviso--resgate {
    background-color: var(--cor-rosa-50);
}

/* Crédito já resgatado. */
.portal-bloco-aviso--concluido {
    background-color: var(--cor-branco);
}

/* Versão mobile empilhada (ícone e valor em cima, botão embaixo). */
.portal-bloco-aviso--empilhado {
    flex-direction: column;
    margin-top: 2rem;
}

/* Coluna de conteúdo à direita do ícone do bloco de aviso.
   A base só carrega o que as três origens tinham em comum
   (`flex flex-col w-full`); recuo e alinhamento ficam nos modificadores,
   porque as origens divergiam. */
.portal-bloco-aviso-conteudo {
    display: flex;
    flex-direction: column;
    width: 100%;
}

/* Origem `flex flex-col ml-8 mt-4 items-start w-full mb-5`. */
.portal-bloco-aviso-conteudo--afastado {
    align-items: flex-start;
    margin-left: 2rem;
    margin-top: 1rem;
    margin-bottom: 1.25rem;
}

/* Recuo menor (aviso de contemplação pendente no mobile).
   Origem `flex flex-col ml-4 mt-4 items-start w-full mb-5`. */
.portal-bloco-aviso-conteudo--estreito {
    align-items: flex-start;
    margin-left: 1rem;
    margin-top: 1rem;
    margin-bottom: 1.25rem;
}

/* Coluna de conteúdo centrada (contagem regressiva + barra de progresso).
   A origem era `flex flex-col w-full pl-4 text-center`: sem margens e sem
   align-items — os filhos esticavam na largura. */
.portal-bloco-aviso-conteudo--centro {
    padding-left: 1rem;
    text-align: center;
}

/* Legenda dentro do bloco ("Crédito disponível", "Aguardando pagamento"). */
.portal-bloco-aviso-legenda {
    font-size: var(--fonte-desktop-pequeno-3);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-pequeno-3);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

.portal-bloco-aviso-legenda--centro {
    align-self: center;
    margin-top: 0.25rem;
}

/* Faixa inferior do bloco onde fica o botão RESGATAR no mobile. */
.portal-bloco-aviso-acoes {
    display: flex;
    flex-direction: column;
    width: 100%;
    margin-top: 1rem;
}

/* Emblema com o valor em BRL do crédito disponível. Absorve resgate-notice. */
/* O raio vem de .resgate-notice e o fundo/cor dos utilitários `bg-*`/`text-*`
   do ternário, todos ainda no markup. A largura é a dos cartões mobile
   (`w-full`); os cartões desktop vinham de `w-1/2` e ficam no modificador. Nenhuma
   das quatro origens era responsiva, então aqui não entra breakpoint. */
.portal-valor-credito {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    margin-top: 0.25rem;
    margin-right: 0.5rem;
    padding: 0.25rem;
    font-size: var(--fonte-desktop-corpo-2);
    line-height: var(--altura-desktop-corpo-2);
    font-weight: var(--peso-semi);
    letter-spacing: var(--tracking-corpo);
}

/* Origem `w-1/2` (emblema dos cartões desktop). */
.portal-valor-credito--metade {
    width: 50%;
}

/* Caixa cinza informativa no pé do cartão ("A compensação do pagamento por
   boleto é de até 3 dias úteis"). */
.portal-caixa-informativa {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin-top: 1.25rem;
    padding: 1rem;
    background-color: var(--cor-fundo-100);
    border-radius: var(--raio-caixa);
}

/* Origem `text-center text-mb-ms-small-3 lg:text-dt-ms-small-2
   font-weight-ms-small-3 text-typo-gray-900`: sem `leading-*`. */
.portal-caixa-informativa-texto {
    text-align: center;
    font-size: var(--fonte-mobile-pequeno-3);
    font-weight: var(--peso-pequeno-3);
    color: var(--cor-texto-900);
}

@media (min-width: 1024px) {
    .portal-caixa-informativa-texto {
        font-size: var(--fonte-desktop-pequeno-2);
    }
}

/* ==========================================================================
   9. BOTÕES E LINKS
   Uma família só. Absorve btn-primary, btn-pink e o botão CANCELAR que hoje é
   recriado com `style` inline (#02ce6a) em três arquivos do perfil.
   ========================================================================== */

/* A caixa do botão (padding, raio, sombra, box-sizing, transição, fundo) segue
   vindo de btn-primary / btn-pink / btn-secondary, que continuam no markup.
   Nenhuma origem declarava display, alinhamento, caixa alta, sublinhado, cursor
   nem tracking: tudo isso virou modificador aplicado só onde havia utilitário. */
.portal-botao {
    font-size: var(--fonte-mobile-botao);
    font-weight: var(--peso-botao);
}

@media (min-width: 1024px) {
    .portal-botao {
        font-size: var(--fonte-desktop-botao);
    }
}

/* Botão que a origem punha em linha flexível centrada
   (`flex items-center justify-center`). */
.portal-botao--flex {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Botão que a origem punha em bloco (`block`). */
.portal-botao--em-bloco {
    display: block;
}

/* Texto centrado (`text-center`). */
.portal-botao--centralizado {
    text-align: center;
}

/* Rótulo em caixa alta (`uppercase`). */
.portal-botao--maiusculo {
    text-transform: uppercase;
}

/* Ação principal verde (DAR LANCE, PAGAR AGORA, AVANÇAR, SALVAR, ACESSAR). */
.portal-botao--primario {
    background: var(--cor-primaria);
    color: var(--cor-branco);
}

.portal-botao--primario:hover,
.portal-botao--primario:active {
    background: var(--cor-primaria-escura);
    box-shadow: var(--sombra-elevada);
}

/* Ação rosa (RESGATAR, Filtrar). */
.portal-botao--rosa {
    background: var(--cor-secundaria);
    color: var(--cor-branco);
}

.portal-botao--rosa:hover,
.portal-botao--rosa:active {
    box-shadow: var(--sombra-elevada);
}

/* Ação secundária de contorno (CANCELAR, "Enviar nova solicitação"). */
.portal-botao--contorno {
    background: var(--cor-branco);
    border-color: var(--cor-primaria);
    color: var(--cor-primaria);
}

.portal-botao--contorno:hover {
    background: var(--cor-verde-50);
}

/* Largura total. */
.portal-botao--bloco {
    width: 100%;
}

/* Largura total no mobile, largura própria no desktop. */
.portal-botao--auto {
    width: 100%;
}

@media (min-width: 1024px) {
    .portal-botao--auto {
        width: auto;
    }
}

/* Botão compacto. */
.portal-botao--compacto {
    padding: 7px 12px;
}

/* Estado desabilitado (a classe é alternada por JS). O cursor não entra: a
   origem só trazia `cursor-pointer` em dois botões, e neles ele era pointer. */
.portal-botao--desabilitado,
.portal-botao:disabled {
    background: var(--cor-fundo-100);
    border-color: transparent;
    color: var(--cor-texto-200);
    box-shadow: none;
}

/* Link sublinhado padrão do portal (rodapé do cartão, ESCOLHER ARQUIVO,
   INFORME DE IR, DETALHES DO CONTRATO). O sublinhado segue vindo do utilitário
   `underline`, que continua no markup e declara text-decoration-line. */
.portal-link {
    font-size: var(--fonte-mobile-botao-link);
    font-weight: var(--peso-botao);
    color: var(--cor-texto-900);
}

@media (min-width: 1024px) {
    .portal-link {
        font-size: var(--fonte-desktop-botao-link);
    }
}

/* Entrelinha do link. Fica em modificador, e não na classe base, porque a
   maioria dos links da origem não declarava entrelinha nenhuma — só estes dois
   grupos traziam o utilitário, em valor fixo e sem par responsivo. */

/* Origem `leading-mb-btn-u` (18px em qualquer largura). */
.portal-link--entrelinha-compacta {
    line-height: var(--altura-mobile-botao-link);
}

/* Origem `leading-dt-btn-u` (20px em qualquer largura). */
.portal-link--entrelinha-ampla {
    line-height: var(--altura-desktop-botao-link);
}

/* Link de ação rosa (ACOMPANHAR, VER DETALHES, ENTRE EM CONTATO EUTBEM). */
.portal-link--acao {
    color: var(--cor-secundaria);
    margin-top: 0.5rem;
}

/* Link verde de ação secundária do boleto (ENVIAR POR E-MAIL, DOWNLOAD). */
.portal-link--secundario {
    color: var(--cor-primaria);
    text-align: center;
}

/* Link discreto abaixo do cartão de autenticação ("esqueceu sua senha?"). */
.portal-link--discreto {
    color: var(--cor-cinza-discreto);
    margin-top: 1.5rem;
}

/* Link dentro de uma faixa de aviso ("Clique aqui para regularizar"). A origem
   era `underline font-weight-bold ml-1`; sublinhado e peso seguem nos
   utilitários do markup, então aqui só resta o recuo. */
.portal-link--aviso {
    margin-left: 0.25rem;
}

/* Rodapé de ação da lista ("MOSTRAR MAIS PAGAMENTOS"). */
.portal-mostrar-mais {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: flex-start;
    width: 100%;
    margin-bottom: 6rem;
    padding-top: 2rem;
    padding-left: 1rem;
    padding-right: 1rem;
    text-transform: uppercase;
    cursor: pointer;
    font-size: var(--fonte-mobile-botao-link);
    font-weight: var(--peso-botao);
    color: var(--cor-texto-500);
}

@media (min-width: 1024px) {
    .portal-mostrar-mais {
        margin-bottom: 0;
    }
}

/* ==========================================================================
   10. TRILHA DE NAVEGAÇÃO (breadcrumb) E ÍCONES
   ========================================================================== */

/* Container da trilha, dentro da faixa escura. Transcreve
   `hidden lg:flex container self-center text-white`: largura e max-width seguem
   vindo de `container`, que continua no markup — a classe não repete nem
   substitui esses valores. */
.portal-trilha {
    display: none;
    align-self: center;
    color: var(--cor-branco);
}

@media (min-width: 1024px) {
    .portal-trilha {
        display: flex;
    }
}

/* Link textual de um nível da trilha. A cor sempre foi herdada de .portal-trilha
   e o cursor vinha do utilitário `cursor-pointer`, só em parte dos níveis. */
.portal-trilha-link {
    padding-left: 0.5rem;
    font-size: var(--fonte-desktop-pequeno-2);
    line-height: var(--altura-desktop-pequeno-2);
    letter-spacing: var(--tracking-pequeno);
}

/* Âncora que embrulha só o chevron entre dois níveis. A origem era `pl-2` puro:
   sem display nem alinhamento próprios. */
.portal-trilha-separador {
    padding-left: 0.5rem;
}

/* Ícone colado à esquerda de um texto. */
.portal-icone-esquerda {
    margin-right: 0.5rem;
}

/* Ícone colado à direita de um texto (ajuda, chevron). */
.portal-icone-direita {
    margin-left: 0.5rem;
}

/* Ícone de link externo no canto do cartão de documento. */
.portal-icone-canto {
    margin-top: 1.5rem;
    margin-right: 1.5rem;
}

@media (min-width: 1024px) {
    .portal-icone-canto {
        margin-top: 0.5rem;
        margin-right: 0.5rem;
    }
}

/* Elemento clicável sem aparência própria (logo, cadeado, chevron). */
.portal-clicavel {
    cursor: pointer;
}

/* ==========================================================================
   11. FORMULÁRIOS
   ========================================================================== */

/* <form> em largura total. */
.portal-formulario {
    width: 100%;
}

/* Linha que agrupa campos lado a lado. Os campos alinham pelo centro do eixo
   transversal (dashboard/resgate/provider e refund). */
/* As três origens só tinham `flex flex-wrap` em comum: `flex flex-row
   items-center flex-wrap` (resgate), `flex flex-col flex-wrap lg:flex-row
   w-full` (senha) e `flex flex-wrap w-full` (endereço). Direção, alinhamento e
   largura viram modificador. */
.portal-campos-linha {
    display: flex;
    flex-wrap: wrap;
}

/* Origem `flex-row items-center`, em linha desde o mobile. */
.portal-campos-linha--linha {
    flex-direction: row;
    align-items: center;
}

/* Origem `flex-col lg:flex-row`, empilhada no mobile. */
.portal-campos-linha--empilhada {
    flex-direction: column;
}

@media (min-width: 1024px) {
    .portal-campos-linha--empilhada {
        flex-direction: row;
    }
}

/* Origem com `w-full`. */
.portal-campos-linha--plena {
    width: 100%;
}

/* Coluna de campos do formulário: total no mobile, metade no desktop. */
.portal-campos-coluna {
    display: flex;
    flex-direction: column;
    width: 100%;
    margin-top: 1.5rem;
}

@media (min-width: 1024px) {
    .portal-campos-coluna {
        width: 50%;
    }
}

/* Caixa do campo (input flutuante + label + ícone). Complementa
   .input-container do SCSS de inputs, que segue responsável pela aparência. */
.portal-campo-caixa {
    width: 100%;
}

/* Meia coluna FIXA (o par Agência/Conta é 50/50 inclusive no mobile). */
.portal-campo-metade {
    display: flex;
    flex-direction: column;
    width: 50%;
}

.portal-campo-metade--esquerda {
    padding-right: 0.5rem;
}

.portal-campo-metade--direita {
    padding-left: 0.5rem;
}

/* Meia coluna RESPONSIVA: largura total no mobile, metade no desktop. Só quatro
   das origens traziam `flex flex-col`; nas demais o bloco era estático. */
.portal-campo-metade-responsiva {
    width: 100%;
}

/* Meia coluna que a origem empilhava em flex (`flex flex-col`). */
.portal-campo-metade-responsiva--coluna {
    display: flex;
    flex-direction: column;
}

@media (min-width: 1024px) {
    .portal-campo-metade-responsiva {
        width: 50%;
    }

    .portal-campo-metade-responsiva--esquerda {
        padding-right: 0.5rem;
    }

    .portal-campo-metade-responsiva--direita {
        padding-left: 0.5rem;
    }
}

/* Campo curto de um quarto da largura (Número, Complemento). */
.portal-campo-quarto {
    display: flex;
    flex-direction: column;
    width: 100%;
}

@media (min-width: 1024px) {
    .portal-campo-quarto {
        width: 25%;
    }

    .portal-campo-quarto--esquerda {
        padding-right: 0.5rem;
    }

    .portal-campo-quarto--direita {
        padding-left: 0.5rem;
    }
}

/* Mensagem de erro do campo, oculta até o JS mostrar. */
.portal-campo-erro {
    display: none;
    color: var(--cor-vermelho-alerta);
    font-size: var(--fonte-desktop-pequeno-3);
    line-height: var(--altura-desktop-pequeno-3);
}

.portal-campo-erro--visivel {
    display: block;
}

/* Campo escondido do formulário, preenchido por JS. */
.portal-campo-oculto {
    display: none;
}

/* Input somente-leitura calculado automaticamente.
   Correção deliberada: bg-gray-100 não existia; o campo passa a ficar cinza. */
.portal-campo-calculado {
    background: var(--cor-fundo-100);
    cursor: not-allowed;
}

/* Realce de validação do input, aplicado por JS. */
.portal-campo-valido {
    border-color: var(--cor-primaria);
}

/* Correção deliberada: border-red-500 não existia; o erro nunca teve borda. */
.portal-campo-invalido {
    border-color: var(--cor-vermelho-alerta);
}

/* Seletor de troca de contrato no cabeçalho do cartão. Transcreve `w-1/3`, que
   era a origem das seis telas em qualquer largura — por isso sem breakpoint. */
.portal-seletor-contrato {
    width: 33.333333%;
}

/* Rótulo textual acima do campo (formulário de solicitação por e-mail). */
/* A origem era `text-dt-ms-small-2 font-weight-normal mb-1`; três das quatro
   traziam ainda `mt-4`, que por isso volta ao markup como utilitário em vez de
   entrar na classe. */
.portal-rotulo-campo {
    margin-bottom: 0.25rem;
    font-size: var(--fonte-desktop-pequeno-2);
    font-weight: var(--peso-normal);
}

/* Rótulo flutuante que acompanha o recuo da coluna direita da grade. */
.portal-rotulo-campo--recuado {
    margin-left: 0;
}

@media (min-width: 1024px) {
    .portal-rotulo-campo--recuado {
        margin-left: 0.5rem;
    }
}

/* Nota "*Campo obrigatório" no rodapé do formulário.
   DECISÃO: escala pequeno-2 (forma dominante, 2 das 3 variantes) e alinhamento
   à direita; a terceira forma (flex/justify-end em escala pequeno-3) foi
   descartada. */
.portal-nota-obrigatorio {
    margin-top: 0.5rem;
    align-self: center;
    font-size: var(--fonte-mobile-pequeno-3);
    color: var(--cor-texto-400);
}

@media (min-width: 1024px) {
    .portal-nota-obrigatorio {
        margin-top: 0;
        align-self: flex-end;
    }
}

/* Texto de instrução no topo do formulário. Origem
   `text-mb-ms-small-2 font-weight-ms-small-2 text-typo-gray-900 mb-6`: sem
   largura, sem alinhamento e sem `leading-*`, e o recuo inferior é 1.5rem
   (`mb-6`), não 1.25rem. */
.portal-instrucao-formulario {
    margin-bottom: 1.5rem;
    font-size: var(--fonte-mobile-pequeno-2);
    font-weight: var(--peso-pequeno-2);
    color: var(--cor-texto-900);
}

/* Rodapé de ações do formulário: no mobile empilha com o botão principal em
   cima; no desktop alinha os botões à direita. */
/* Quatro das origens não traziam `flex-wrap` nem `gap`: os dois viraram
   modificador em vez de ficar na base. Pelo mesmo motivo saíram da base o
   `flex-col-reverse lg:flex-row`, o `justify-end` e o `mt-5` — só as origens de
   `--quebravel` os traziam; as de `--linha` eram `flex flex-row w-full`, sem
   nada disso. */
.portal-acoes {
    display: flex;
    width: 100%;
}

/* Quebra de linha no mobile e linha única no desktop
   (`flex-col-reverse lg:flex-row flex-wrap lg:flex-no-wrap justify-end mt-5`). */
.portal-acoes--quebravel {
    flex-direction: column-reverse;
    flex-wrap: wrap;
    justify-content: flex-end;
    margin-top: 1.25rem;
}

@media (min-width: 1024px) {
    .portal-acoes--quebravel {
        flex-direction: row;
        flex-wrap: nowrap;
    }
}

/* Vão de meia unidade entre os botões (`gap-2`). */
.portal-acoes--vao {
    gap: 0.5rem;
}

/* Rodapé de passo do assistente: botão à esquerda, nota à direita. */
.portal-acoes--espalhado {
    flex-direction: column;
    justify-content: space-between;
    margin-top: 2rem;
}

@media (min-width: 1024px) {
    .portal-acoes--espalhado {
        flex-direction: row;
    }
}

/* Rodapé de passo já em linha desde o mobile, sem respiro extra
   (`flex flex-row w-full` e `flex flex-row items-start w-full`). */
.portal-acoes--linha {
    flex-direction: row;
}

/* Rodapé de ações centralizado (painel de confirmação). */
.portal-acoes--centro {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin-top: auto;
    gap: 1rem;
}

@media (min-width: 1024px) {
    .portal-acoes--centro {
        flex-direction: row;
        width: 66.666667%;
        margin-top: 2rem;
    }
}

/* Divisória horizontal entre blocos do formulário. Substitui os
   `border-bottom: 1px` inline e o divisor vazio das telas de autenticação. */
/* A origem era `border-background-gray-300` sozinha: só a cor da borda, sem
   espessura (o preflight deixa border-width em 0). */
.portal-divisor {
    border-color: var(--cor-fundo-300);
}

/* Divisória das telas de autenticação. Transcreve `mt-3 mb-8 w-full` mais o
   `style="border-bottom: 1px solid #EFEFEF"` que estava inline. */
.portal-divisor--auth {
    width: 100%;
    margin-top: 0.75rem;
    margin-bottom: 2rem;
    border-bottom: 1px solid var(--cor-fundo-100);
}

/* Divisória do "Redefinir senha": era um `style` inline com largura total,
   linha inferior e 32px de respiro embaixo, sem margem superior. */
.portal-divisor--auth-simples {
    width: 100%;
    margin-bottom: 32px;
    border-bottom: 1px solid var(--cor-fundo-100);
}

/* Barra de filtro alinhada à direita (ano/mês + botão Filtrar). */
/* Origem `flex-row items-center justify-end` (+ `hidden lg:flex` ou
   `flex lg:hidden`): não havia `gap`. */
.portal-filtro {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
}

/* Select da barra de filtro. Transcreve `mr-2` mais o `style` inline
   `height: auto; padding-top: 8px; padding-bottom: 8px`. */
.portal-filtro-campo {
    margin-right: 0.5rem;
    height: auto;
    padding-top: 8px;
    padding-bottom: 8px;
}

/* Select de um terço da barra (ano e mês). */
.portal-filtro-campo--terco {
    width: 33.333333%;
}

/* ==========================================================================
   12. ANEXOS (upload do resgate)
   ========================================================================== */

/* Área de seleção de arquivo em largura total. */
.portal-anexo {
    width: 100%;
}

/* Gatilho clicável "ESCOLHER ARQUIVO". O sublinhado segue vindo do utilitário
   `underline`, que continua no markup e entrega `text-decoration-line` — a
   origem não entregava o shorthand `text-decoration` nem `line-height`. */
.portal-anexo-gatilho {
    display: flex;
    flex-direction: row;
    align-items: center;
    cursor: pointer;
    font-size: var(--fonte-desktop-pequeno-1);
    font-weight: var(--peso-semi);
    color: var(--cor-texto-900);
}

/* Bloco de progresso do upload, revelado por JS. */
.portal-anexo-progresso {
    display: none;
    flex-direction: column;
    width: 100%;
    margin-top: 1rem;
}

.portal-anexo-progresso--visivel {
    display: flex;
}

/* Nome do arquivo escolhido (substitui o `font-size: 10px` inline). A origem
   era `text-typo-gray-700` + o style inline: sem `leading-*`, logo sem
   `line-height`. */
.portal-anexo-nome {
    font-size: 10px;
    color: var(--cor-texto-700);
}

/* Linha da barra com os ícones de sucesso e de remover à direita. */
.portal-anexo-progresso-linha {
    display: flex;
    flex-direction: row;
    align-items: center;
    width: 100%;
}

/* Barra de progresso do upload. */
.portal-anexo-barra {
    width: 100%;
    margin-top: 0.25rem;
}

/* Ícone de lixeira que remove o arquivo anexado. */
.portal-anexo-remover {
    margin-left: 0.5rem;
    cursor: pointer;
}

/* ==========================================================================
   13. ASSISTENTE DE PASSOS (resgate)
   ========================================================================== */

/* Trilha horizontal de passos (1 Dados / 2 Nota fiscal). */
.portal-passos {
    display: flex;
    flex-direction: row;
    align-items: center;
    margin-top: 3rem;
}

/* Item de passo (bolinha numerada + rótulo). */
.portal-passo-item {
    display: flex;
    flex-direction: row;
    align-items: center;
}

.portal-passo-item--seguinte {
    margin-left: 1.25rem;
}

/* Rótulo do passo, colado na bolinha numerada. */
.portal-passo-rotulo {
    margin-left: 0.5rem;
}

/* Painel de conteúdo de um passo. */
.portal-passo-painel {
    display: flex;
    flex-direction: column;
    width: 100%;
    margin-top: 1.5rem;
}

.portal-passo-painel--oculto {
    display: none;
}

/* ==========================================================================
   14. DICAS (tooltip)
   ========================================================================== */

/* Âncora posicional do ícone de ajuda. */
.portal-ajuda {
    position: relative;
    display: flex;
    flex-direction: row;
    margin-left: 0.5rem;
}

.portal-ajuda--centralizada {
    align-self: center;
}

/* Balão de dica. Absorve .tooltip do common.scss. */
.portal-dica {
    visibility: hidden;
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 212px;
    padding: 22px;
    top: -70px;
    background-color: var(--cor-texto-700);
    border-radius: 3px;
    box-shadow: 0 2px 19px rgba(0, 0, 0, 0.14);
    text-align: center;
    font-size: 10px;
    line-height: 14px;
    letter-spacing: var(--tracking-pequeno);
    font-weight: var(--peso-normal);
    color: var(--cor-branco);
    transition: all 300ms ease-in-out;
}

.portal-dica--visivel {
    visibility: visible;
}

/* ==========================================================================
   15. NAVEGAÇÃO E LAYOUT BASE
   ========================================================================== */

/* <body> das telas do portal. */
.portal-corpo {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    font-family: var(--fonte-portal);
}

/* Barra de navegação branca do topo, só no desktop. */
.portal-barra-navegacao {
    display: none;
    flex-direction: row;
    align-items: center;
    justify-content: center;
}

@media (min-width: 1024px) {
    .portal-barra-navegacao {
        display: flex;
    }
}

/* Faixa escura logo abaixo da navegação (abriga a trilha no desktop e a barra
   de topo no mobile). Complementa dashboard-nav, que segue no markup e é quem
   entrega altura e fundo; o acolchoamento continua em `px-5 py-4`, também no
   markup. */
.portal-faixa-navegacao {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    width: 100%;
    height: 107px;
}

@media (min-width: 1024px) {
    .portal-faixa-navegacao {
        flex-direction: column;
        height: 132px;
    }
}

/* Barra de topo do mobile: voltar à esquerda, título no centro, menu à direita.
   Duas das quatro origens não traziam `w-full`, então a largura é modificador. */
.portal-barra-mobile {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
}

/* Origem com `w-full`. */
.portal-barra-mobile--plena {
    width: 100%;
}

@media (min-width: 1024px) {
    .portal-barra-mobile {
        display: none;
    }
}

/* Nome da rota atual no centro da barra mobile. */
/* `tracking-mb-ms-small-1` e `tracking-mb-ms-small-2` não existiam em CSS
   nenhum: nunca houve tracking. As duas origens divergiam no resto — a da faixa
   escura era `text-mb-ms-small-2 font-weight-ms-small-2 leading-dt-ms-small-2
   text-white` (peso 400, com leading e cor) e a da barra do topo era
   `text-mb-ms-small-1 font-weight-ms-small-1` (peso 500, sem leading e sem
   cor) — então na base só fica o que as duas tinham. */
.portal-titulo-rota {
    text-transform: uppercase;
    font-size: var(--fonte-mobile-pequeno-2);
}

/* Sobre a faixa escura (origem `font-weight-ms-small-2 leading-dt-ms-small-2
   text-white`). */
.portal-titulo-rota--claro {
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-pequeno-2);
    color: var(--cor-branco);
}

/* Sobre fundo branco (origem `font-weight-ms-small-1`, sem cor própria: a do
   texto vinha por herança). */
.portal-titulo-rota--escuro {
    font-weight: var(--peso-pequeno-1);
}

/* Barra de abas fixa no rodapé do mobile. Complementa dashboard-footer, que
   segue no markup e é quem entrega `height` e `bottom`. Sem `z-index` nem
   `box-shadow`: a origem (`dashboard-footer flex lg:hidden flex-row
   justify-between items-center fixed w-full`) não tinha nenhum dos dois. */
.portal-abas-rodape {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    position: fixed;
    bottom: 0;
    width: 100%;
    height: 68px;
}

@media (min-width: 1024px) {
    .portal-abas-rodape {
        display: none;
    }
}

/* Aba do rodapé mobile (ícone em cima, rótulo embaixo). O fundo continua vindo
   do ternário do Blade (`bg-background-gray-100` / `bg-white`), que é onde o
   `<style>` de tema alcança o elemento. */
.portal-abas-rodape-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}

/* Rótulo sob o ícone da aba. A origem trazia `tracking-mb-ms-small-2`, que foi
   purgado do app.css do estado original e portanto não entregava
   `letter-spacing` nenhum. */
.portal-abas-rodape-rotulo {
    margin-top: 0.25rem;
    font-size: var(--fonte-mobile-pequeno-2);
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-pequeno-2);
    color: var(--cor-texto-900);
}

/* ==========================================================================
   16. AUTENTICAÇÃO
   ========================================================================== */

/* Casca da página de autenticação. A origem era `flex flex-col container
   self-center py-5`: largura, max-width e recuo vertical seguem em `container`
   e `py-5`, que continuam no markup. Duas das cinco telas (email e sucesso) não
   traziam `flex-grow`, por isso ele é modificador. */
.portal-pagina-auth {
    display: flex;
    flex-direction: column;
    align-self: center;
}

/* Origem com `flex-grow`. */
.portal-pagina-auth--crescente {
    flex-grow: 1;
}

/* Bloco centralizador entre a casca e o cartão. As cinco origens só tinham
   `flex flex-col items-center` em comum: `justify-*`, `flex-grow` e o `p-3`
   apareciam em subconjuntos diferentes. O acolchoamento volta pro markup como
   `p-3 lg:p-0`, que é como a origem o trazia. */
.portal-auth-miolo {
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* Origem com `justify-center`. */
.portal-auth-miolo--centrado {
    justify-content: center;
}

/* Origem com `justify-start`. */
.portal-auth-miolo--inicio {
    justify-content: flex-start;
}

/* Origem com `flex-grow`. */
.portal-auth-miolo--crescente {
    flex-grow: 1;
}

/* Cartão branco central da autenticação. Complementa .login-card do SCSS.
   O fundo continua vindo do utilitário `bg-white`, que segue no markup.
   Duas das sete origens (login e firstaccess) não traziam `flex-grow`, por isso
   ele é modificador. */
.portal-cartao-auth {
    display: flex;
    flex-direction: column;
    width: 100%;
}

/* Origem com `flex-grow`. */
.portal-cartao-auth--crescente {
    flex-grow: 1;
}

/* Miolo do cartão: empilha logo, título, formulário e botão.
   O conflito `items-center` + `items-start` das views resolve por
   `items-center`: no app.css do estado original `.items-start` fica no offset
   8142 e `.items-center` no 8212, mesma especificidade, vence a de baixo.
   `justify-content` e as margens divergiam entre as origens, então saem da base
   e viram modificador. */
.portal-auth-conteudo {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex-grow: 1;
}

/* Origem com `justify-start`. */
.portal-auth-conteudo--inicio {
    justify-content: flex-start;
}

/* Origem com `justify-center`. */
.portal-auth-conteudo--centrado {
    justify-content: center;
}

/* Origem com `my-16`. */
.portal-auth-conteudo--respiro {
    margin-top: 4rem;
    margin-bottom: 4rem;
}

/* Título principal de tela de autenticação. Transcreve
   `text-mb-ms-h4 lg:text-dt-ms-h4 font-weight-ms-h4`: só tamanho e peso — a
   origem não trazia leading, tracking nem cor. A margem inferior fica FORA da
   classe porque divergia entre as origens (`mb-6`, `mb-2`, inline 12px e
   nenhuma), e segue no markup como utilitário. */
.portal-titulo-auth {
    font-size: var(--fonte-mobile-h4);
    font-weight: var(--peso-h4);
}

@media (min-width: 1024px) {
    .portal-titulo-auth {
        font-size: var(--fonte-desktop-h4);
    }
}

.portal-titulo-auth--centro {
    text-align: center;
}

/* Mensagem de erro devolvida pelo cookie no login. Transcreve o
   `style="color:#FF0000"` que estava inline no parágrafo. */
.portal-titulo-auth--erro {
    color: #FF0000;
}

/* Logo eutbem no topo do estado de confirmação. */
.portal-logo-confirmacao {
    height: 3rem;
}

@media (min-width: 1024px) {
    .portal-logo-confirmacao {
        height: 4rem;
    }
}

/* Casca de duas colunas exclusiva do login. Transcreve
   `flex flex-col flex-grow lg:flex-row self-center`. Largura, max-width,
   acolchoamento e fundo seguem em `container`, `py-5` e `bg-white`, que
   continuam no markup — a origem não tinha recuo lateral nem max-width fixo. */
.portal-login-split {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    align-self: center;
}

@media (min-width: 1024px) {
    .portal-login-split {
        flex-direction: row;
    }
}

/* Coluna de ilustração do login.
   DECISÃO: as duas colunas declaravam lg:w-2/3 (soma 4/3 da linha); a
   ilustração passa a 1/3 e o formulário fica com 2/3. */
.portal-login-ilustracao {
    display: flex;
    flex-direction: column;
    width: 100%;
    background-position: center;
}

@media (min-width: 1024px) {
    .portal-login-ilustracao {
        width: 33.333333%;
        min-height: 100%;
    }
}

/* Coluna do formulário no login. */
.portal-login-formulario {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    padding-left: 1rem;
    padding-right: 1rem;
}

@media (min-width: 1024px) {
    .portal-login-formulario {
        width: 66.666667%;
        padding-left: 6rem;
        padding-right: 0;
    }
}

/* Selo "Você está em um ambiente seguro" no topo do login. A origem era
   `lg:flex text-mb-small-1 text-gray-new ml-2 font-weight-bold`: o `flex` só
   valia a partir de 1024px, não havia `flex-row` nem `items-center`, e
   `text-mb-small-1` era inerte (o token é `mb-ms-small-1`) — logo nem
   `font-size` nem `line-height`. */
.portal-selo-ambiente-seguro {
    margin-left: 0.5rem;
    font-weight: var(--peso-negrito);
    color: var(--cor-cinza-discreto);
}

@media (min-width: 1024px) {
    .portal-selo-ambiente-seguro {
        display: flex;
    }
}

/* ==========================================================================
   17. ABAS (perfil)
   ========================================================================== */

/* Coluna lateral com a lista de abas, só no desktop. */
.portal-abas-lista {
    display: none;
    flex-direction: column;
    width: 33.333333%;
}

@media (min-width: 1024px) {
    .portal-abas-lista {
        display: flex;
    }
}

/* Item de aba do menu lateral. Complementa .button-selector do SCSS. */
.portal-aba {
    display: flex;
}

/* Cabeçalho-acordeão da aba na versão mobile. */
.portal-aba-mobile {
    display: flex;
    margin-bottom: 2rem;
}

@media (min-width: 1024px) {
    .portal-aba-mobile {
        display: none;
    }
}

/* Painel de conteúdo de uma aba. O estado agora é explícito, em vez de depender
   de `hidden` e `flex` colidindo no mesmo atributo. */
.portal-aba-painel {
    display: none;
    flex-wrap: wrap;
    width: 100%;
    margin-bottom: 1rem;
}

.portal-aba-painel--ativo {
    display: flex;
}

@media (min-width: 1024px) {
    .portal-aba-painel {
        width: 50%;
        margin-bottom: 0;
    }
}

/* Corpo do cartão que hospeda a lista de abas e o painel. */
.portal-abas-corpo {
    display: flex;
    flex-direction: column;
    width: 100%;
    margin-top: 1rem;
}

@media (min-width: 1024px) {
    .portal-abas-corpo {
        flex-direction: row;
        margin-top: 2.5rem;
    }
}

/* ==========================================================================
   18. LANCE
   ========================================================================== */

/* Painel verde do bloco de lance no mobile. O fundo continua vindo de
   `bg-green-50`, que segue no markup e é gancho do `<style>` de tema. */
.portal-painel-lance {
    display: flex;
    flex-direction: column;
    margin-top: 1.25rem;
    padding: 1.25rem;
}

/* Chamada em negrito ao lado/acima da barra de progresso. A origem do mobile
   (`mt-2 font-weight-bold text-mb-ms-small-2 …`) não trazia `mb-2` nem
   `text-left`: os dois viraram modificador. */
.portal-lance-chamada {
    font-size: var(--fonte-desktop-pequeno-2);
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-negrito);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

/* Origem com `mb-2 text-left` (chamada do desktop). */
.portal-lance-chamada--bloco {
    margin-bottom: 0.5rem;
    text-align: left;
}

/* Prazo do lance abaixo da barra de progresso.
   DECISÃO: unificado em cinza 700 (a divergência mobile/desktop 500x700 não
   tinha motivo aparente). */
.portal-lance-prazo {
    margin-top: 0.25rem;
    text-align: left;
    font-size: var(--fonte-desktop-pequeno-3);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-negrito);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-700);
}

/* Linha que coloca lado a lado o bloco de progresso e o botão. */
.portal-lance-acoes {
    display: flex;
    flex-direction: row;
    align-items: center;
    margin-top: 0.5rem;
}

/* Barra de progresso. Absorve .progress-bar do dashboard.scss. */
.portal-barra-progresso {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    width: 100%;
    height: 9px;
    padding: 1px;
    border: 1px solid var(--cor-borda-300);
    border-radius: 30px;
}

.portal-barra-progresso-preenchimento {
    height: 5px;
    border-radius: 40px;
    background: var(--cor-primaria);
}

/* Faixa azul de destaque do percentual do lance (substitui o bloco inteiro de
   `style` inline: cor #3D58D8, raio 8px, padding 16/20 e transição). */
.portal-destaque-percentual {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    padding: 16px 20px;
    border-radius: var(--raio-bloco);
    background-color: #3D58D8;
    transition: background-color 0.3s ease;
}

/* Estado acima de 100%. Correção deliberada: o par laranja
   (#FED7AA + text-orange-900) não existe na paleta; passa a usar a escala
   amarela de atenção, com texto legível. */
.portal-destaque-percentual--excedido {
    background: var(--cor-amarelo-100);
}

/* A origem era `text-dt-ms-h6 font-weight-600 text-white`: sem `leading-*`. */
.portal-destaque-percentual-texto {
    font-size: var(--fonte-desktop-h6);
    font-weight: var(--peso-semi);
    color: var(--cor-branco);
}

.portal-destaque-percentual--excedido .portal-destaque-percentual-texto {
    color: var(--cor-amarelo-900);
}

/* Faixa de atalhos de preenchimento abaixo do input. */
/* Origem `flex flex-row mt-2`. Duas das três traziam ainda `flex-wrap`, que por
   isso é modificador. */
.portal-atalhos {
    display: flex;
    flex-direction: row;
    margin-top: 0.5rem;
}

/* Origem com `flex-wrap`. */
.portal-atalhos--quebravel {
    flex-wrap: wrap;
}

/* ==========================================================================
   19. HISTÓRICO DE LANCES
   ========================================================================== */

/* Bloco de uma assembleia com suas ofertas. Transcreve `py-4`. A cor da linha
   vem de `border-background-gray-100` e a espessura do `style` inline
   (`border-bottom-width: 1px`), ambos no markup — por isso aqui não entra
   `border-bottom`. */
.portal-historico-grupo {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

/* Cabeçalho do grupo: data à esquerda, contagem à direita. */
.portal-historico-grupo-cabecalho {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.5rem;
}

/* Item de oferta: empilha no mobile, duas colunas no desktop. */
.portal-historico-item {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
}

@media (min-width: 1024px) {
    .portal-historico-item {
        flex-direction: row;
    }
}

/* Coluna direita do item (valor e percentual). */
.portal-historico-item-valores {
    display: flex;
    flex-direction: column;
    margin-top: 0.5rem;
}

@media (min-width: 1024px) {
    .portal-historico-item-valores {
        align-items: flex-end;
        margin-top: 0;
    }
}

/* ==========================================================================
   20. COBRANÇA E BOLETO
   ========================================================================== */

/* Eixo horizontal de uma cobrança: descrição à esquerda, valor/status à direita. */
.portal-cobranca-linha {
    display: flex;
    flex-direction: row;
    width: 100%;
}

/* Linha do histórico de pagamentos. Absorve .row-payments. */
/* O acolchoamento de baixo e a borda seguem vindo de .row-payments, que continua
   no markup; repeti-los aqui declarava propriedade que a origem não trazia. */
.portal-cobranca-historico {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    width: 100%;
    padding-top: 2rem;
    padding-left: 1rem;
    padding-right: 1rem;
}

/* Coluna esquerda da cobrança (descrição + vencimento).
   DECISÃO: uma largura só (2/3 no mobile, 1/2 no desktop); a variante w-3/5 do
   histórico foi descartada. */
.portal-cobranca-descricao {
    display: flex;
    flex-direction: column;
    width: 66.666667%;
}

@media (min-width: 1024px) {
    .portal-cobranca-descricao {
        width: 50%;
    }
}

/* Coluna direita da cobrança (valor + etiqueta + ação).
   DECISÃO: a margem negativa `-mb-8` do histórico foi descartada. */
.portal-cobranca-acoes {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    width: 33.333333%;
}

@media (min-width: 1024px) {
    .portal-cobranca-acoes {
        width: 50%;
    }
}

/* Envoltório da etiqueta de status na linha do histórico. */
.portal-cobranca-status {
    display: flex;
    justify-content: flex-end;
    width: 100%;
    margin-top: 0.25rem;
    order: 99;
}

@media (min-width: 1024px) {
    .portal-cobranca-status {
        width: auto;
        order: 0;
    }
}

/* Linha secundária cinza: "Data de vencimento: 10/09/2026". */
.portal-cobranca-vencimento {
    display: inline-flex;
    align-items: center;
    width: 60%;
    padding-right: 1rem;
    font-size: var(--fonte-mobile-pequeno-2);
    line-height: var(--altura-desktop-pequeno-3);
    font-weight: var(--peso-pequeno-3);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-500);
}

@media (min-width: 1024px) {
    .portal-cobranca-vencimento {
        width: auto;
        font-size: var(--fonte-desktop-corpo-1);
    }
}

/* Valor monetário da cobrança, alinhado à direita. */
.portal-cobranca-valor {
    margin-top: 0.25rem;
    margin-bottom: 0.25rem;
    text-align: right;
    font-size: var(--fonte-mobile-corpo-2);
    line-height: var(--altura-desktop-corpo-2);
    font-weight: var(--peso-corpo-2);
    letter-spacing: var(--tracking-corpo);
    color: var(--cor-texto-900);
}

@media (min-width: 1024px) {
    .portal-cobranca-valor {
        margin-top: 0;
        margin-bottom: 0;
        font-size: var(--fonte-desktop-corpo-2);
    }
}

/* Bloco de meta-informações da cobrança (número da fatura, data, status). */
.portal-cobranca-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-top: 0.75rem;
    font-size: var(--fonte-mobile-pequeno-3);
    line-height: var(--altura-desktop-pequeno-2);
    font-weight: var(--peso-pequeno-2);
    letter-spacing: var(--tracking-pequeno);
}

@media (min-width: 1024px) {
    .portal-cobranca-meta {
        flex-direction: row;
        align-items: center;
        margin-top: 1.5rem;
        font-size: var(--fonte-desktop-pequeno-2);
    }
}

.portal-cobranca-meta--fim {
    align-items: flex-end;
}

/* Item individual dentro do bloco de meta-informações. A origem era só `mr-3`;
   quem trazia `flex` ganha o modificador, e quem trazia `mr-1` usa o curto. */
.portal-cobranca-meta-item {
    margin-right: 0.75rem;
}

.portal-cobranca-meta-item--curto {
    margin-right: 0.25rem;
}

.portal-cobranca-meta-item--flex {
    display: flex;
}

/* Valor total do boleto em destaque rosa. Origem
   `text-mb-ms-h4 lg:text-dt-ms-h4 font-weight-ms-h4 text-pink-400`: sem
   `leading-*`. */
.portal-valor-destaque {
    font-size: var(--fonte-mobile-h4);
    font-weight: var(--peso-h4);
    color: var(--cor-secundaria);
}

@media (min-width: 1024px) {
    .portal-valor-destaque {
        font-size: var(--fonte-desktop-h4);
    }
}

/* Área centralizada do código de barras (âncora do balão "Código copiado"). */
.portal-boleto-codigo {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
}

/* Linha digitável clicável. Complementa .bank-slip-number do SCSS. */
.portal-boleto-linha-digitavel {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin-top: 0.5rem;
    cursor: pointer;
}

/* Rodapé de ações do boleto (o col-reverse põe o botão primário no topo da
   pilha no mobile). */
/* Origem `flex flex-col-reverse lg:flex-row items-center justify-end`: sem
   `gap`. */
.portal-boleto-acoes {
    display: flex;
    flex-direction: column-reverse;
    align-items: center;
    justify-content: flex-end;
}

@media (min-width: 1024px) {
    .portal-boleto-acoes {
        flex-direction: row;
    }
}

/* ==========================================================================
   21. GRADES, OPÇÕES E ATALHOS DE CONTRATO
   ========================================================================== */

/* Grade de cartões: empilha no mobile, lado a lado no desktop. Ocupa a largura
   toda do contêiner (dashboard/lances/form e index, dashboard/details/index). */
/* Nenhuma das origens declarava `gap`: o vão entre os cartões vinha só das
   margens de cada cartão. */
.portal-grade {
    display: flex;
    flex-direction: column;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
}

@media (min-width: 1024px) {
    .portal-grade {
        flex-direction: row;
        padding-left: 0;
        padding-right: 0;
    }
}

/* Grade em largura total (transcreve `w-full`). */
.portal-grade--plena {
    width: 100%;
}

/* Respiro superior `mt-8`. */
.portal-grade--espacada {
    margin-top: 2rem;
}

/* Respiro superior `mt-16`. */
.portal-grade--afastada {
    margin-top: 4rem;
}

/* Bloco centralizado (estado vazio, tela de escolha, confirmação). */
/* Transcreve `flex flex-col w-full items-center justify-center`. As margens
   ficam fora: em lances/index a origem trazia `margin-bottom: 150px` inline e
   nenhum recuo superior; em resgate/index trazia `mt-16` e nenhum inferior. */
.portal-bloco-centralizado {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
}

/* Cartão de opção de resgate (ícone à esquerda, textos e botão à direita). */
.portal-opcao {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    width: 100%;
}

@media (min-width: 1024px) {
    .portal-opcao {
        width: 50%;
    }
}

/* Primeiro cartão da dupla (`mr-0 lg:mr-4`). */
.portal-opcao--primeira {
    margin-right: 0;
}

/* Segundo cartão da dupla (`mt-8 lg:mt-0 ml-0 lg:ml-4`). */
.portal-opcao--segunda {
    margin-top: 2rem;
    margin-left: 0;
}

@media (min-width: 1024px) {
    .portal-opcao--primeira {
        margin-right: 1rem;
    }

    .portal-opcao--segunda {
        margin-top: 0;
        margin-left: 1rem;
    }
}

/* Corpo textual do cartão de opção, ao lado do ícone. */
.portal-opcao-corpo {
    display: flex;
    flex-direction: column;
    margin-left: 1.5rem;
}

/* Container geral dos cartões. As duas origens só tinham `flex flex-grow` em
   comum: a do desktop era `w-full items-center justify-start flex-col` e a do
   mobile era só `flex-row`. O recuo negativo do topo continua vindo de
   `contracts-container`, que só o desktop carregava. */
.portal-cartoes {
    display: flex;
    flex-grow: 1;
}

/* Origem `flex-col w-full items-center justify-start` (desktop). */
.portal-cartoes--coluna {
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    width: 100%;
}

/* Origem `flex-row` (mobile). */
.portal-cartoes--linha {
    flex-direction: row;
}

/* Trilho de rolagem horizontal que enfileira os cartões no mobile. Transcreve
   `flex flex-row min-w-full overflow-x-scroll`. Sem `padding-right`: o
   espaçador invisível `ml-5 h-1 w-1 invisible` segue no fim da lista, e o
   `overflow-x` é `scroll`, não `auto`. */
.portal-cartoes-trilho {
    display: flex;
    flex-direction: row;
    min-width: 100%;
    overflow-x: scroll;
}

/* Item clicável da lista lateral de contratos. Absorve normal-card e
   small-card. */
.portal-contrato-atalho {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    min-width: 280px;
    max-width: 280px;
    margin-left: 32px;
    margin-bottom: 1.25rem;
    background: var(--cor-branco);
    border-radius: var(--raio-cartao);
    cursor: pointer;
}

.portal-contrato-atalho--ativo::before {
    display: block;
    position: absolute;
    content: '';
    left: 0;
    height: 100%;
    width: 5px;
    background: var(--cor-primaria);
    border-top-left-radius: var(--raio-caixa);
    border-bottom-left-radius: var(--raio-caixa);
}

.portal-contrato-atalho--cancelado::before {
    background: var(--cor-borda-300);
}

.portal-contrato-atalho--contemplado::before {
    background: var(--cor-secundaria);
}

/* Área interna com padding do atalho de contrato. */
.portal-contrato-atalho-corpo {
    display: flex;
    width: 100%;
    padding: 16px;
}

/* Coluna de texto do atalho, à direita do ícone. */
.portal-contrato-atalho-texto {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    margin-left: 1rem;
}

/* Título "Contrato Nº X" dentro do atalho. */
.portal-contrato-atalho-titulo {
    width: 100%;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--cor-borda-100);
    text-align: left;
    font-size: var(--fonte-desktop-pequeno-4);
    line-height: var(--altura-desktop-pequeno-4);
    font-weight: var(--peso-pequeno-4);
    letter-spacing: var(--tracking-pequeno);
    color: var(--cor-texto-900);
}

/* Marcação "Cancelado" ao lado do número do contrato. */
.portal-marca-cancelado {
    color: var(--cor-vermelho-alerta);
}

/* ==========================================================================
   22. EXPANSÃO
   ========================================================================== */

/* Botão quadrado com chevron que expande/recolhe o cartão de assembleia.
   Substitui o `width/height: 33px` e o raio inline. */
.portal-expandir {
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 33px;
    height: 33px;
    border-color: var(--cor-borda-200);
    border-radius: var(--raio-etiqueta);
    cursor: pointer;
}

@media (min-width: 1024px) {
    .portal-expandir {
        display: flex;
    }
}

.portal-expandir--aberto img {
    transform: rotate(180deg);
    transition: all 100ms ease-in-out;
}

/* Painel expansível com os resultados da assembleia. */
.portal-painel-expansivel {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding-top: 2rem;
    padding-bottom: 2rem;
    padding-left: 1.5rem;
    padding-right: 1.5rem;
    background-color: var(--cor-texto-50);
}

@media (min-width: 1024px) {
    .portal-painel-expansivel {
        display: none;
    }
}

/* ==========================================================================
   23. LAYOUT GENÉRICO E VISIBILIDADE
   Escape valve: os 8 agentes de conversão usam ESTAS classes quando o bloco é
   puramente estrutural e não tem papel próprio. Nunca inventar nome novo.
   ========================================================================== */

/* Linha horizontal. Sete origens não traziam `items-center`, então o
   alinhamento no eixo cruzado é modificador, não default do componente. */
.portal-linha {
    display: flex;
    flex-direction: row;
}

/* Conteúdo centrado no eixo cruzado (`items-center`). */
.portal-linha--centrada {
    align-items: center;
}

/* Só `justify-between`: duas das quatro origens não traziam `w-full`, e a
   largura já tem modificador próprio (`--plena`). */
.portal-linha--entre {
    justify-content: space-between;
}

.portal-linha--fim {
    justify-content: flex-end;
}

.portal-linha--plena {
    width: 100%;
}

/* Coluna vertical. */
.portal-coluna {
    display: flex;
    flex-direction: column;
}

/* Só `items-center`: três das quatro origens não traziam `justify-center`. */
.portal-coluna--centrada {
    align-items: center;
}

/* Origem com `justify-center` (centra no eixo principal da coluna). */
.portal-coluna--centrada-no-eixo {
    justify-content: center;
}

.portal-coluna--plena {
    width: 100%;
}

.portal-coluna--crescente {
    flex-grow: 1;
}


/* Meia coluna genérica no desktop. */
.portal-metade {
    width: 100%;
}

@media (min-width: 1024px) {
    .portal-metade {
        width: 50%;
    }
}

/* Visível só no desktop. */
.portal-so-desktop {
    display: none;
}

@media (min-width: 1024px) {
    .portal-so-desktop {
        display: flex;
    }
}

/* Visível só no mobile. */
.portal-so-mobile {
    display: flex;
}

@media (min-width: 1024px) {
    .portal-so-mobile {
        display: none;
    }
}

/* Oculto até o JS revelar (substitui o utilitário `hidden`, que o jQuery
   alterna em várias telas). */
.portal-oculto {
    display: none;
}
