/* ds-v3 */
/* ============================================================================
   lig-auth.css — as páginas clássicas de ENTRADA (/login, /update-password, /qrcode, /perdi-acesso,
   /onboarding, message.html, 404/erro). Extraído do lig-theme.css na F0-TEMA (28/09/2026) e levado ao
   DS v3 no lote A-ENTRADA (02/10/2026): espaço, tipo, cor, raio, elevação e motion saem TODOS de token
   (`--space-*`, `--text-*`/`--lh-*`, `--lig-*`, `--hairline-*`, `--lig-radius-*`, `--t-*`/`--ease-*`).
   As larguras vieram da D16 do founder (03/10/2026, lote A-ENTRADA-D16D17): todo cartão de entrada
   tem a largura do cartão do Login do DS (380, o token `--lig-auth-cartao`, declarado abaixo) e o
   /qrcode tem a largura de leitura da camada (`--lig-page-prose`, 660). As únicas medidas cruas que
   sobram são os tamanhos do QR, cada um marcado `largura-ok:` na própria linha: a D27 (founder, 03/10/2026)
   os mantém (280 no /qrcode e na chave, 220 no onboarding). Guarda: qa/entrada.test.mjs (zero hex, zero rgba, zero px fora de token e de
   `largura-ok:`; tokens resolvidos SEM `data-theme`; larguras da D16; layout 390/768/1280; toque; foco).

   DE ONDE VÊM OS TOKENS (medido no lote, 02/10/2026): o `web_include_css` do hooks.py serve
   lig-auth.css → lig-blog.css → lig-theme.css em toda página clássica, e o lig-theme.css declara no
   `:root` a paleta, o bloco DS-V3 (gerado do DS pinado) e a faixa CAMADA-V3:TOKENS. A página clássica
   NÃO tem `data-theme`, então os tokens do frappe-ui remapeados dentro de `[data-theme=…]`
   (`--ink-base`, `--surface-gray-*`, `--elevation-*`…) NÃO existem aqui — este arquivo só lê os do
   `:root`, e declara só dois: o que a camada precisa e não acharia (`--ink-base`) e o único token
   próprio da entrada (`--lig-auth-cartao`), os dois no bloco do fundo, abaixo. Custom property
   resolve no valor computado: a ordem de carga (este antes do tema) não muda o que o token vale.

   ONDE CARREGA: só nas páginas clássicas (web_include_css). Todo seletor daqui é `body[data-path=…]`,
   `.page-card`/rodapé do cartão de auth do frappe ou `.lig-acao-mensagem` (criada pelo lig-auth.js),
   e nada disso existe no SPA (o <body> do _lms.html não tem data-path) nem no desk.
   O modal do frappe (`.modal-content`) FICOU no lig-theme.css: ele também existe no desk.
   ORDEM DE CARGA: a única superfície que o carrega é o `web_include_css` do hooks.py, que serve este
   arquivo ANTES do lig-blog.css e do lig-theme.css. Ele NÃO entra no _lms.html do SPA (a injeção do
   build-image.yml leva só o lig-nativas.css e o lig-theme.css) nem no desk (app_include_css). ⛔ Até o
   N-NATIVAS-B (04/10/2026) esta linha dizia "hooks.py e o _lms.html do build-image.yml". O CSS próprio
   da página de login do frappe (login.bundle) vem DEPOIS das três folhas, e é por isso que há
   `!important` onde ele disputa a mesma propriedade.

   O QUE É DA CAMADA E O QUE É DAQUI: o markup que é NOSSO (o /onboarding e os blocos montados pelo
   lig-auth.js) usa as classes da camada LIG.ui (`.lig-btn`, `.lig-field`, `.lig-field-control`,
   `.lig-check`), que o lig-theme.css já traz; aqui fica só a composição da página (cartão, largura,
   pilha). O markup do CORE (formulário de login, desafio do 2FA, /qrcode, message.html) não é nosso
   e não muda de classe: ele é vestido por seletor, que é o que sobra deste arquivo.
   ============================================================================ */

/* ── O fundo e o token que falta (todas as telas de entrada) ── */
body[data-path='login'],
body[data-path='update-password'],
body[data-path='qrcode'],
body[data-path='perdi-acesso'],
body[data-path='message'],
body[data-path='onboarding'] {
  background: var(--lig-black);
  color: var(--lig-text-2);
  color-scheme: dark;
  position: relative;
  /* `--ink-base` (texto sobre a cor de ação) é do frappe-ui e só existe dentro de `[data-theme]`.
     Sem ele, o `.lig-btn--primary` da camada (color: var(--ink-base)) herdava o text-2 do body:
     rótulo claro sobre o rosa. Aqui ele aponta para o preto travado da paleta. */
  --ink-base: var(--lig-black);
  /* D16 (founder, 03/10/2026): a largura de TODO cartão de entrada é a do cartão do Login do DS
     (components/PlataformaAluno, `.login-card { max-width: 380px }`); o DS não tem token para ela.
     Mora aqui, e não na faixa CAMADA-V3:TOKENS do lig-theme.css, porque só as telas de entrada a leem
     (e o lig-theme.css estava fora da fronteira do lote). É o ÚNICO comprimento cru do arquivo fora dos
     tamanhos do QR — o qa/entrada.test.mjs (entrada-02) conta. */
  --lig-auth-cartao: 380px;
}
/* Glow ambiente no topo (DS Login: o palco preto com --glow-ambient). A elipse do token tem medida
   própria (720×340, transparente a 70%), então a caixa cobre o body inteiro sem mudar o desenho. */
body[data-path='login']::before,
body[data-path='update-password']::before,
body[data-path='qrcode']::before,
body[data-path='perdi-acesso']::before,
body[data-path='onboarding']::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--glow-ambient);
  pointer-events: none;
}

/* ── O cartão (DS Login: surface + anel hairline-2 + --lig-radius-lg) ── */
body[data-path='login'] .page-card,
body[data-path='update-password'] .page-card,
body[data-path='perdi-acesso'] .page-card,
body[data-path='onboarding'] .page-card {
  background: var(--lig-surface);
  box-shadow: 0 0 0 1px var(--hairline-2);
  border-radius: var(--lig-radius-lg);
  border: none;
}
/* A largura de TODO cartão de entrada (D16): uma regra só, pelo token. Inclui o cartão do core no /login e
   no /update-password, que o login.bundle do frappe (carregado DEPOIS) prende em 371 px e, abaixo de 576 px,
   solta em 100%: o seletor daqui (0,2,1) vence o dele (0,2,0) nos dois casos. O cartão da tela de mensagem
   é o primeiro filho da `.error-page` (veja a seção da mensagem). Conta em border-box (o padding entra). */
body[data-path='login'] .page-card,
body[data-path='update-password'] .page-card,
body[data-path='perdi-acesso'] .page-card,
body[data-path='onboarding'] .page-card,
body[data-path='message'] .error-page > div {
  width: 100%;
  max-width: var(--lig-auth-cartao);
}
body[data-path='login'] .page-card-head-text,
body[data-path='login'] h4,
body[data-path='update-password'] h4,
body[data-path='perdi-acesso'] h4,
body[data-path='onboarding'] h4 {
  color: var(--lig-text);
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.015em;
}
body[data-path='login'] .page-card-subtitle,
body[data-path='login'] .text-muted,
body[data-path='perdi-acesso'] .page-card-subtitle,
body[data-path='qrcode'] .text-muted {
  color: var(--lig-text-muted);
}
/* ⚠️ ESTA REGRA ESTAVA MORTA, e por isso ganhou `!important` e companhia.
   O rótulo do campo pedia o text-2 e a rede entregava o cinza do core: o CSS
   da página de login do frappe v16 carrega DEPOIS do `web_include_css` e vence
   — o mesmo motivo registrado no `.form-control` logo abaixo. Ninguém percebeu
   porque a verificação lia o nosso arquivo, não o que o navegador pintava.

   O `/login` do frappe é UM documento com VÁRIOS estados (entrar, cadastro,
   esqueci a senha, link enviado) trocados por JS, e o `/update-password` é
   outra página com a mesma marcação. Medido por pixel no staging em
   07/08/2026, sobre o tema escuro: o rótulo e o `a` sem classe a 4,55:1
   (reprova em card), "Back to sign in" e `.btn-resend-link` a **2,43:1** — e
   os dois últimos são LINKS, controle e não decoração.

   Sem prefixo `data-path` de propósito: foi listar caminho a caminho que
   deixou o `/update-password` de fora na primeira vez. `.page-card` é o cartão
   de auth do frappe e não existe fora dessas telas; os outros dois seletores
   são as mensagens de rodapé do próprio cartão. */
.page-card .form-label,
.page-card .page-card-subtitle,
.page-card .text-muted,
.page-card a:not([class]),
.page-card .btn-resend-link,
.sign-up-message a,
.forgot-password-message a,
.footer-col-right .text-muted {
  color: var(--lig-text-muted) !important;
}
/* O rótulo é o do DS FormControl (o `.lig-field-label` da camada): 500, --text-label, em --lig-text. */
.page-card .form-label {
  color: var(--lig-text) !important;
  font-weight: 500;
  font-size: var(--text-label);
}

/* 404 e erro: a única tela clássica que o tema esqueceu. `body[data-path='404']`
   vinha com o fundo claro de fábrica do frappe enquanto o resto do portal é
   escuro — fundo claro com a nossa tinta clara por cima. Medido em 07/08:
   "Back to Home" a 3,93:1, num link. */
body[data-path='404'],
body[data-path='error'] {
  background: var(--lig-surface);
  color: var(--lig-text-2);
}

/* ── Campos do core (/login, /update-password) ──
   !important: o CSS próprio da página de login do frappe v16 carrega DEPOIS
   do web_include_css e vence a especificidade — exceção registrada em
   OVERRIDES.md (escopo restrito a body[data-path=login/update-password]).
   O campo veste o mesmo que o `.lig-field-control` da camada: surface-2,
   hairline-2, --lig-radius-sm e, no foco, a borda de ação + --focus-ring (DS 18). */
body[data-path='login'] .form-control,
body[data-path='update-password'] .form-control {
  background: var(--lig-surface-2) !important;
  border: 1px solid var(--hairline-2) !important;
  color: var(--lig-text) !important;
  border-radius: var(--lig-radius-sm);
}
/* Estes dois estavam no MESMO seletor e não são a mesma coisa. `.field-icon` é
   ornamento ao lado do campo; `.password-icon` é o botão de mostrar/ocultar a
   senha — controle interativo, e no text-3 ele reprova até o piso de 3:1 que o
   WCAG dá a objeto gráfico. Separados em 07/08/2026. */
body[data-path='login'] .field-icon {
  color: var(--lig-text-3); /* text-3-ok: ornamento ao lado do campo, não é controle */
}
body[data-path='login'] .password-icon {
  color: var(--lig-text-muted);
}
body[data-path='login'] .form-control::placeholder,
body[data-path='update-password'] .form-control::placeholder {
  color: var(--lig-text-3); /* text-3-ok: placeholder é exatamente o papel do token */
}
body[data-path='login'] .form-control:focus,
body[data-path='update-password'] .form-control:focus {
  border-color: var(--lig-action) !important;
  box-shadow: var(--focus-ring) !important;
  background: var(--lig-surface-2) !important;
  color: var(--lig-text) !important;
}

/* ── Botões do core: as variantes da camada (primary/secondary) por seletor ──
   Hierarquia real do template v16: o submit é `.btn-login` (classe btn-default!)
   e o link alternativo é `.btn-login-option`. 1 ação primária por vista. */
body[data-path='login'] .btn-primary,
body[data-path='update-password'] .btn-primary,
body[data-path='update-password'] .btn-signup,
body[data-path='login'] .btn-signup,
body[data-path='perdi-acesso'] .btn-primary,
body[data-path='qrcode'] .btn-primary,
body[data-path='login'] button.btn-login[type='submit'] {
  background: var(--lig-action) !important;
  border-color: var(--lig-action) !important;
  color: var(--ink-base) !important;
  font-weight: 600;
  border-radius: var(--lig-radius-sm);
  transition: background var(--t-micro) var(--ease-swift), box-shadow var(--t-micro) var(--ease-swift);
}
body[data-path='login'] .btn-primary:hover,
body[data-path='login'] button.btn-login[type='submit']:hover {
  background: var(--lig-action-hover) !important;
  border-color: var(--lig-action-hover) !important;
  color: var(--ink-base) !important;
  box-shadow: var(--glow-pink);
}
body[data-path='login'] a.btn-default,
body[data-path='login'] .btn-login-option,
body[data-path='login'] a.btn-login-with-email-link {
  background: transparent !important;
  color: var(--lig-text-2) !important;
  border-color: transparent !important;
  box-shadow: inset 0 0 0 1px var(--hairline-3) !important;
  border-radius: var(--lig-radius-sm);
  transition: background var(--t-micro) var(--ease-swift), color var(--t-micro) var(--ease-swift);
}
body[data-path='login'] a.btn-default:hover,
body[data-path='login'] .btn-login-option:hover,
body[data-path='login'] a.btn-login-with-email-link:hover {
  color: var(--lig-text) !important;
  background: var(--lig-surface-2) !important;
}

/* ── O botão do core desde o frappe v16.52.0: `.es-button` (Espresso) ──
   O CORE-BUMP (lig_lms#684) trocou o markup das telas de acesso: o submit do /login, o "Enviar link" do
   esqueci a senha, o "Verificar" do desafio do 2FA (montado pelo login.js do core), o "Confirmar" do
   /update-password e o "Início" da tela de quem já entrou viraram `.es-button[data-variant='solid']`, e o
   link alternativo virou `.es-button.btn-login-option` (sem variante = `subtle`; vestido pelas regras acima,
   que miram a classe que ficou). As regras de `.btn-login`/`.btn-primary` acima não acham mais o submit, e o
   solid do website.bundle (que carrega ANTES deste arquivo) pinta `--surface-gray-10` (#171717 no `:root`
   claro, o que vale aqui, sem `data-theme`) com o texto em `--ink-base` — que o bloco do fundo, no topo deste
   arquivo, aponta para o PRETO da paleta. Medido no QA do deploy de staging da v0.28.28 (run 39166508707,
   18/10/2026): preto sobre #171717, 1,17:1, e 1,79:1 no hover (#383838). Aqui o solid volta a ser a
   primária da camada (`.lig-btn--primary` do lig-theme.css), estado por estado: repouso rosa de ação com
   `--ink-base`, hover `--lig-action-hover` com o glow, pressionado magenta com `--lig-text` (preto sobre
   magenta mede 3,3:1, camada-07) e travado como o `.lig-btn:disabled` (o do core é um cinza-CLARO sobre o
   tema escuro). O `:not([aria-busy='true'])` do travado é o `:not(.is-busy)` da camada: ocupado mantém a cor
   da variante com o spinner. O foco é o outline do fim deste arquivo, que já cobre todo `button`/`a`.
   `!important` onde o core disputa a propriedade: o `.es-button` mexe em fundo e cor em todo estado.
   Guarda: qa/auth-es-button.test.mjs (o button.css do v16.52.0 copiado da tag, conferido pelo blob). */
body[data-path='login'] .es-button[data-variant='solid'],
body[data-path='update-password'] .es-button[data-variant='solid'],
body[data-path='perdi-acesso'] .es-button[data-variant='solid'],
body[data-path='qrcode'] .es-button[data-variant='solid'],
body[data-path='message'] .es-button[data-variant='solid'] {
  background: var(--lig-action) !important;
  border-color: var(--lig-action) !important;
  color: var(--ink-base) !important;
  font-weight: 600;
  border-radius: var(--lig-radius-sm);
  transition: background var(--t-micro) var(--ease-swift), box-shadow var(--t-micro) var(--ease-swift), color var(--t-micro) var(--ease-swift);
}
body[data-path='login'] .es-button[data-variant='solid']:hover,
body[data-path='update-password'] .es-button[data-variant='solid']:hover,
body[data-path='perdi-acesso'] .es-button[data-variant='solid']:hover,
body[data-path='qrcode'] .es-button[data-variant='solid']:hover,
body[data-path='message'] .es-button[data-variant='solid']:hover {
  background: var(--lig-action-hover) !important;
  border-color: var(--lig-action-hover) !important;
  color: var(--ink-base) !important;
  box-shadow: var(--glow-pink);
}
body[data-path='login'] .es-button[data-variant='solid']:active,
body[data-path='update-password'] .es-button[data-variant='solid']:active,
body[data-path='perdi-acesso'] .es-button[data-variant='solid']:active,
body[data-path='qrcode'] .es-button[data-variant='solid']:active,
body[data-path='message'] .es-button[data-variant='solid']:active {
  background: var(--lig-magenta) !important;
  border-color: var(--lig-magenta) !important;
  color: var(--lig-text) !important;
}
body[data-path='login'] .es-button[data-variant='solid']:is(:disabled, .disabled):not([aria-busy='true']),
body[data-path='update-password'] .es-button[data-variant='solid']:is(:disabled, .disabled):not([aria-busy='true']),
body[data-path='perdi-acesso'] .es-button[data-variant='solid']:is(:disabled, .disabled):not([aria-busy='true']),
body[data-path='qrcode'] .es-button[data-variant='solid']:is(:disabled, .disabled):not([aria-busy='true']),
body[data-path='message'] .es-button[data-variant='solid']:is(:disabled, .disabled):not([aria-busy='true']) {
  background: var(--lig-surface-2) !important;
  border-color: var(--lig-surface-2) !important;
  color: var(--lig-text-3) !important; /* text-3-ok: estado desabilitado é exatamente o papel do token (o mesmo do `.lig-btn:disabled`) */
  box-shadow: none;
  cursor: not-allowed;
}

/* VALIDACAO-720:INICIO ── A mensagem de validação do core desde o frappe v16.52.0 (lig_lms#720) ──
   O mesmo CORE-BUMP trocou a validação das telas de acesso: o envio vazio do /login, o e-mail inválido do
   esqueci a senha e do link por e-mail agora escrevem no `<p class="field-error text-base text-ink-red-8">`
   de cada `.form-group` (login.js do core, `login.show_field_error`, que põe `.invalid` no grupo; o
   login.bundle o mostra), e o /update-password escreve a força da senha num `.password-strength-value`
   com `text-ink-{red,orange,blue,green}-8` e a divergência num `.password-mismatch-message.text-danger`.
   As cores vêm da paleta CLARA do Espresso (colors.css do core no `:root`, o que vale aqui, sem
   `data-theme`): `--ink-red-8` = `--red-700` = #b41d1d sobre o cartão (`--lig-surface`). Medido no
   /login do staging (v0.28.28, core v16.52.0): "Digite seu e-mail." e "Digite sua senha." a 2,83:1; no
   /update-password, a força a 2,83 (Fraca), 3,49 (Média), 4,06 (Boa) e 3,82:1 (Ótima) e "As senhas não
   coincidem" (o `.text-danger` do bootstrap, #e03636 com `!important`) a 4,29:1.
   Aqui a mensagem de campo (obrigatório, e-mail inválido) é o erro do DS FormControl (o `.lig-field-erro`
   da camada): `--lig-action` no `--text-small`, e o campo do grupo inválido ganha a borda de ação (o
   `.lig-field.has-erro`). O medidor do /update-password segue a D183 (founder, 18/10/2026: "No DS temos a
   cor vermelha. Para esses casos pode utilizar o vermelho."): "Fraca" e "As senhas não coincidem" no
   vermelho do DS, que é o `--lig-danger-ink` (o `--lig-danger` de base mede 3,54:1 sobre o cartão, abaixo
   do AA; o `-ink` é a variante de texto do MESMO vermelho, 5,13:1); "Média" no `--lig-warn`; "Boa" e
   "Ótima" no `--lig-teal-ink`. `!important` na cor da mensagem porque o `.text-danger` do core o usa, e na
   borda porque ela disputa a do `.form-control` acima. Guarda: qa/auth-validacao.test.mjs, cujo controle
   positivo tira este bloco inteiro, do INICIO ao FIM (não mude os marcadores). */
body[data-path='login'] .field-error,
body[data-path='update-password'] .field-error {
  font: 400 var(--text-small) var(--font-body);
  color: var(--lig-action) !important;
}
body[data-path='update-password'] .password-mismatch-message {
  font: 400 var(--text-small) var(--font-body);
  color: var(--lig-danger-ink) !important;
}
body[data-path='login'] .form-group.invalid .form-control,
body[data-path='login'] .page-card-body.invalid .form-control,
body[data-path='update-password'] .form-group.invalid .form-control,
body[data-path='update-password'] .page-card-body.invalid .form-control {
  border-color: var(--lig-action) !important;
}
body[data-path='update-password'] .password-strength-value.text-ink-red-8 {
  color: var(--lig-danger-ink);
}
body[data-path='update-password'] .password-strength-value.text-ink-orange-8 {
  color: var(--lig-warn);
}
body[data-path='update-password'] .password-strength-value:is(.text-ink-blue-8, .text-ink-green-8) {
  color: var(--lig-teal-ink);
}
/* VALIDACAO-720:FIM */
body[data-path='login'] a,
body[data-path='qrcode'] a,
body[data-path='perdi-acesso'] a:not(.btn-primary),
body[data-path='onboarding'] a:not(.lig-btn) {
  color: var(--lig-action);
}
body[data-path='login'] a:hover,
body[data-path='qrcode'] a:hover,
body[data-path='perdi-acesso'] a:not(.btn-primary):hover,
body[data-path='onboarding'] a:not(.lig-btn):hover {
  color: var(--lig-action-bright);
}
/* ARMADILHA (achada no /qrcode em 31/07): um `<a>` com classe de botão NÃO é
   link. A regra de cor acima tem especificidade (0,1,2) e vence
   `.lig-btn--primary` (0,1,1) — o rótulo saía rosa sobre fundo rosa, ou seja,
   botão sem texto visível. Fica aqui, colado na regra que causa o problema,
   valendo para todas as telas clássicas: qualquer botão futuro nasce certo. */
body[data-path='login'] a.lig-btn,
body[data-path='qrcode'] a.lig-btn,
body[data-path='update-password'] a.lig-btn,
body[data-path='message'] a.lig-btn,
body[data-path='perdi-acesso'] a.lig-btn,
body[data-path='onboarding'] a.lig-btn,
body[data-path='login'] a.lig-btn:hover,
body[data-path='qrcode'] a.lig-btn:hover,
body[data-path='update-password'] a.lig-btn:hover,
body[data-path='message'] a.lig-btn:hover,
body[data-path='perdi-acesso'] a.lig-btn:hover,
body[data-path='onboarding'] a.lig-btn:hover {
  color: var(--lig-text);
}
body[data-path='login'] a.lig-btn--primary,
body[data-path='qrcode'] a.lig-btn--primary,
body[data-path='update-password'] a.lig-btn--primary,
body[data-path='message'] a.lig-btn--primary,
body[data-path='perdi-acesso'] a.lig-btn--primary,
body[data-path='onboarding'] a.lig-btn--primary,
body[data-path='login'] a.lig-btn--primary:hover,
body[data-path='qrcode'] a.lig-btn--primary:hover,
body[data-path='update-password'] a.lig-btn--primary:hover,
body[data-path='message'] a.lig-btn--primary:hover,
body[data-path='perdi-acesso'] a.lig-btn--primary:hover,
body[data-path='onboarding'] a.lig-btn--primary:hover {
  color: var(--ink-base);
}
body[data-path='login'] ::selection,
body[data-path='update-password'] ::selection,
body[data-path='qrcode'] ::selection,
body[data-path='perdi-acesso'] ::selection,
body[data-path='onboarding'] ::selection {
  background: var(--lig-action);
  color: var(--lig-black);
}

/* ── O checkbox da camada nas páginas clássicas (achado do A-ENTRADA, 02/10/2026) ──
   O `website.bundle` do frappe dá `appearance: none` a TODO `input[type=checkbox]` e desenha a caixa
   com borda e fundo próprios; a camada (`.lig-check .lig-field-control`) zera fundo e borda porque
   conta com o controle NATIVO + `accent-color` (DS §5.2). As duas juntas apagavam a caixa: o aceite
   dos Termos no desafio do /login e no /onboarding saía SEM caixa visível (medido na casca com o CSS
   do staging). Aqui o controle volta a ser o nativo, que é o que a camada pressupõe. */
body[data-path='login'] .lig-check .lig-field-control,
body[data-path='update-password'] .lig-check .lig-field-control,
body[data-path='qrcode'] .lig-check .lig-field-control,
body[data-path='perdi-acesso'] .lig-check .lig-field-control,
body[data-path='message'] .lig-check .lig-field-control,
body[data-path='onboarding'] .lig-check .lig-field-control {
  appearance: auto;
}

/* ── Desafio OTP (2FA) no /login: o core injeta #twofactor_div com indicator
   "blue" hardcoded → action; input com cara de código de 6 dígitos ── */
body[data-path='login'] #twofactor_div .indicator.blue {
  color: var(--lig-text);
}
body[data-path='login'] #twofactor_div .indicator.blue::before {
  background: var(--lig-action) !important;
}
body[data-path='login'] #login_token,
body[data-path='onboarding'] #lig_otp_input {
  text-align: center;
  letter-spacing: 0.35em;
  font-size: var(--text-lead);
  font-family: var(--font-mono);
}
body[data-path='login'] #login_token::placeholder {
  letter-spacing: normal;
  font-size: var(--text-ui);
  font-family: var(--font-body);
}
body[data-path='onboarding'] #lig_otp_input::placeholder {
  color: var(--lig-text-3); /* text-3-ok: placeholder é exatamente o papel do token */
}
body[data-path='login'] #twofactor_div #qr_info {
  color: var(--lig-text-2);
  line-height: var(--lh-body);
}
/* "Confiar neste dispositivo" (F2, D1 opt-in): desde o A-ENTRADA é o `.lig-check` da camada, montado
   pelo lig-auth.js; aqui só a distância do botão.
   Ritmo (D79, lig_lms#434): o espaço aceite → "Confiar" é o MESMO do código → aceite, o gap do form do
   core e nada mais. Somavam-se a ele a margem de cima do "Confiar" (--space-3) e a `margin-bottom` que o
   `label` do core dá ao aceite (36 px contra 16 na casca do staging). As duas saem; a altura de toque
   do `.lig-check` (min-height) fica, porque é o alvo. Prova: o caso "ritmo" do qa/entrada.test.mjs. */
/* O gap do form do desafio (D79 no v16.52.0, achado do lig_lms#720). Até o v16.27.0 ele vinha do login.bundle
   do core (`.for-login .page-card form { display: flex; flex-direction: column; gap: 16px }`); o login.bundle do
   v16.52.0 (o HU44MCUI servido pelo staging em 18/10/2026) não tem mais a regra, porque os forms do login.html
   trazem as utilidades `flex flex-col gap-8` no markup, e o `.form-verify` que o `request_otp` monta não traz
   nenhuma. Sem ela o form é bloco, e o código, o aceite e o "Confiar" ficavam colados (0 px, medido). O gap
   volta aqui, no mesmo valor (`--space-4`), só para o form do desafio. */
body[data-path='login'] #twofactor_div .form-verify {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
body[data-path='login'] #lig_aceite_wrap {
  margin-bottom: 0;
}
body[data-path='login'] #lig_trust_wrap {
  margin: 0 0 var(--space-1);
}

/* ── /qrcode (setup do 2FA): a página herda navbar+footer padrão do web.html —
   escondê-los p/ igualar às demais telas de auth; QR em cartão claro (o SVG
   precisa de fundo claro p/ leitura da câmera) ── */
body[data-path='qrcode'] .navbar,
body[data-path='qrcode'] .web-footer,
body[data-path='qrcode'] footer {
  display: none !important;
}
body[data-path='qrcode'] main,
body[data-path='qrcode'] .page_content {
  margin: 0 auto;
  padding: var(--space-12) var(--space-6) var(--space-16);
}
/* D16: o /qrcode na largura de LEITURA da camada (`--lig-page-prose`, 660). Ela vale para o texto, como no
   `.lig-pg-corpo` da camada: o limite fica no bloco de dentro (o `.page_content`, que tem o texto) e soma o
   próprio gutter, porque a conta é em border-box. O `main` deixa de ter limite próprio (até 03/10 os dois
   tinham 880 px) e fica com o do `.container` do core, que é mais largo. */
body[data-path='qrcode'] .page_content {
  max-width: calc(var(--lig-page-prose) + 2 * var(--space-6));
}
body[data-path='qrcode'] h1 {
  color: var(--lig-text);
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.025em;
  font-size: var(--text-h2);
  line-height: var(--lh-h2);
  margin-bottom: var(--space-6);
}
body[data-path='qrcode'] p,
body[data-path='qrcode'] ol {
  color: var(--lig-text-2);
  font-size: var(--text-base);
  line-height: var(--lh-body);
}
body[data-path='qrcode'] ol li {
  margin-bottom: var(--space-2);
}
body[data-path='qrcode'] img[src^='data:image/svg+xml'] {
  background: var(--lig-text); /* o branco da paleta: o QR precisa de fundo claro para a câmera */
  padding: var(--space-4);
  border-radius: var(--lig-radius-md);
  box-shadow: 0 0 0 1px var(--hairline-2);
  width: 100%;
  max-width: 280px; /* largura-ok: tamanho do QR mantido pela D27 (03/10/2026) */
  height: auto;
}

/* Saída do passo "volte à tela de verificação" + chave em texto para quem faz
   o cadastro pelo próprio celular e não consegue fotografar a tela (31/07). */
body[data-path='qrcode'] .lig-qr-acoes {
  margin: var(--space-6) 0 var(--space-1);
}
body[data-path='qrcode'] .lig-qr-chave {
  max-width: 280px; /* largura-ok: acompanha o QR, mantido pela D27 (03/10/2026) */
  margin-top: var(--space-6);
}
body[data-path='qrcode'] .lig-qr-abrir {
  display: block;
  text-align: center;
}
body[data-path='qrcode'] .lig-qr-nota {
  font-size: var(--text-label);
  line-height: var(--lh-small);
  color: var(--lig-text-muted);
  margin: var(--space-3) 0 var(--space-2);
}
body[data-path='qrcode'] .lig-qr-chave-valor {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-base);
  letter-spacing: 0.08em;
  color: var(--lig-text);
  background: var(--lig-surface);
  border: 1px solid var(--lig-border-solid);
  border-radius: var(--lig-radius-sm);
  padding: var(--space-3) var(--space-4);
  word-break: break-all;
  user-select: all;
}
body[data-path='qrcode'] .lig-qr-copiar {
  margin-top: var(--space-3);
}
/* "Chave copiada": o anel do `.lig-btn--secondary` é estado (--lig-sombra-estado, W4 classe 9), e
   é nele que o sucesso vira teal — a borda que esta regra pintava não existe no `.lig-btn`. */
body[data-path='qrcode'] .lig-qr-copiar.is-ok {
  --lig-sombra-estado: inset 0 0 0 1px var(--lig-teal-ink);
  color: var(--lig-teal-ink);
}

/* ── /perdi-acesso (página própria do lig_lms): card central estilo login ── */
body[data-path='perdi-acesso'] .for-perdi-acesso {
  display: flex;
  justify-content: center;
  padding: var(--space-16) var(--space-4);
}
body[data-path='perdi-acesso'] .page-card {
  padding: var(--space-8) var(--space-6);
}
body[data-path='perdi-acesso'] .page-card-head h4 {
  margin-bottom: var(--space-2);
}
body[data-path='perdi-acesso'] .lig-steps {
  padding-left: var(--space-6);
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-ui);
  line-height: var(--lh-body);
}
body[data-path='perdi-acesso'] .lig-steps li {
  margin-bottom: var(--space-3);
}
body[data-path='perdi-acesso'] .lig-sla {
  color: var(--lig-text-muted);
  font-size: var(--text-label);
  margin: var(--space-3) 0 var(--space-4);
}
body[data-path='perdi-acesso'] .lig-back {
  text-align: center;
  margin-top: var(--space-4);
  font-size: var(--text-ui);
}
body[data-path='perdi-acesso'] .navbar,
body[data-path='perdi-acesso'] .web-footer,
body[data-path='perdi-acesso'] footer {
  display: none !important;
}

/* ── /onboarding (wizard do aluno, página própria do lig_lms): mesma linguagem das telas de auth
     (card central escuro, glow, ação rosa). Desde o A-ENTRADA o markup do template é o da camada
     (`.lig-field`/`.lig-field-control`/`.lig-field-erro`, `.lig-check`, `.lig-btn`): aqui fica a
     composição — o cartão e a pilha do corpo. ── */
body[data-path='onboarding'] .navbar,
body[data-path='onboarding'] .web-footer,
body[data-path='onboarding'] footer {
  display: none !important;
}
body[data-path='onboarding'] .for-onboarding {
  display: flex;
  justify-content: center;
  padding: var(--space-12) var(--space-4) var(--space-16);
}
body[data-path='onboarding'] .page-card {
  padding: var(--space-6) var(--space-6) var(--space-8);
}
body[data-path='onboarding'] h4 {
  font-size: var(--text-h3);
  line-height: var(--lh-h3);
  margin-bottom: var(--space-2);
}
body[data-path='onboarding'] .page-card-subtitle {
  color: var(--lig-text-muted);
  font-size: var(--text-ui);
  line-height: var(--lh-body);
  margin: 0;
}
body[data-path='onboarding'] .page-card-head {
  margin-bottom: var(--space-6);
}
/* A pilha do corpo: um ritmo só (--space-4) entre QR, campo, aceite, erro e ações — antes cada peça
   trazia a própria margem (6, 8, 10, 14, 16, 18 px). O botão ocupa a largura do cartão. */
body[data-path='onboarding'] .page-card-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
body[data-path='onboarding'] .page-card-body > p {
  margin: 0;
}
body[data-path='onboarding'] .page-card-body > .lig-btn {
  width: 100%;
}
/* Trilha de etapas (D17, 03/10/2026): o visual do `ui.passos` da camada (P-15), NÃO interativo.
   O `ui.passos` é JS (o lig-spa.js não carrega na página clássica) e monta BOTÕES; aqui a trilha é ornamento
   de orientação (aria-hidden: quem anuncia o passo é o título), então o template reproduz as CLASSES dele
   (`.lig-passos` › `.lig-passos-lista` › `.lig-passos-item` › `.lig-passos-marca` + `.lig-passos-rotulo`) e
   os atributos que a camada pinta (`data-estado='feito'` = ✓ teal; `aria-current='step'` = anel de ação +
   lift), em <span>, sem <button>. O desenho é todo do lig-theme.css; aqui só o que o tira de controle:
   nada de ponteiro (sem cursor de mão, sem hover — o hover da camada trocaria o anel de ação do passo atual
   pelo hairline), e a altura de repouso da camada também no toque (os 44 px do ponteiro grosso são de ALVO,
   e ornamento não é alvo). */
body[data-path='onboarding'] .lig-passos[aria-hidden='true'] {
  margin-bottom: var(--space-6);
  pointer-events: none;
}
body[data-path='onboarding'] .lig-passos[aria-hidden='true'] .lig-passos-item {
  cursor: default;
  min-height: var(--space-8);
}
/* QR do 2FA — fundo claro p/ leitura da câmera */
body[data-path='onboarding'] .lig-qr-wrap {
  display: flex;
  justify-content: center;
}
body[data-path='onboarding'] .lig-qr-wrap svg,
body[data-path='onboarding'] .lig-qr-wrap img {
  background: var(--lig-text); /* o branco da paleta: o QR precisa de fundo claro para a câmera */
  padding: var(--space-4);
  border-radius: var(--lig-radius-md);
  width: 100%;
  max-width: 220px; /* largura-ok: tamanho do QR mantido pela D27 (03/10/2026) */
  height: auto;
}
body[data-path='onboarding'] .lig-qr-help {
  text-align: center;
  font-size: var(--text-label);
}
/* Passo Termos (PR-L3): links para os textos publicados. O link ocupa a linha inteira da lista, e a
   linha tem a altura de toque (--tap-min) em qualquer ponteiro. */
body[data-path='onboarding'] .lig-termos-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
body[data-path='onboarding'] .lig-termos-links li {
  background: var(--lig-surface-2);
  border: 1px solid var(--hairline-2);
  border-radius: var(--lig-radius-sm);
}
body[data-path='onboarding'] .lig-termos-links a {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: 0 var(--space-4);
  font-weight: 500;
}
/* D17 (03/10/2026): os links "Termos de Uso"/"Política de Privacidade" (aceite do desafio do /login e do
   passo 2fa do /onboarding, e a lista do passo Termos) vão na COR DE AÇÃO do DS (guideline 18: links =
   action) pelo primitivo da camada, sem regra aqui: o markup é nosso (onboarding.html e o `linkExterno()`
   do lig-auth.js) e leva `class="lig-link"`, e o `a.lig-link` do lig-theme.css, que o web_include_css
   serve a estas páginas, já traz a cor, o hover em --lig-action-bright, o sublinhado e o anel de foco. Com a
   classe, o `.page-card a:not([class])` da seção dos rótulos deixa de casar com eles. Contraste: entrada-09. */

/* ── Tela de mensagem/erro (message.html — ex.: link do QR expirado, 403):
   o body dessa renderização recebe data-path='message' (o path do template
   substituto), verificado ao vivo na v16.27.0 ── */
body[data-path='message'] {
  background: var(--lig-black) !important;
}
body[data-path='message'] .error-page,
body[data-path='message'] .error-page > div {
  background: transparent;
  color: var(--lig-text-2);
}
/* A `.error-page` do core é um flex ROW centralizado, e o card (seu primeiro
   filho) encolhe até o conteúdo — 163px medidos no prod em 31/07. Com o bloco
   de saída dentro dele (ver `lig-auth.js`), o card precisa de uma largura
   própria, senão o formulário de reenvio nasce espremido: desde a D16 é a do
   cartão de entrada (`--lig-auth-cartao`), dada na regra do cartão. */
body[data-path='message'] .error-page > div {
  text-align: left; /* a largura é a de todo cartão de entrada (D16), na regra do cartão lá em cima */
}
body[data-path='message'] .error-page .page-card-head {
  color: var(--lig-text);
  font-family: var(--font-display);
  font-weight: 500;
  border: none;
}
body[data-path='message'] .error-page .details,
body[data-path='message'] .error-page p {
  color: var(--lig-text-2);
}
body[data-path='message'] .error-page .btn-primary {
  background: var(--lig-action) !important;
  border-color: var(--lig-action) !important;
  color: var(--ink-base) !important;
  font-weight: 600;
  border-radius: var(--lig-radius-sm);
}
body[data-path='message'] a {
  color: var(--lig-action);
}

/* ── Bloco de ação das telas de mensagem (injetado pelo lig-auth.js) ────────
   A tela do core informa que o link de acesso morreu e não oferece caminho
   nenhum: em 27/07 o founder achou o beco sem saída junto com o inglês. O
   bloco traz "Enviar de novo o e-mail" + os atalhos de saída.
   SEM escopo por data-path de propósito: estas classes são NOSSAS e não
   disputam cascata com o CSS do frappe — escopar aqui só duplicaria seletor.
   Os tokens vêm de :root, então valem também nas páginas clássicas (que não
   têm [data-theme]). ── */
.lig-acao-mensagem {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--hairline-2);
  text-align: left;
}
.lig-acao-mensagem-form { display: flex; flex-direction: column; gap: var(--space-3); }
.lig-acao-mensagem-titulo {
  margin: 0;
  font: 500 var(--text-ui) var(--font-body);
  color: var(--lig-text);
}
.lig-acao-mensagem-ok,
.lig-acao-mensagem-saida {
  margin: 0;
  font: 400 var(--text-label) var(--font-body);
  color: var(--lig-text-muted);
}
.lig-acao-mensagem-saida a { color: var(--lig-action); }
/* O `label { margin-bottom: .5rem }` do bootstrap do frappe soma-se ao gap do `.lig-field` (a camada conta
   com rótulo sem margem): na página clássica o rótulo do campo da camada volta a não ter margem própria. */
.lig-field > .lig-field-label { margin: 0; }
.lig-acao-mensagem .lig-btn { align-self: flex-start; }
/* Na tela de mensagem, `body[data-path='message'] .error-page p` (0,2,2)
   vence a definição de classe acima (0,1,0) e pinta TODO parágrafo do card de
   --lig-text-2 — medido em fixture offline em 27/07. Para o corpo isso é
   ganho de contraste e fica como está; para o TÍTULO do bloco a hierarquia
   importa, então ele é reafirmado com especificidade suficiente (0,3,1). */
body[data-path='message'] .error-page .lig-acao-mensagem-titulo {
  color: var(--lig-text);
}

/* ── Toque (DS: 44 px por PONTEIRO, nunca pela largura da janela — V3-04 da camada) ──
   Os primitivos da camada (`.lig-btn`, `.lig-check`) já trazem o seu; aqui entram o markup do core
   e os links que ficam sozinhos na linha (o link dentro de frase é exceção do WCAG 2.5.8). A largura
   cheia do botão do bloco de mensagem é para o polegar não mirar num botão encostado na borda — por
   isso ela também vale por ponteiro (até o A-ENTRADA era `max-width: 640px`, a janela). */
@media (pointer: coarse) {
  body[data-path='login'] .form-control,
  body[data-path='update-password'] .form-control,
  body[data-path='login'] button.btn,
  body[data-path='update-password'] button.btn,
  body[data-path='perdi-acesso'] button.btn,
  body[data-path='qrcode'] button.btn,
  body[data-path='message'] button.btn,
  /* O `.es-button` do v16.52.0 não tem `.btn` e crava `height` de 28 px: o `min-height` vence o `height`. */
  body[data-path='login'] .es-button,
  body[data-path='update-password'] .es-button,
  body[data-path='perdi-acesso'] .es-button,
  body[data-path='qrcode'] .es-button,
  body[data-path='message'] .es-button {
    min-height: var(--tap-min);
  }
  body[data-path='login'] a.btn,
  body[data-path='update-password'] a.btn,
  body[data-path='perdi-acesso'] a.btn,
  body[data-path='qrcode'] a.btn,
  body[data-path='message'] a.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap-min);
  }
  body[data-path='login'] a.btn.btn-block,
  body[data-path='update-password'] a.btn.btn-block,
  body[data-path='perdi-acesso'] a.btn.btn-block {
    display: flex;
  }
  .forgot-password-message a,
  .sign-up-message a,
  body[data-path='perdi-acesso'] .lig-back a,
  body[data-path='onboarding'] .lig-qr-help a,
  .lig-acao-mensagem-saida a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-min);
  }
  .lig-acao-mensagem .lig-btn { align-self: stretch; }
}

/* ── Foco visível em toda tela de entrada (DS 09: nunca remover) ──
   outline (não box-shadow): o CSS da página de login vence a cascata do shadow, e o checkbox do
   frappe zera o outline no :focus. Até o A-ENTRADA o /onboarding e a tela de mensagem ficavam de
   fora — e o `.btn-default` do onboarding apagava o anel com o próprio box-shadow !important. */
body[data-path='login'] :where(a, button, input[type='checkbox']):focus-visible,
body[data-path='update-password'] :where(a, button, input[type='checkbox']):focus-visible,
body[data-path='qrcode'] :where(a, button, input[type='checkbox']):focus-visible,
body[data-path='perdi-acesso'] :where(a, button, input[type='checkbox']):focus-visible,
body[data-path='message'] :where(a, button, input[type='checkbox']):focus-visible,
body[data-path='onboarding'] :where(a, button, input[type='checkbox']):focus-visible {
  outline: var(--focus-width) solid var(--lig-action) !important;
  outline-offset: var(--focus-width);
}
