/* =========================================================
   NORMA — Autenticação
   Estilos das páginas de conta (signup, verify, login, mfa-setup,
   reset-password, account). Reaproveita os mesmos tokens definidos
   em css/styles.css :root — nenhuma cor, fonte, raio ou espaçamento
   novo é introduzido aqui, mesma regra de css/checkout.css.

   Sobre estados de erro/força de senha: a paleta da Norma não tem
   vermelho nem verde. Erros usam negrito + glifo "!" + barra lateral
   em prussian blue (mesmo padrão de checkout.css); o medidor de força
   de senha usa preenchimento em onyx (não em cor) + rótulo textual,
   nunca uma barra vermelho/amarelo/verde.
   ========================================================= */

/* [hidden], .skip-link, .field, .form-status e .spinner viviam aqui e
   passaram para css/styles.css -- a única folha que TODAS as 23 páginas
   carregam. Não são cópias lá: foram movidos, porque styles.css carrega
   primeiro e qualquer cópia deixada aqui continuaria a ganhar. */

/* =========================================================
   Estrutura da página
   ========================================================= */

/* `min-height: 60vh` reserva um palco; `align-items: center` é o que
   distribui a folga que sobra. Sem ele o .auth era `display: block` e
   TODA a folga caía em baixo: medido a 1440x1600, reset-password abria a
   50px do topo com 518.41px de vazio por baixo do painel, e login e
   verify faziam o mesmo assim que a janela passava dos ~1210 e ~1050px.
   .outcome (css/checkout.css) faz a MESMA reserva de 60vh e reparte-a ao
   centésimo de pixel em todas as alturas -- isto é uma cópia desse par,
   não uma invenção.
   O 50/70 do padding NÃO é tocado: a folga divide-se em partes iguais
   por cima e por baixo do padding, portanto a inversão deliberada de
   20px entre topo e base continua exactamente onde estava. */
.auth {
  padding-block: var(--space-3xl) var(--space-5xl);
  background: var(--color-white);
  min-height: 60vh;
  display: flex;
  align-items: center;
}

/* A OUTRA METADE, e não é opcional. Com o .auth a ser flex, o .container
   passa a ser um ITEM flex -- e um item flex com `margin-inline: auto`
   deixa de segurar a coluna e centra-se na largura do próprio conteúdo.
   checkout.css:342-350 regista o que isso custou quando aconteceu ao
   .outcome: o .container media 608px com 408.5px de margem esquerda e o
   h1 aterrava a 440.5px enquanto o logótipo por cima dele ficava a
   164.5px -- 308px de quebra entre a marca e o conteúdo, que é a aresta
   que S2.2 declara P0. `width: 100%` devolve ao .container o
   comportamento que ele tem nas outras 16 páginas; a centragem vertical
   não é afectada. As duas declarações são uma só mudança. */
.auth > .container { width: 100%; }

.auth-head { margin-bottom: var(--space-2xl); max-width: 52ch; }
.auth-head h1 { font-size: 2rem; }
.auth-sub { margin-top: var(--space-base); font-size: 1.125rem; line-height: 1.6; color: var(--color-onyx-soft); }

@media (min-width: 768px) {
  .auth-head h1 { font-size: 2.5rem; }
}

.auth-panel {
  max-width: 440px;
  background: var(--color-platinum);
  border-radius: var(--radius-card);
  padding: var(--space-2xl);
}

.auth-links { margin-top: var(--space-lg); font-size: 0.875rem; }
/* UX_LAW_AUDIT.md #1 (Fitts's law): measured 65x20px live, under the 44px
   tap-target floor -- this is the password-reset link. Invisible hit-area
   via padding + a compensating negative margin, same technique as
   .info-tip > summary::after (portal.css) -- the visible underlined text
   does not change size or position. */
.auth-links a {
  display: inline-block;
  padding: 12px 4px;
  margin: -12px -4px;
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Caminho de quem ainda não tem conta. Fica FORA do .auth-panel, como
   um segundo bloco: dentro do painel viraria mais uma linha de rodapé
   do formulário, que é exatamente o que ele deixou de ser quando o
   menu passou a mandar todo mundo para cá. */
.auth-alt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-base);
  margin-top: var(--space-lg);
  padding: var(--space-lg) var(--space-2xl);
  background: var(--color-platinum);
  border-radius: var(--radius-card);
  /* Mesma medida de .auth-panel logo acima. Medido em login.html a
     1440px: o painel do formulário dava 440px e este dava 1.096px --
     dois painéis no token de superfície, mesmo raio, empilhados, com
     as arestas direitas a 656px um do outro, e o de baixo duas vezes e
     meia mais largo para uma linha de texto e um botão. Reutiliza o
     literal que já estava no ficheiro; não cria token. */
  max-width: 440px;
}
.auth-alt p { margin: 0; font-weight: 700; font-size: 0.9375rem; }

/* =========================================================
   Formulário
   .auth-form, .auth-actions, .field, .field-error, .form-status e
   .spinner vivem agora em css/styles.css (uma declaração para as 23
   páginas). O layout do formulário teve de subir junto com .field:
   portal-dashboard.html e portal-project.html escrevem
   `class="auth-form"` e NÃO carregam este ficheiro, e o mesmo vale para
   a linha de dois botões `.auth-actions` de portal-deliverable.html --
   ou seja, essas regras nunca desenharam nada nessas páginas.
   ========================================================= */

/* =========================================================
   Medidor de força de senha
   Preenchimento monocromático (onyx), nunca vermelho/verde — a
   distinção é feita pelo texto do rótulo, não pela cor da barra.
   ========================================================= */

.strength-meter { margin-top: var(--space-xs); }
.strength-track {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--color-white);
  border: 1px solid var(--color-onyx);
  overflow: hidden;
}
.strength-fill {
  height: 100%;
  width: 0%;
  background: var(--color-onyx);
  transition: width 0.2s ease;
}
@media (prefers-reduced-motion: reduce) { .strength-fill { transition: none; } }
.strength-label { display: block; margin-top: var(--space-xs); font-weight: 700; font-size: 0.8125rem; }

/* =========================================================
   Código de verificação (6 dígitos) — verify.html, MFA challenge
   ========================================================= */

.code-input {
  font-family: inherit;
  font-size: 1.5rem;
  letter-spacing: 0.4em;
  text-align: center;
  font-weight: 700;
}

/* =========================================================
   Cartão de autenticação dividido (.auth-split)
   Convite de um lado, formulário do outro, costura curva entre os
   dois. Componente: src/components/ui/auth-switch.tsx, que regista lá
   a tradução de cada valor da referência para os tokens daqui.

   ELEVAÇÃO: sombra OU borda, nunca as duas -- uma borda de 1px por
   baixo de uma sombra larga é o "ghost card". Este cartão fica com a
   sombra (--shadow-float, o mesmo passo único que o cartão do mês e o
   diálogo de cookies já usam) e sem borda nenhuma.
   ========================================================= */

.auth-split {
  /* PUBLIC-B (25/09/2026): the hand-copied literal elevation/radius is gone
     -- this card is also `.pg-auth-split` (public.css), which already wins
     the cascade with the DS's own --shadow-card/--radius-2xl, so the base
     rule now points at the DS tokens directly instead of a private literal
     that public.css had to override anyway. */
  --auth-radius-panel: var(--radius-2xl);
  --auth-shadow-float: var(--shadow-lg);

  --auth-invite-width: 42%;

  position: relative;
  width: 100%;
  max-width: 1040px;
  margin-inline: auto;
  background: var(--color-white);
  border-radius: var(--auth-radius-panel);
  box-shadow: var(--auth-shadow-float);
  overflow: hidden;
}

/* --- Os dois formulários --- */

/* Empilhados na MESMA célula: o cartão mede a altura do formulário
   activo, e o inactivo não empurra nada. Os dois ficam montados (é o
   que torna a troca instantânea e sem rede) -- `inert`, posto pelo
   componente, é que os tira do Tab e do leitor de tela. */
.auth-split__panes { position: relative; display: grid; }
.auth-split__pane {
  grid-area: 1 / 1;
  background: var(--color-white);
  padding: var(--space-3xl) var(--space-2xl) var(--space-5xl);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* O inactivo sai do fluxo sem sair do DOM. `position: absolute` e não
   só `visibility: hidden`: escondido mas em fluxo, ele continuava a
   ocupar a célula da grelha, e como o formulário de cadastro é bem mais
   alto que o de login, o cartão de login abria com uns 200px de branco
   morto por cima do título. Fora de fluxo, a altura do cartão é a do
   formulário que está à vista. */
.auth-split__pane[inert] {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Só a opacidade transita. `visibility` NÃO -- e isto não é detalhe:
   com ela na lista, o painel que acabava de ficar activo continuava a
   computar `visibility: hidden` durante toda a transição, e .focus()
   numa subárvore invisível falha em silêncio. Medido: em rAF1 e rAF2
   ainda vinha `hidden`, e só aos 250ms é que o foco pegava. Fora da
   lista, a visibilidade muda no mesmo recálculo em que o `inert` sai, e
   o foco entra no quadro seguinte. */
.auth-split__pane {
  transition: opacity 200ms ease;
}

/* --- Painel do convite (fundo prussian) --- */

.auth-split__invite {
  position: relative;
  background: var(--color-prussian-blue);
  color: var(--color-white);
  padding: var(--space-3xl) var(--space-2xl);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Empilhado, o formulário vem primeiro: quem abre /login num celular
   vem entrar, não criar conta, e com o convite por cima a tarefa
   principal começava abaixo da dobra. Aqui o convite não desliza --
   não há para onde, numa coluna só. */
@media (max-width: 899px) {
  .auth-split { display: flex; flex-direction: column; }
  .auth-split__panes { order: 1; }
  .auth-split__invite { order: 2; }
}

/* --- O deslize --- */

@media (min-width: 900px) {
  .auth-split__panes {
    /* Os dois formulários ocupam a metade que o convite não cobre. */
    margin-left: var(--auth-invite-width);
    width: calc(100% - var(--auth-invite-width));
  }
  .auth-split--signup .auth-split__panes { margin-left: 0; }

  .auth-split__invite {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: var(--auth-invite-width);
    padding: var(--space-5xl) var(--space-2xl);
    z-index: 2;
    transition: transform 460ms ease;
  }

  /* A única coisa que se move é o painel, e move-se em `transform` --
     nem `left`, nem `width`, nem layout nenhum por quadro. */
  .auth-split--signup .auth-split__invite {
    transform: translateX(calc((100% / 42) * 58));
  }

  /* A costura acompanha: com o painel à direita, a curva tem de abrir
     para o outro lado, senão fica a apontar para fora do cartão. */
  .auth-split--signup .auth-split__seam { transform: scaleX(-1); left: -1px; right: auto; }
}

/* Quem pediu menos movimento troca de formulário na mesma -- só não vê
   o painel viajar. O estado final é idêntico. */
@media (prefers-reduced-motion: reduce) {
  .auth-split__invite,
  .auth-split__pane { transition: none; }
}

.auth-split__invite-inner {
  position: relative;
  z-index: 1;
  max-width: 34ch;
  text-align: center;
}

.auth-split__invite h2 {
  margin: 0;
  /* PUBLIC-B2 (25/09/2026): styles.css:430's bare `h2` rule sets
     font-weight: 800 and was the only rule setting font-weight here --
     this class+element
     selector overrides everything ELSE about h2 but never touched that
     property, so 800 won by default. claude-design's DS headings are
     weight 500; setting it here (a sheet PUBLIC-B may edit) fixes it at
     the two h2s this card actually renders, without touching styles.css. */
  font-weight: 500;
  font-size: 1.75rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--color-white);
}

/* Platinum, não um cinzento: é o par secundário já documentado sobre
   prussian. */
.auth-split__invite p {
  margin: var(--space-base) 0 var(--space-2xl);
  color: var(--color-platinum);
  line-height: 1.6;
}

/* PUBLIC-B2 (25/09/2026): toggle button swapped to DS `.n-btn-secondary`
   (bundle.css), which fills `var(--surface)` -- on this prussian panel
   that is invisible against itself. Same fix as the old .btn-secondary
   override it replaces: force white border/text at rest, and prussian
   text on the white hover fill so it never renders white-on-white. */
.auth-split__invite .n-btn-secondary {
  background: transparent;
  border-color: var(--color-white);
  color: var(--color-white);
  box-shadow: none;
}
.auth-split__invite .n-btn-secondary:hover,
.auth-split__invite .n-btn-secondary:focus-visible {
  background: var(--color-white);
  background-image: none;
  color: var(--color-prussian-blue);
}

/* --- A costura --- */

.auth-split__seam { display: none; }

@media (min-width: 900px) {
  .auth-split__seam {
    display: block;
    position: absolute;
    top: -1px;
    right: -1px;
    width: 150px;
    /* `height: auto` aqui desenhava a curva à altura própria do viewBox
       (~150px) e deixava o resto da aresta a direito -- a curva saía um
       entalhe no topo em vez de uma varredura inteira. Com
       preserveAspectRatio="none" a altura tem de ser imposta. */
    height: calc(100% + 2px);
    z-index: 0;
    fill: var(--color-white);
  }
}

/* --- Conteúdo do formulário --- */

@media (min-width: 900px) {
  .auth-split__pane { padding: var(--space-5xl) var(--space-3xl); }
}

.auth-split__form-inner { width: 100%; max-width: 420px; }

/* Caixa de frase, e não a CAIXA ALTA que styles.css dá aos títulos das
   páginas não-landing. É um desvio deliberado à convenção actual e está
   assinalado como tal: a referência que este cartão segue é em caixa de
   frase, e "ÁREA DO CLIENTE" em versalete a 2rem grita numa tela cuja
   tarefa é escrever duas linhas e sair. Se a convenção antiga ganhar,
   apaga-se esta declaração e nada mais.

   É um <h2> e não um <h1> porque o cartão tem agora DOIS títulos no
   mesmo documento (entrar e criar conta) e só um pode ser o h1 da
   página -- que é o do cabeçalho da própria página. O foco salta para
   aqui ao alternar, daí o tabindex="-1" no componente. */
.auth-split__form-inner h2 {
  margin: 0;
  /* PUBLIC-B2 (25/09/2026): same cause as .auth-split__invite h2 above --
     styles.css:430's bare h2 rule was the only one declaring font-weight. */
  font-weight: 500;
  font-size: 2rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
  text-align: center;
  text-transform: none;
}
.auth-split__form-inner h2:focus-visible { outline-offset: 6px; }

.auth-split__sub {
  margin: var(--space-base) 0 0;
  text-align: center;
  color: var(--color-onyx-soft);
  line-height: 1.6;
}

.auth-split .auth-form { margin-top: var(--space-2xl); }

/* --- Campos em pílula, com ícone --- */

/* A referência preenche o campo e não lhe dá borda. Aqui a borda entra
   na mesma: platinum sobre branco mede 1,16:1, abaixo dos 3:1 que a
   WCAG 1.4.11 pede à fronteira de um controlo. --color-control-edge
   mede 3,07:1 sobre platinum -- é o token que já existe para isto. */
.auth-split .field input,
.auth-split .field select {
  width: 100%;
  max-width: none;
  background: var(--color-platinum);
  border: 1px solid var(--color-control-edge);
  border-radius: var(--radius-pill);
  padding: 14px var(--space-lg);
  min-height: 48px;
}

.auth-split .field input:hover,
.auth-split .field select:hover { border-color: var(--color-prussian-blue); }

/* O ícone é decorativo: o <label> visível por cima já nomeia o campo. */
.auth-split .field-icon { position: relative; }
.auth-split .field-icon > .n-icon {
  position: absolute;
  left: var(--space-lg);
  top: 50%;
  transform: translateY(-50%);
  --n-icon-size: 18px;
  color: var(--color-onyx-soft);
  pointer-events: none;
}
.auth-split .field-icon input { padding-left: calc(var(--space-lg) + 18px + var(--space-md)); }

/* O botão "Mostrar" mora dentro da pílula, por isso o padding da
   direita cresce em vez de o botão sair para fora dela. */
.auth-split .password-field { max-width: none; }
.auth-split .password-field input { padding-right: 5.25rem; }

.auth-split .code-input { text-align: center; }

/* --- Acções --- */

.auth-split .auth-actions { align-items: stretch; }
/* PUBLIC-B2 (25/09/2026): the submit button is `.n-btn-block` now, which
   already sets width:100%; `.n-btn` already centres its own content --
   this rule targeted the retired `.btn` class and had nothing left to do. */
.auth-split .auth-links { text-align: center; }

/* =========================================================
   MFA / TOTP setup — segredo para digitação manual

   DECISÃO REVERTIDA 2026-09-09. Esta secção dizia que mostrávamos só o
   segredo "em vez de um leitor de QR Code de terceiros não verificável
   neste ambiente sem build step". As duas premissas caíram: há build step
   desde a migração para Vite, e o QR passou a ser gerado LOCALMENTE pela
   biblioteca do Project Nayuki (MIT, compilada para js/vendor/qrcodegen.js),
   sem serviço de terceiros -- portanto o segredo continua sem sair do
   browser, que era a preocupação real por trás da regra antiga.

   O QR vive em css/mfa-qr.css, carregado só por mfa-setup.html. A chave
   manual abaixo FICA: é o caminho para quem não tem câmera, usa gestor de
   senhas no mesmo aparelho, ou lê por leitor de tela.
   ========================================================= */

.totp-secret {
  display: block;
  margin: var(--space-base) 0;
  padding: var(--space-lg);
  background: var(--color-white);
  border: 1px solid var(--color-onyx);
  border-radius: var(--radius-card);
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 1.125rem;
  letter-spacing: 0.15em;
  word-break: break-all;
  text-align: center;
}

/* =========================================================
   Página de conta
   ========================================================= */

/* .account-section foi retirado: era byte a byte .portal-section, que
   agora vive em css/styles.css e serve as duas superfícies.
   .badge também foi retirado -- ver .status-badge em css/styles.css. Um
   componente de badge, não dois. (Esteve em portal.css, que esta página
   não carrega, e por isso o badge desta página renderizava sem caixa
   nenhuma; a regra vive agora na folha que as 23 páginas carregam.) */

.account-summary { display: flex; flex-direction: column; gap: var(--space-xs); margin-bottom: var(--space-lg); }
.account-summary dt { font-weight: 500; font-size: 0.8125rem; color: var(--color-onyx-soft); }
.account-summary dd { font-weight: 700; font-size: 1rem; margin: 0 0 var(--space-base); }

/* .btn-danger-outline moved to styles.css so a danger button works on
   every page, not only the ones that happen to load auth.css -- it was
   reachable only here even though the component API
   (components/ui/button.tsx) offers it as a general variant.
   norma_DESIGN.md §13 / Appendix A still describe it as living in this
   file; that cross-reference is now stale and needs its own update. */

/* =========================================================
   Confirmação de exclusão (revelada dentro da própria página)
   ========================================================= */

.delete-confirm {
  margin-top: var(--space-lg);
  padding: var(--space-lg);
  background: var(--color-white);
  border-left: 3px solid var(--color-prussian-blue);
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
}
