/* Scrollbar: .login-scrollbar-wrap/.login-scrollbar-thumb definidos em scrollbar.css.
   body { padding-right } aqui reserva o espaço para a track (contexto exclusivo desta página). */
body {
  padding-right: 10px;
  box-sizing: border-box;
}

/* A página de login não tem header — eliminar a margem-top que styles.css aplica via --main-header-height */
#main-container {
  margin-top: 0;
  background-color: transparent;
}

/* container do login */
.login-container {
  position: relative; /* confina .login-overlay ao conteúdo (1922px) — evita que a bg image cubra a track da scrollbar (10px) */
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  width: 100%;
}

.login-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  /* O que se vê antes de o vídeo ter o 1.º frame — e o que fica para sempre em
     quem não recebe fundo nenhum (ligação fraca). Era este o buraco que o poster
     tapava a meio MB por visita; uma cor custa zero bytes. O tom é o do véu já
     aplicado por ::after sobre a fotografia, para a transição não dar solavanco. */
  background-color: #0d0d0f;
}

/* A <picture> e o <video> vivem os dois no overlay e têm de se sobrepor: sem isto
   empilham-se em fluxo normal (ambos com height: 100%) e o segundo sai para fora
   do ecrã. A ordem do DOM é imagem → vídeo, que é a ordem de pintura desejada — a
   imagem é o que se vê enquanto o vídeo não tem o 1.º frame. */
.login-overlay > .bg-image {
    position: absolute;
    inset: 0;
}

/* O vídeo entra por cima do poster com um fade curto. Sem isto a troca era
   instantânea — o ecrã passava de uma fotografia desfocada de 380 bytes para o
   vídeo nítido num único frame, e o estalo dava-se mesmo por ele.
   Nasce a zero e é o login.js que lhe põe .is-visible no `loadeddata`: começar
   visível seria mostrar o poster do <video> por cima do poster da <picture>, os
   dois iguais, e o fade não teria de onde partir.
   Se o JS não correr, o <video> nunca recebe fontes nem desenha nada — ficar
   invisível é o comportamento certo, com a <picture> por baixo a fazer o fundo. */
.login-overlay > video.bg-image {
    opacity: 0;
    transition: opacity 0.4s ease-in;
}

.login-overlay > video.bg-image.is-visible {
    opacity: 1;
}

/* Véu escuro sobre a imagem/vídeo de fundo — mesmo valor de .hero-overlay:after
   (hero.css, já carregado nesta página) para o login ler igual aos heros do site. */
.login-overlay::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
}

.login-form-container {
    width: 100%;
}

.login-form-container.center {
    display: flex;
    justify-content: center;
}

.login-panel {
    display: flex;
    align-items: center;
    justify-content: center;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    text-align: center;
}

/* ── Logo ────────────────────────────────────────────────────────────────────
   Âncora de identidade do cartão. 120px é deliberadamente contido: a 150px o
   logo e o título "Iniciar Sessão" ficavam com o mesmo peso visual e competiam
   um com o outro — assim o logo identifica e o título continua a ser quem diz
   o que se faz aqui.
   O SVG vem inline da view e traz fill="currentColor": segue o token do cartão
   em vez de trazer uma cor fixa. */
.login-logo {
    display: flex;
    justify-content: center;
    /* O cartão é um flex column, que por omissão estica os filhos à largura toda —
       e o halo de foco deste <a> aparecia à volta do cartão inteiro em vez do logo.
       align-self encolhe-o ao conteúdo; o margin-inline volta a centrá-lo. */
    align-self: center;
    padding: var(--space-1);
    /* Sem margem em baixo. O que separa o wordmark do nome da aplicação já é o
       padding acima (4px, que existe para o halo de foco caber) mais o meio-espaço
       do line-height do próprio nome (2,4px) — cerca de 6px óticos, meia altura da
       letra. É a distância a que um subtítulo de identidade se lê como parte da
       mesma marca e não como a linha seguinte.
       Chegou a ser 24px (com o título pelo meio) e depois 8px, o que dava 14,8px
       óticos para um texto de 12px: os dois liam-se como dois blocos. */
    margin: 0;
    color: var(--color-text);
    text-decoration: none;
    border-radius: var(--radius-sm);
}

/* O logo é a única coisa clicável do cabeçalho — sem indicação de foco, quem
   navega por teclado passa por ele às cegas. Mesmo halo do resto do cartão. */
.login-logo:focus-visible {
    outline: none;
    box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

.login-logo svg {
    width: 120px;
    height: auto;
    display: block;
}

.login-title {
    margin: 0;
    padding: 0;
    font-size: var(--text-2xl); /* 18px: abaixo dos 20px de antes — o logo por cima passou a ser a âncora e o título deixou de precisar de competir */
    font-weight: var(--weight-bold);
    line-height: var(--line-tight);
    color: var(--color-text); /* o cartão é data-theme="light" — segue o token */
}

.login-links {
  margin: 0;
  padding: 0;
}

/* Assinatura da aplicação por baixo do título: kicker discreto, não uma segunda
   linha de peso igual. Fecha o bloco de cabeçalho — o espaço que o separa dos
   campos é o maior do cartão, para o olho ler "cabeçalho" e "formulário" como
   dois grupos. */
.app-name {
    /* Sem margem em cima: o espaço até ao logo é dado por ele (--space-2). Em baixo
       fica o maior gap do cartão — é o que separa "quem somos" de "o que se faz". */
    margin: 0 0 var(--space-6) 0;
    /* --text-sm (12px) e não --text-2xs: este é um ecrã anónimo, e o mínimo legível
       em ecrãs anónimos são 12px (ver "Lighthouse — Orçamento de Performance" em
       .github/copilot-instructions.md). Aqui o tamanho pequeno não estava a comprar
       densidade nenhuma — o cartão tem dois campos. O peso discreto continua a vir
       do letter-spacing largo, das maiúsculas e da cor esbatida, não do corpo. */
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    letter-spacing: 0.12em;
    line-height: var(--line-normal);
    color: var(--color-text-muted);
    text-transform: uppercase;
}

/* Cartão. Largura fixa (o conteúdo natural dava ~275px, estreito de mais para a
   altura) e elevação sobre a fotografia de fundo em vez de aresta viva. */
/* Entrada do cartão. O fundo é um vídeo que leva sempre um instante a aparecer; sem
   isto o cartão surgia de repente por cima dele, como um salto.
   A primeira versão (200ms, 6px) não se dava por ela. A segunda (550ms) durava o
   suficiente, mas a curva era uma saída exponencial — quase todo o percurso
   acontecia no primeiro terço do tempo, pelo que o cartão continuava a aparecer de
   golpe e os restantes 400ms eram um assentar que ninguém via.
   Esta distribui o movimento pela duração toda: 900ms e uma curva simétrica e
   suave, sem o arranque abrupto. O cartão chega de baixo (24px) e ligeiramente
   reduzido — transparência e movimento, e mais nada.
   Houve aqui um `filter: blur(5px)`, para o cartão parecer focar sobre o vídeo:
   saiu. O desfoque punha o texto ilegível durante meio segundo, num cartão que
   existe para ser lido, e obrigava o browser a refazer o filtro em cada frame —
   custo real por um efeito que ninguém pediu.
   Nada disto atrasa quem chega para escrever: a animação não intercepta o rato nem
   o teclado, e um clique no campo durante a entrada já escreve. */
@keyframes login-card-in {
    from {
        opacity: 0;
        transform: translateY(24px) scale(0.97);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

#login-form-container {
    animation: login-card-in 0.9s cubic-bezier(0.33, 0, 0.2, 1) both;
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    box-sizing: border-box;
    width: min(380px, calc(100vw - var(--space-8)));
    padding: var(--space-6);
    background-color: var(--color-surface);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}

/* A animação nasce em pausa (a classe é posta pelo script inline da view, ainda
   durante o parsing) e só arranca quando o login.js confirma que o fundo tem
   imagem no ecrã. `both` mantém o fotograma inicial enquanto está pausada, por
   isso o cartão fica invisível em vez de aparecer já desenhado à espera. */
#login-form-container.is-bg-pending {
    animation-play-state: paused;
}

#login-form {
    display: flex;
    flex-direction: column;
    padding: 0;
}

/* ── Ritmo vertical do formulário ────────────────────────────────────────────
   As margens verticais e o padding lateral de .form-col são zerados aqui: neste
   cartão o espaçamento é dado pelas linhas (regras abaixo), não pelas colunas,
   e o padding lateral de 5px estreitava os campos face ao título e ao botão.
   O padding-bottom NÃO é tocado — é a reserva da mensagem de erro
   (--form-error-reserve, contrato global de components.css) e conta para os
   gaps calculados a seguir. */
#login-form .form-col {
    margin: 0;
    padding-left: 0;
    padding-right: 0;
}

#login-form label {
    margin-bottom: var(--space-1);
    /* A regra global (.form-label, label em components.css) dá 11px, que é a
       densidade certa nas listas de trabalho do backoffice e é pequena de mais num
       ecrã que se abre no telemóvel. Sobe-se aqui, no ecrã anónimo, e não no token
       — mexer no --text-xs mudava 320 usos e a densidade de toda a aplicação. */
    font-size: var(--text-sm);
}

/* ── Ritmo vertical do cartão ────────────────────────────────────────────────
   Quatro degraus, do mais junto ao mais separado: 4px prende a etiqueta ao seu
   campo, 20px mantém os campos como um grupo, 24px separa blocos com funções
   diferentes (opção, acção) e 32px marca o fim do cartão.

   Os gaps entre linhas contam SEMPRE com o padding-bottom do .form-col, que é
   a reserva da mensagem de erro (--form-error-reserve, hoje 20px em
   components.css). Só as linhas precedidas de um campo a têm — a do botão vem
   depois do checkbox, que não reserva nada. Recalcular se a reserva mudar. */

/* Campo → campo: 20px, todo ele dado pela reserva. */
#login-form .form-row + .form-row {
    margin-top: 0;
}

/* Campos → opções: 4 + 20 de reserva = 24px. */
#login-form .form-row:has(#remember-me) {
    margin-top: var(--space-1);
}

/* Opção → acção: 24px. Sem reserva antes (o checkbox não tem mensagem de erro),
   por isso é a margem sozinha que faz o degrau — o mesmo salto visual do de cima. */
#login-form .form-row:has(#submit_sign_in_button) {
    margin-top: var(--space-5);
}

/* Acção → ajuda: 32px, o maior do cartão. O link é uma saída lateral, não a
   continuação do que se estava a fazer, e fecha o bloco com o mesmo intervalo
   que o cabeçalho usa para o abrir. */
#login-form .form-row:has(.login-links) {
    margin-top: var(--space-6);
}

/* Os campos.
   Altura igual à do botão (42px): as três caixas empilhadas leem como uma só
   coluna.
   A borda é escurecida 20% porque o par --color-surface-alt (fundo) +
   --color-border a 10% foi pensado para o tema escuro do CMS, onde o campo fica
   mais escuro que o painel e se lê afundado; sobre este cartão branco o mesmo
   par dá um bloco cinzento de contorno indefinido. A fórmula é a do :hover
   global dos campos em components.css.
   NÃO se toca no FUNDO de propósito: --color-surface é o que o design system usa
   para input:disabled, e clarear o campo aqui fá-lo-ia passar por desativado. */
#login-form input:not([type="checkbox"]) {
    height: var(--height-btn-lg);
    font-size: var(--text-md);
    text-align: center;
    border-color: color-mix(in srgb, var(--color-border), var(--color-text) 20%);
}

#login-form input:-webkit-autofill,
#login-form input:-webkit-autofill:hover,
#login-form input:-webkit-autofill:focus,
#login-form input:-webkit-autofill:active {
    -webkit-box-shadow: 0 0 0 1000px #ffffff inset !important; /* intentional: webkit autofill bg-override, must be literal white */
    -webkit-text-fill-color: #333333 !important; /* intentional: webkit autofill text-color override */
    transition: background-color 5000s ease-in-out 0s;
}

/* Botão à largura do cartão e à altura dos campos. O selector antigo apontava a
   #submit-sign-in-button (com hífens), id que não existe no HTML — a regra nunca
   chegou a aplicar-se. */
#login-form #submit_sign_in_button {
    width: 100%;
    height: var(--height-btn-lg);
    margin: 0;
    font-size: var(--text-sm);
}

/* Hover. O .bt-filled.contrast global troca o fundo por --color-text-muted, que
   neste cartão claro é preto a 65% — num CTA desta largura o botão parece
   esmorecer em vez de responder. Aqui clareia-se o mesmo token 14%, a fórmula
   que .bt-filled.primary:hover já usa em components.css: o botão continua sólido
   e a variante mantém-se theme-aware. */
#login-form #submit_sign_in_button:hover:not(.active, .disabled, [disabled]) {
    color: var(--color-surface);
    background: color-mix(in srgb, var(--color-text), #fff 14%);
    border-color: color-mix(in srgb, var(--color-text), #fff 14%);
}

/* Foco por teclado. .bt-filled:focus zera o outline em components.css, o que
   deixava quem chega ao botão por Tab sem qualquer indicação de onde está — no
   ecrã de login, onde e-mail → Tab → palavra-passe → Tab → entrar é um percurso
   normal. O halo é o mesmo dos campos desta página (styles.css, .app input:focus),
   para o cartão inteiro responder ao teclado da mesma maneira. :focus-visible não
   dispara em cliques de rato, logo nada muda para quem usa o rato. */
#login-form #submit_sign_in_button:focus-visible {
    box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

/* Botão durante a submissão: bloqueado (disabled) mas com o aspecto de premido.
   O login.js junta .active + [disabled] — e o design system dá a [disabled] um
   cinzento apagado com !important, que ganhava ao .active e fazia o botão parecer
   indisponível a meio de uma acção que está mesmo a decorrer. Aqui repõe-se o
   estado premido para a variante .bt-filled.contrast (o cartão é sempre claro, logo
   o botão lê-se preto): mesmos tokens da variante, clareados 14% — a fórmula de
   .bt-filled.primary:hover em components.css. Única cópia deliberada — !important
   só se vence com !important. */
#login-form #submit_sign_in_button.active[disabled] {
    color: var(--color-surface) !important;
    background: color-mix(in srgb, var(--color-text), #fff 14%) !important;
    border-color: color-mix(in srgb, var(--color-text), #fff 14%) !important;
    opacity: 1;
    cursor: default !important;
}


/* ── Aviso do cartão (sessão expirada, credenciais erradas) ──────────────────
   Ocupa o lugar acima dos campos em vez de flutuar por cima deles. Fica dentro
   do cartão para o olho encontrar a explicação onde está a acção. */
.login-notice {
    margin: 0 0 var(--space-4) 0;
    padding: var(--space-3);
    font-size: var(--text-sm);
    line-height: var(--line-normal);
    text-align: center;
    border-radius: var(--radius-sm);
    color: var(--color-red);
    background: color-mix(in srgb, var(--color-red), transparent 90%);
    border: 1px solid color-mix(in srgb, var(--color-red), transparent 72%);
}

/* Saída involuntária não é culpa de ninguém — informa, não acusa. */
.login-notice.is-info {
    color: var(--color-text);
    background: var(--color-surface-alt);
    border-color: var(--color-border);
}

.login-notice[hidden] {
    display: none;
}

/* ── Mostrar/ocultar palavra-passe ───────────────────────────────────────────
   O campo é centrado; sem esta reserva o texto passava por baixo do botão. */
#login-form .input-container.has-affix {
    position: relative;
}

#login-form .input-container.has-affix input {
    padding-right: var(--space-6);
    padding-left: var(--space-6);
}

/* O olho do Edge cala-se aqui pela mesma razão do CMS (components.css, bloco do
   `.cms-affix-btn`): o nativo revela sem tocar no `type`, e depois de lhe
   carregarem o nosso deixava de conseguir esconder a palavra-passe. Regra à
   parte, que um pseudo-elemento desconhecido leva a regra toda à frente. */
#login-form .input-container.has-affix input::-ms-reveal { display: none; }

#login-form .login-affix-btn {
    position: absolute;
    top: 50%;
    right: var(--space-2);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    color: var(--color-text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--radius-sm);
    transform: translateY(-50%);
    cursor: pointer;
    transition: color 0.15s ease, background 0.15s ease;
}

#login-form .login-affix-btn:hover,
#login-form .login-affix-btn:focus-visible {
    color: var(--color-text);
    background: var(--color-surface-hover);
}

/* Mesmo halo dos campos e do botão — o cartão responde ao teclado de uma só maneira. */
#login-form .login-affix-btn:focus-visible {
    box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

/* .form-row i { visibility: hidden; position: absolute } (components.css) reserva
   o lugar do ícone de validação e apanha QUALQUER <i> dentro de uma linha de
   formulário — este incluído, que ficava invisível com o botão a funcionar às
   escuras. O design system já repõe o mesmo para os ícones dentro de botões
   .bt-* (logo a seguir a essa regra); aqui aplica-se o mesmo antídoto. */
#login-form .login-affix-btn .ph {
    visibility: visible;
    position: static;
    transform: none;
    font-size: 16px; /* intentional: ícone dentro de um alvo de 28px */
}

/* ── Aviso de Caps Lock ──────────────────────────────────────────────────────
   Fica no fluxo, a seguir ao campo. Chegou a consumir a reserva de erro do
   .form-col com margem negativa, para não deslocar nada — mas o campo vazio
   mostra a sua mensagem de validação nesse mesmo espaço, e as duas frases
   sobrepunham-se. Um deslocamento de 14px é melhor do que texto ilegível. */
#login-form .login-hint {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    margin: var(--space-1) 0 calc(var(--form-error-reserve) * -1) 0;
    /* 12px pela mesma regra do ecrã anónimo. É o aviso que explica a razão mais
       banal de "a minha palavra-passe deixou de funcionar" — e o sítio onde menos
       se quer texto miúdo é aquele que evita uma conta bloqueada. */
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    line-height: var(--line-normal);
    color: var(--color-text-muted);
}

#login-form .login-hint[hidden] {
    display: none;
}

#login-form .link-recover {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: var(--weight-regular);
    color: var(--color-text-muted);
    line-height: var(--line-normal);
    text-decoration: none;
}

#login-form .link-recover:hover,
#login-form .link-recover:focus-visible {
    color: var(--color-text);
    text-decoration: underline;
}

/* A caixa e o texto já são um só elemento flex na regra global de components.css
   (input[type=checkbox] + label). Aqui só se corrige o que era específico do
   login: não duplicar o espaço da caixa (o ::before já traz 7px, o gap somava
   mais 8px) e não herdar a margem lateral direita da regra global, que deslocava
   o par 8px para a esquerda do centro do cartão.
   Prefixado com #login-form porque a regra global (input[type=checkbox] + label)
   tem mais especificidade que .remember-me-label sozinha — e este ficheiro carrega
   ANTES de components.css. */
/* "Lembrar-me" no alcance do teclado. input[type="checkbox"] { display: none }
   (components.css) tirava a caixa da ordem de tabulação — quem não usa rato não
   conseguia marcar a opção, e ela tem efeito real: decide se a sessão dura 7 ou
   30 dias. A view passou a marcá-la com .visually-hidden (base.css), que a mantém
   fora do fluxo sem a desligar; falta só repor o display, porque o selector de
   atributo global vence a classe. Nada muda visualmente em repouso. */
#login-form #remember-me.visually-hidden {
    display: inline-block;
}

/* O foco recai na caixa desenhada pelo ::before do label: mesmo halo dos campos e
   do botão desta página, mais a borda escurecida — só o halo, numa caixa de 20px
   com borda clara, quase não se via. O token da borda é o mesmo que o estado
   :checked já usa em components.css. */
#login-form #remember-me:focus-visible + .remember-me-label::before {
    border-color: var(--color-text-muted);
    box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

#login-form .remember-me-label {
    justify-content: center;
    margin: 0;
    font-size: var(--text-sm);
    color: var(--color-text);
    cursor: pointer;
    user-select: none;
}

/* Faixa animada do rodapé — parente da faixa de saudação do dashboard
   (modules/dashboard/assets/css/dashboard.css), que o login não carrega.
   A primeira versão animava `background-position` num elemento a 100% de
   largura: `background-position` não é composto pela GPU, portanto era um
   repaint da faixa inteira a cada frame — e o rodapé vive abaixo da dobra, pelo
   que esse trabalho todo acontecia sem ninguém o ver.
   Esta anima `transform` num pseudo-elemento: a GPU compõe, o layout não mexe e
   não há um único repaint. Quem a liga e desliga é o login.js, conforme o
   rodapé esteja ou não no ecrã. */
.main-footer {
    display: flex;
    position: relative;
    bottom: 0;
    left: 0;
    margin: 0;
    padding: 20px 0px;
    /* O pseudo-elemento tem o DOBRO da largura: sem isto assomava para fora e
       dava scroll horizontal à página inteira. */
    overflow: hidden;
    /* Contexto de empilhamento próprio: o `z-index: -1` do pseudo fica atrás do
       texto do rodapé mas nunca escapa para trás do resto da página. */
    isolation: isolate;
    /* O que se vê enquanto o movimento estiver desligado, e o que fica por baixo
       se o pseudo não chegar a pintar. */
    background-color: #101010;
}

/* A faixa: o mesmo gradiente de sempre, esticado a 400% da largura do rodapé —
   exactamente o que o `background-size: 400% 400%` da versão anterior fazia. A
   diferença é o que se move. */
.main-footer::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 400%;
    z-index: -1;
    background-image: linear-gradient(-60deg, #111, #333, #666, #333);
    background-size: 100% 100%;
}

/* `is-animating` é posta pelo login.js quando o rodapé entra no ecrã e retirada
   quando sai. Sem JS não há animação — que é a falha certa: um gradiente parado
   é indistinguível do que aqui esteve durante meses. */
.main-footer.is-animating::before {
    /* 4s + `alternate` reproduz o percurso da versão original (background-position
       0%→100%→0% em 8s): a faixa varre três larguras de ecrã e volta atrás, ao
       mesmo ritmo. A primeira tentativa desta reescrita andava a 80px/s contra os
       ~1080px/s do original — tecnicamente a animar, visualmente parada.
       `alternate` também é o que dispensa truques para o ciclo fechar: o percurso
       de volta é o de ida ao contrário. */
    animation: login-footer-drift 4s ease-in-out infinite alternate;
    /* Só enquanto anima: `will-change` permanente é uma camada de compositor
       permanente, que é precisamente o custo que se está aqui a evitar. */
    will-change: transform;
}

@keyframes login-footer-drift {
    from { transform: translate3d(0, 0, 0); }
    /* -75% de 400% = três larguras de rodapé, o mesmo percurso do original. */
    to   { transform: translate3d(-75%, 0, 0); }
}

.copyright-area {
    margin: 0 auto;
    padding: 3px 0;
}

.copyright-text {
    margin: 0px;
    /* 12px: mínimo legível do ecrã anónimo. Era o bloco de texto com mais peso na
       página (36% do total) e o mais pequeno de todos. */
    font-size: var(--text-sm);
    font-weight: var(--weight-regular);
    color: #ffffff;
    text-align: center;
}
/* Movimento reduzido: a página já troca o vídeo de fundo por uma imagem nestas
   condições (login.js) — a entrada do cartão segue a mesma preferência. */
@media (prefers-reduced-motion: reduce) {
    #login-form-container {
        animation: none;
    }

    /* O gradiente fica; o movimento é que não. */
    .main-footer.is-animating::before {
        animation: none;
        will-change: auto;
    }
}
