[hidden]:not([hidden="until-found"]) { display: none !important; }

/* =============================================================================
   Fundação — F04
   =============================================================================

   O que esta camada é: o vocabulário visual do produto. Cor semântica,
   tipografia, espaço, raio, elevação, largura, camada, movimento e foco.

   O que esta camada NÃO é: um redesenho. Nada aqui muda a aparência de uma
   página sozinho. Os tokens passam a existir; as páginas migram uma a uma,
   com comparação visual, conforme o F04 exige.

   Por que ela precisou existir — medido em 25/08/2026, em 12.185 linhas:

   - 21 breakpoints distintos, incluindo 760, 768, 780 e 781 — quatro quebras
     dentro de 21px, que ninguém consegue manter de propósito;
   - 8+ tamanhos de fonte espremidos entre 0.76rem e 0.9rem, sem escala;
   - raio, sombra e duração escolhidos caso a caso (0.2s, 0.18s, 220ms, 160ms);
   - z-index indo de 1 a 9999 sem camadas nomeadas.

   A cor já era o pedaço saudável: `light.css` e `dark.css` já traziam ~40
   tokens semânticos nos dois temas. Esta fundação não os reescreve — ela
   completa o que faltava em volta.

   Regra de entrada: cor ou breakpoint novo não entra fora daqui sem
   justificativa registrada. O teste `test_fundacao_visual.py` cobra isso.

   Ordem de carga: este arquivo vem ANTES de global.css, para que qualquer
   regra de produto possa sobrescrever a fundação sem disputa de
   especificidade — a fundação declara tokens, não impõe aparência.
   ========================================================================== */

:root {
    /* ---------------------------------------------------------------------
       Espaço — uma escala, não uma opinião por elemento.
       Os valores em uso hoje se aglomeravam em 0.2/0.35/0.45/0.55/0.6rem;
       a escala abaixo os absorve sem que ninguém precise decidir de novo.
       --------------------------------------------------------------------- */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4rem;

    /* ---------------------------------------------------------------------
       Tipografia
       `--text-base` é 0.95rem porque é o que `.btn` e o corpo já usam:
       a escala foi extraída do produto, não trazida de fora.
       --------------------------------------------------------------------- */
    --font-body: 'Segoe UI', system-ui, -apple-system, 'Helvetica Neue', sans-serif;
    --font-display: var(--font-body);
    --font-mono: ui-monospace, 'Cascadia Code', 'Consolas', monospace;

    --text-xs: 0.75rem;
    --text-sm: 0.82rem;
    --text-base: 0.95rem;
    --text-md: 1.05rem;
    --text-lg: 1.25rem;
    --text-xl: 1.6rem;
    --text-2xl: 2rem;

    --weight-regular: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;

    --leading-tight: 1.2;
    --leading-normal: 1.5;
    --leading-relaxed: 1.7;

    --tracking-label: 0.06em;

    /* ---------------------------------------------------------------------
       Raio
       `999px` (pílula) e `50%` (círculo) ganham nome porque são intenção,
       não medida: eles não escalam junto com o resto.
       --------------------------------------------------------------------- */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;
    --radius-pill: 999px;
    --radius-circle: 50%;

    /* ---------------------------------------------------------------------
       Elevação
       Três degraus, derivados de UMA cor por tema (`--shadow-color`, definida
       em light.css e dark.css). Sombra clara sobre fundo claro e sombra
       escura sobre fundo escuro são problemas diferentes; um token só por
       tema resolve os três níveis sem duplicar a paleta aqui.
       O fallback mantém a página apresentável se o tema não carregar.
       --------------------------------------------------------------------- */
    --elevation-0: none;
    --elevation-1: 0 2px 8px var(--shadow-color);
    --elevation-2: 0 10px 24px var(--shadow-color);
    --elevation-3: 0 18px 42px var(--shadow-color);

    /* ---------------------------------------------------------------------
       Largura
       `--width-prose` em `ch` porque a medida de leitura é contada em
       caracteres, não em pixels — ela acompanha o tamanho da fonte.
       --------------------------------------------------------------------- */
    --width-prose: 68ch;
    --width-narrow: 34rem;
    /* 03/09/2026 — o degrau que faltava, e por isso cada casca inventava o
       seu. Formulário não é lista: uma coluna de campos com a largura de
       `--width-content` vira viagem de olho entre o rótulo e o campo, e uma
       com `--width-narrow` espreme os pares lado a lado. */
    --width-form: 58rem;
    --width-content: 72rem;
    --width-wide: 90rem;

    /* ---------------------------------------------------------------------
       Camadas
       O produto tinha z-index de 1 a 9999 sem nome. Estes são os planos que
       realmente existem; qualquer número solto acima de 10 é dívida.
       --------------------------------------------------------------------- */
    --layer-base: 0;
    --layer-raised: 10;
    --layer-sticky: 100;
    --layer-header: 200;
    --layer-overlay: 900;
    --layer-dialog: 1000;
    --layer-toast: 1100;

    /* ---------------------------------------------------------------------
       Movimento
       Três durações. `--motion-*` é zerado sob `prefers-reduced-motion`
       no fim deste arquivo, então quem usa o token herda o respeito à
       preferência sem escrever a media query de novo.
       --------------------------------------------------------------------- */
    --motion-fast: 120ms;
    --motion-base: 180ms;
    --motion-slow: 280ms;
    --ease-standard: cubic-bezier(0.2, 0, 0.2, 1);
    --ease-out: cubic-bezier(0, 0, 0.2, 1);

    /* ---------------------------------------------------------------------
       Foco
       `--focus-ring` já existia nos dois temas (é uma cor). O que faltava era
       a espessura e o afastamento — sem eles, cada componente inventava o
       seu, e o anel sumia sobre fundos claros.
       --------------------------------------------------------------------- */
    --focus-ring-width: 3px;
    --focus-ring-offset: 2px;

    /* ---------------------------------------------------------------------
       Opacidade de estado
       --------------------------------------------------------------------- */
    --opacity-disabled: 0.55;
    --opacity-muted: 0.7;
}

/* =============================================================================
   Esquema de cor nativo — a barra de rolagem também é interface
   =============================================================================
   Sem `color-scheme`, o navegador presume claro e desenha o que ele controla —
   barra de rolagem, `<select>`, campos de data, menu de autopreenchimento —
   com a paleta do sistema. No Windows isso é uma barra branca com setas
   cinzas colada num produto quase preto: a única faixa da tela que nenhuma
   regra de produto alcança.

   `::-webkit-scrollbar` não resolveria: não existe no Firefox, e troca a barra
   nativa (que segue o comportamento e a acessibilidade do sistema) por uma
   caixa pintada à mão. `color-scheme` pede ao navegador que desenhe a dele no
   tom certo, e é honrado pelos dois motores.

   Os dois temas precisam declarar o seu. O script no `<head>` de
   `base_core.html` carimba `data-theme="dark"`/`"light"` no `<html>` antes do
   primeiro paint; sem o par abaixo, o tema claro herdaria a barra escura.
   ========================================================================== */

:root {
    /* Escuro é o padrão do produto — é o que o script do `<head>` assume
       quando não há cookie de tema, e o que vale se o JS não rodar. */
    color-scheme: dark;

    /* A barra larga do Windows vem com setas nas pontas, que não existem em
       mais nenhum controle deste produto. `thin` tira as setas sem trocar a
       barra nativa por uma imitação. */
    scrollbar-width: thin;

    /* Herdado de propósito: assim todo contêiner rolável do produto usa o
       mesmo par, em vez de cada um cair no cinza do sistema. Quem quer a
       barra escondida continua declarando `scrollbar-width: none`. */
    scrollbar-color: var(--muted-color) var(--secondary-color);
}

:root[data-theme="light"] {
    color-scheme: light;
}

/* =============================================================================
   Breakpoints
   =============================================================================
   Custom properties não funcionam dentro de `@media` — não existe token de
   breakpoint em CSS puro. Então a escala canônica vive aqui como documentação
   executável: `test_fundacao_visual.py` lê estes comentários como a lista de
   valores permitidos e falha quando um valor novo aparece fora dela.

     --bp-sm   640px   telefone → tablet
     --bp-md   768px   tablet
     --bp-lg   1024px  desktop
     --bp-xl   1280px  tela larga

   Os 21 breakpoints legados continuam funcionando. Eles migram por página,
   com comparação visual — nunca por substituição mecânica global.
   ========================================================================== */

/* =============================================================================
   Foco visível — o piso, não o teto
   =============================================================================
   `:focus-visible` aparece 23 vezes em global.css, cada uma com sua própria
   espessura e cor. A regra abaixo usa `:where()` (especificidade zero) e
   carrega antes: ela NÃO substitui aquelas 23 — cobre todo o resto, que até
   agora dependia do anel padrão do navegador ou de nada.

   As 23 migram para o token uma a uma, com comparação visual. Enquanto isso,
   nenhum controle fica sem foco visível.
   ========================================================================== */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: var(--focus-ring-width) solid var(--focus-ring);
    outline-offset: var(--focus-ring-offset);
}

/* =============================================================================
   Estados que o produto produz mas não desenhava
   =============================================================================
   `nf_submit_once.js` marca `aria-busy` no formulário e desabilita o botão a
   cada envio. Até aqui o CSS não estilizava nenhum dos dois: o botão morria
   mas continuava com aparência de clicável e cursor de mão — e a pessoa,
   corretamente, clicava de novo.
   ========================================================================== */

/* `aria-disabled` cobre o link e o controle que precisa continuar focável —
   `disabled` de verdade tira do foco, e às vezes isso é justamente o errado. */
:where(button, [role="button"], input[type="submit"], input[type="button"]):disabled,
[aria-disabled="true"]:where(button, a, [role="button"]) {
    cursor: not-allowed;
    opacity: var(--opacity-disabled);
    box-shadow: var(--elevation-0);
}

/* O cursor de espera vale para a área toda: o alvo já não responde. */
form[aria-busy="true"] {
    cursor: progress;
}

form[aria-busy="true"] :where(button, input[type="submit"]):disabled {
    cursor: progress;
}

/* Indicador de carregamento. Fica no `::after` para não apagar o rótulo:
   trocar o texto do botão por "Enviando…" perde a informação do que foi
   enviado, e a leitura de tela anuncia a troca como conteúdo novo. */
form[aria-busy="true"] :where(button, input[type="submit"]):disabled::after {
    content: "";
    display: inline-block;
    width: 0.8em;
    height: 0.8em;
    margin-left: var(--space-2);
    vertical-align: -0.05em;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: var(--radius-circle);
    animation: nf-spin var(--motion-slow) linear infinite;
}

@keyframes nf-spin {
    to { transform: rotate(360deg); }
}

/* =============================================================================
   Movimento reduzido
   =============================================================================
   Zerar os tokens de duração faz a preferência valer para tudo que os usa,
   sem que cada componente precise repetir a media query.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    :root {
        --motion-fast: 0ms;
        --motion-base: 0ms;
        --motion-slow: 0ms;
    }

    form[aria-busy="true"] :where(button, input[type="submit"]):disabled::after {
        animation: none;
        /* Sem giro, o anel vira um ponto parado — que não comunica nada.
           Um traço cheio ao menos marca que há algo em andamento. */
        border-top-color: currentColor;
        opacity: var(--opacity-muted);
    }
}
