/* =============================================================================
   Sistema de design do GPlaybacks (paginas de conta, planos e pagamento).

   ARQUITETURA, em tres camadas declaradas por @layer:

     tokens      as decisoes. Cor, raio, espaco, tipo, sombra e tempo. Nenhum
                 seletor pinta nada aqui.
     base        reset e elementos nus.
     components  as pecas. Cada uma le tokens, nunca valor cru.
     utilities   os poucos ajustes pontuais, no fim, para vencerem sem !important.

   POR QUE @layer: sem ele, a ordem do arquivo vira a regra, e qualquer bloco
   novo colado no fim ganha de tudo por acidente. Com camadas, uma utilitaria de
   uma linha vence um componente de vinte sem precisar de !important, e o
   componente nunca vence o token.

   O RISCO DE @layer, e por que ele esta aceito aqui: navegador que nao conhece
   a regra descarta o BLOCO INTEIRO, entao a pagina chegaria sem estilo nenhum,
   e nao degradada. Isso e seguro neste app porque o piso de suporte dele ja e
   mais alto: OPFS (secao 10.4 do SPEC) pede Chrome 108 e Safari 15.2, e @layer
   existe desde Chrome 99, Safari 15.4 e Firefox 97. Nenhum navegador capaz de
   guardar o acervo fica sem as camadas. Se um dia o piso do app descer, este
   arquivo desce junto.

   POR QUE ISTO NAO E shadcn/ui, e o que foi aproveitado dele:
   shadcn/ui e React mais Tailwind mais build step. Este frontend nao tem build
   step (web/src/core/config.js: "Nao existe build step"), a CSP de
   gplay/main.py e script-src 'self' sem CDN, e o app precisa abrir sem rede.
   Trazer o runtime dele trocaria a arquitetura do frontend inteiro.
   O que foi trazido e o que resolve o problema visual: a arquitetura de tokens
   SEMANTICOS (background/foreground/muted/border/ring/destructive em vez de
   nomes de cor), a escala unica de raio derivada de --radius, o anel de foco
   como token de primeira classe, e o contrato de estados de cada componente
   (hover, focus-visible, active, disabled, invalid).

   REGRAS DA CASA:
     - Sem @import de CDN. Fonte do sistema, senao a pagina nao abre offline e
       vaza o IP do usuario. Foi por isso que o Google Fonts saiu (CLAUDE.md 7).
     - Nenhum valor cru em componente. Se precisou de um numero novo, ele vira
       token antes.
     - Todo elemento interativo tem :focus-visible visivel. Sem excecao.
   ============================================================================= */

@layer tokens, base, components, utilities;

/* Os tokens moram em styles/tokens.css, carregado ANTES desta folha.
   Ver o cabecalho daquele arquivo para o motivo da separacao. */

/* ============================================================================
   2. BASE
   ========================================================================== */
@layer base {
  *,
  *::before,
  *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
  }

  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }

  body {
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--background);
    color: var(--foreground);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overscroll-behavior-y: none;
  }

  /* Luz ambiente da marca.
     Um radial-gradient fixo no lugar dos dois pseudo-elementos de 420px com
     filter:blur(120px) que existiam antes. Mesma leitura visual, e sai da
     conta uma camada de composicao permanente que o celular pagava em toda
     rolagem, num app que roda no palco com audio decodificando junto. */
  body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
      radial-gradient(70% 45% at 15% -5%, rgb(var(--luz) / .030), transparent 70%),
      radial-gradient(60% 40% at 90% 100%, rgb(var(--luz) / .022), transparent 70%);
  }

  img,
  svg {
    display: block;
    max-width: 100%;
  }

  button,
  input,
  select,
  textarea {
    font: inherit;
    color: inherit;
  }

  /* Contrato de foco da casa.
     Um unico anel, um unico token, em tudo que recebe foco. Componente que
     precisa de anel diferente redefine --ring no proprio escopo, nunca a regra.
     :focus-visible, e nao :focus, para o anel nao aparecer em clique de mouse. */
  :focus-visible {
    outline: 2px solid var(--ring);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
  }

  ::selection {
    background: var(--ring-halo);
    color: var(--foreground);
  }

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: .01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: .01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

/* ============================================================================
   3. COMPONENTES
   ========================================================================== */
@layer components {

  /* -- moldura ------------------------------------------------------------ */
  .gp-app {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--width-form);
    min-height: 100vh;
    min-height: 100dvh;
    margin-inline: auto;
    padding:
      calc(var(--space-6) + var(--safe-top))
      calc(var(--space-5) + var(--safe-right))
      calc(var(--space-10) + var(--safe-bottom))
      calc(var(--space-5) + var(--safe-left));
    background: var(--surface);
    display: flex;
    flex-direction: column;
  }

  /* No desktop com mouse a moldura vira cartao. No toque ela ocupa a tela
     inteira: borda arredondada em celular so rouba area util. */
  @media (min-width: 520px) and (hover: hover) and (pointer: fine) {
    .gp-app {
      min-height: auto;
      margin-block: var(--space-8) var(--space-12);
      border: 1px solid var(--border-strong);
      border-radius: var(--radius-3xl);
      box-shadow: var(--shadow-lg);
    }
  }

  @media (pointer: coarse) {
    .gp-app {
      max-width: none;
      margin: 0;
      border: 0;
      border-radius: 0;
      box-shadow: none;
    }
  }

  @media (pointer: coarse) and (min-width: 700px) {
    .gp-app {
      padding-left: calc(max(var(--space-5), (100% - 620px) / 2) + var(--safe-left));
      padding-right: calc(max(var(--space-5), (100% - 620px) / 2) + var(--safe-right));
    }
  }

  .gp-app.wide { max-width: var(--width-form); }

  @media (min-width: 760px) and (hover: hover) and (pointer: fine) {
    .gp-app.wide {
      max-width: var(--width-wide);
      padding-inline: var(--space-8);
    }
  }

  /* Centraliza no desktop. No celular NAO: com o teclado aberto, centrar
     empurra o campo em foco para fora da tela. */
  .gp-center { justify-content: flex-start; }

  @media (min-width: 520px) and (hover: hover) and (pointer: fine) {
    .gp-center { justify-content: center; }
  }

  /* ======================================================================
     CASCA DE AUTENTICACAO: meia tela no desktop, aplicativo no celular.

     Sao dois contextos diferentes na mesma pagina, e um cartao flutuante
     centralizado nao atende nenhum dos dois.

     DESKTOP (>=960px): duas colunas. A esquerda vende, a direita trabalha.
     Cartao de 420px boiando no meio de um monitor de 27 polegadas e o gesto
     que faz produto pago parecer formulario administrativo.

     CELULAR: ocupa a tela inteira, sem cartao, sem borda, sem sombra. O botao
     de acao cai na metade de baixo, no alcance do polegar, e as acoes
     secundarias encostam no rodape em vez de flutuarem no meio do vazio. E o
     que separa "site aberto no celular" de "aplicativo".
     ====================================================================== */
  /* TELA CHEIA EM TODA LARGURA, inclusive no monitor de 2560.
     Ate aqui, acima de 1600px a casca virava um cartao de 1440px com borda,
     raio e sombra boiando no meio da tela. Era o que fazia a entrada parecer
     painel administrativo. Agora as duas areas encostam nas bordas da janela,
     como no GDrums: a marca ocupa o que sobra e o formulario tem uma coluna
     propria, de largura limitada, para o campo nunca esticar. */
  .auth {
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    grid-template-columns: 1fr;
    background: var(--surface);
    /* O traco do campo. Creme (ou preto palco, no claro) a 45%: da 3:1 ou
       mais contra o fundo nos dois temas, o minimo para o contorno de um
       controle (WCAG 1.4.11). */
    --linha-campo: rgb(var(--tinta) / .45);
  }

  @media (min-width: 960px) {
    /* A pagina nao rola: so a coluna do formulario. O cadastro e mais alto
       que a tela, e rolando a pagina inteira a marca subia junto e sumia. */
    .auth {
      height: 100vh;
      height: 100dvh;
      overflow: hidden;
      grid-template-columns: minmax(0, 1fr) clamp(480px, 38vw, 720px);
    }
  }

  /* -- painel de marca, so no desktop -- */
  .auth-side { display: none; }

  @media (min-width: 960px) {
    .auth-side {
      position: relative;
      display: flex;
      flex-direction: column;
      min-height: 0;
      padding:
        clamp(var(--space-8), 5vh, var(--space-16))
        clamp(var(--space-10), 5vw, calc(var(--space-12) * 2))
        0;
      background: var(--background);
      overflow: hidden;
    }

    /* A marca no painel e o logo inteiro, grande, como no GDrums: de 168 a
       280px de largura. A 28px de altura ele lia como rodape de e-mail. */
    .auth-side > .gp-lockup { margin-bottom: 0; }
    .auth-side > .gp-lockup img { height: clamp(40px, 3.4vw, 64px); }
    /* Titulo e nota andam JUNTOS, como um bloco so, ancorado no centro
       optico. Antes o titulo tinha `margin: auto` e a nota `margin-top: auto`:
       cada um era empurrado para uma extremidade, e num monitor largo e baixo
       (2553x878) sobrava um buraco de 400px entre a frase e a legenda dela.
       Duas pecas soltas nas pontas de uma coluna vazia nao sao composicao. */
    .auth-side-bloco {
      margin-top: auto;
      margin-bottom: auto;
      display: flex;
      flex-direction: column;
      gap: var(--space-6);
    }
  }

  /* UMA frase, e mais nada.

     Aqui havia uma lista de tres beneficios com bolinha e um desenho de ondas
     com as quatro faixas. Os dois eram preenchimento: a lista e o padrao de
     landing page generica, e o desenho era decoracao que nao informava nada.
     Retirar foi a decisao de design, nao economia de trabalho. Restricao e o
     que separa peca comercial de tela de produto.

     O que carrega o painel agora e a tipografia: corpo grande, entrelinha
     fechada, peso 600 em vez de 800. Titulo grande com peso maximo grita; com
     peso medio e entrelinha curta, impoe. */
  /* O teto era --text-display, 56px. Num monitor de 2553px o titulo travava ali
     e ocupava 220px de uma coluna de 1200: a frase que sustenta o painel
     inteiro ficava do tamanho de um subtitulo. O clamp agora acompanha a
     largura de verdade, e o piso continua protegendo o notebook. */
  .auth-side-titulo {
    font-size: clamp(38px, 4.6vw, 92px);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-display);
    letter-spacing: var(--tracking-display);
    max-width: 13ch;
  }

  .auth-side-titulo em {
    display: block;
    font-style: normal;
    color: var(--muted-foreground);
  }

  /* Assinatura no rodape do painel: texto pequeno, do tamanho de uma legenda.
     E o unico outro elemento da coluna. */
  /* A legenda do titulo. Sobe para --muted-foreground: em
     --subtle-foreground ela dava cerca de 4:1 sobre esta superficie, abaixo do
     minimo para texto pequeno, e era o texto que explica o produto para quem
     nunca ouviu falar dele. A barra a esquerda amarra a legenda ao titulo. */
  .auth-side-nota {
    max-width: 46ch;
    padding-left: var(--space-4);
    border-left: 2px solid var(--border-strong);
    color: var(--muted-foreground);
    font-size: var(--text-md);
    line-height: var(--leading-relaxed);
  }

  /* A ONDA DA MARCA no pe do painel, no lugar da tira de ritmos do GDrums.
     O mesmo desenho da onda do simbolo (as oito alturas de .onda em
     static/app.css, repetidas), na largura do painel. O comeco e coral, o
     trecho que ja saiu do play; o resto e o creme apagado do que ainda vai
     tocar. Parada: decoracao animada de fundo e GPU acesa a toa num aparelho
     que passa o show inteiro ligado. */
  .auth-onda { display: none; }

  @media (min-width: 960px) {
    .auth-onda {
      display: flex;
      align-items: center;
      gap: clamp(3px, .35vw, 6px);
      height: clamp(40px, 6vh, 72px);
      margin-top: var(--space-8);
      margin-bottom: clamp(var(--space-8), 5vh, var(--space-16));
      overflow: hidden;
      -webkit-mask-image: linear-gradient(90deg, black 70%, transparent);
      mask-image: linear-gradient(90deg, black 70%, transparent);
    }

    .auth-onda i {
      flex: 0 0 clamp(4px, .45vw, 8px);
      border-radius: var(--radius-full);
      background: var(--border-hover);
    }

    .auth-onda i:nth-child(8n+1) { height: 42%; }
    .auth-onda i:nth-child(8n+2) { height: 83%; }
    .auth-onda i:nth-child(8n+3) { height: 100%; }
    .auth-onda i:nth-child(8n+4) { height: 58%; }
    .auth-onda i:nth-child(8n+5) { height: 75%; }
    .auth-onda i:nth-child(8n+6) { height: 100%; }
    .auth-onda i:nth-child(8n+7) { height: 50%; }
    .auth-onda i:nth-child(8n)   { height: 33%; }

    /* O que ja tocou: as primeiras barras, e so elas. */
    .auth-onda i:nth-child(-n+11) { background: var(--accent); }
  }

  /* -- coluna do formulario -- */
  .auth-main {
    display: flex;
    flex-direction: column;
    padding:
      calc(var(--space-5) + var(--safe-top))
      calc(var(--space-5) + var(--safe-right))
      calc(var(--space-6) + var(--safe-bottom))
      calc(var(--space-5) + var(--safe-left));
  }

  @media (min-width: 600px) and (max-width: 959.98px) {
    .auth-main { padding-inline: calc(max(var(--space-5), (100% - 520px) / 2)); }
  }

  @media (min-width: 960px) {
    .auth-main {
      min-height: 0;
      overflow-y: auto;
      overscroll-behavior: contain;
      padding: var(--space-12) clamp(var(--space-10), 4vw, var(--space-16));
      background: var(--surface);
      border-left: 1px solid var(--border);
    }
    /* Centrado na vertical SEM cortar o topo. justify-content:center num
       bloco mais alto que a coluna empurra o comeco para cima da rolagem, e
       o titulo do cadastro sumia. Duas molas que encolhem ate zero centram
       quando cabe e somem quando nao cabe. */
    .auth-main::before,
    .auth-main::after {
      content: '';
      flex: 1 1 0;
    }
    /* Largura de leitura de formulario: 400px, e cresce com a escala do
       monitor (--fs). A coluna e mais larga que isso de proposito, para o
       formulario respirar, e o campo nunca estica ate a borda. */
    .auth-main > * { width: 100%; max-width: calc(400px * var(--fs)); margin-inline: auto; }
    /* O link de voltar alinha com o formulario, e nao com a borda da coluna:
       o recuo negativo que ele usa no celular empurrava a seta 8px para fora
       da borda dos campos. */
    .auth-main > .gp-back { align-self: auto; margin-inline: auto; padding-left: 0; }
  }

  /* Empurra rodape e acoes secundarias para baixo no celular, para o polegar
     alcancar o botao e para nao sobrar vazio no fim da tela. No desktop a
     coluna ja e centrada, entao o empurrao sai de cena. */
  .auth-fill { flex: 1 1 var(--space-8); min-height: var(--space-4); }

  @media (min-width: 960px) {
    .auth-fill { display: none; }
  }

  /* Manchete por contexto.

     No celular nao existe painel da esquerda, entao o slogan tem que estar
     AQUI: e ele que da voz a tela, e sem ele sobra um "Entrar" seco que
     qualquer formulario administrativo tambem tem. No desktop o slogan ja
     domina a coluna da esquerda, e repetir na direita seria eco.

     Uma das duas some com display:none, que tira o no da arvore de
     acessibilidade tambem: nunca existem dois h1 expostos ao mesmo tempo. */
  .so-celular { display: block; }
  .so-desktop { display: none; }

  @media (min-width: 960px) {
    .so-celular { display: none; }
    .so-desktop { display: block; }
  }

  /* Barra de topo do celular: a marca compacta, do jeito que um app se
     apresenta. Some no desktop, onde quem apresenta e o painel da esquerda. */
  .auth-topbar .gp-lockup img { height: 34px; }

  .auth-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-8);
  }

  @media (min-width: 960px) {
    .auth-topbar { display: none; }
  }

  /* -- marca e assinatura -------------------------------------------------- */
  /* O gradiente da marca sobrou em DOIS lugares na tela de conta: o simbolo e
     a palavra da assinatura. Em mais nenhum. */
/* Wordmark em TEXTO, nao em gradiente animado.
   O simbolo (o PNG) guarda a cor da marca; repetir as cinco cores na palavra,
   em toda tela, com animacao infinita, era o gesto que mais fazia a interface
   parecer template. E custava uma animacao permanente de background-position
   num app que roda com audio decodificando. */
  .gtext { color: var(--foreground); }

  .gp-brand {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    align-self: flex-start;
    color: var(--foreground);
    text-decoration: none;
    border-radius: var(--radius-sm);
  }

  /* O logo inteiro, a 28px de altura (120px de largura, o minimo da marca
     para o logo completo). Largura automatica: nunca esticar. */
  .gp-brand img { height: 28px; width: auto; flex-shrink: 0; }

  /* O `top: 3px` saiu junto com o gap de 4px: o simbolo e a palavra estavam
     desalinhados na vertical e o conserto era empurrar o texto para baixo.
     Com `align-items: center` e o gap normal, os dois ja se alinham sozinhos,
     e a marca deixa de encostar no titulo logo abaixo. */
  .gp-brand {
    gap: var(--space-2);
    margin-bottom: var(--space-10);
  }

  .gp-brand span {
    font-size: var(--text-lg);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-tight);
  }

  /* Assinatura pequena, no alto e a esquerda. Substitui o logo de 72px
     centralizado: um simbolo grande no meio da tela e o gesto padrao de
     template, e ele empurrava o formulario para a metade de baixo. Aqui a
     marca se identifica e sai da frente. */
  .gp-lockup {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    align-self: flex-start;
    margin-bottom: var(--space-10);
    color: var(--foreground);
    text-decoration: none;
    border-radius: var(--radius-sm);
  }

  .gp-lockup img { height: 28px; width: auto; flex-shrink: 0; }

  .gp-lockup span {
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-tight);
  }

  /* Titulo editorial, alinhado a esquerda.
     O nome do app nao vira manchete: quem chegou aqui ja sabe onde esta. A
     manchete diz o que o produto FAZ, e a segunda linha, no acento, e a
     promessa que nenhum concorrente escreve igual. */
  .auth-hero { margin-bottom: var(--space-8); }

  .auth-hero-title {
    font-size: clamp(34px, 9.5vw, 44px);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tighter);
    text-wrap: balance;
  }

  .auth-hero-title em { display: block; font-style: normal; color: var(--accent-text); }

  .auth-hero-sub {
    max-width: 38ch;
    margin-top: var(--space-2);
    color: var(--muted-foreground);
    font-size: var(--text-md);
    line-height: var(--leading-normal);
    text-wrap: pretty;
  }

  /* No desktop o titulo do formulario ("Entrar", "Criar conta") ganha um
     degrau: ele abre a coluna de trabalho e estava do mesmo tamanho do rotulo
     de um campo mais dois pontos de peso. */
  @media (min-width: 960px) {
    .auth-hero-title { font-size: clamp(40px, 2.8vw, 56px); }
    .auth-hero { margin-bottom: var(--space-8); }
  }

  @media (max-height: 740px) {
    .gp-lockup { margin-bottom: var(--space-6); }
    .auth-hero { margin-bottom: var(--space-6); }
    .auth-hero-title { font-size: var(--text-2xl); }
    .auth-hero-sub { font-size: var(--text-sm); margin-top: var(--space-2); }
  }

  /* Titulo das telas de catalogo (planos) e dos documentos legais.
     ALINHADO A ESQUERDA, como em entrar e criar-conta.

     Era centrado, e centrar era o unico motivo de a pagina de planos parecer
     de outro produto: a marca fica no alto a esquerda, o titulo saltava para o
     meio, o subtitulo tambem, e o paragrafo de dez linhas do rodape terminava
     centrado, que e a forma mais dificil de ler texto corrido. Uma borda
     esquerda comum para marca, titulo, cartoes e rodape e o que faz as quatro
     telas lerem como o mesmo produto. */
  .gp-title {
    font-size: var(--text-3xl);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-display);
  }

  .gp-sub {
    max-width: 46ch;
    color: var(--muted-foreground);
    font-size: var(--text-md);
    line-height: var(--leading-normal);
    text-wrap: pretty;
  }

  .h-title {
    font-size: var(--text-xl);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-tight);
  }

  .sub {
    color: var(--muted-foreground);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
  }

  .gp-back {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    align-self: flex-start;
    /* Respiro antes da manchete. Com 8px, o link de voltar encostava num
       titulo de 36px e os dois liam como um bloco so. */
    margin-bottom: var(--space-6);
    padding: var(--space-2) var(--space-3) var(--space-2) var(--space-2);
    margin-left: calc(var(--space-2) * -1);
    background: none;
    border: none;
    border-radius: var(--radius-full);
    color: var(--muted-foreground);
    font-size: var(--text-base);
    font-weight: var(--weight-medium);
    text-decoration: none;
    cursor: pointer;
    transition: color var(--duration) var(--ease), background var(--duration) var(--ease);
  }

  .gp-back svg { width: 20px; height: 20px; }
  .gp-back:hover { color: var(--foreground); background: var(--card); }
  .gp-back:active { transform: translateX(-2px); }

  /* -- cartao ------------------------------------------------------------- */
  /* O mesmo cartao do app (static/visual.css): superficie erguida, fio de
     cabelo e o fio de luz em cima. */
  .card {
    background: linear-gradient(180deg, rgb(var(--tinta) / .025), transparent 40%), var(--card);
    border: 1px solid var(--hairline);
    border-radius: var(--raio-cartao);
    box-shadow: var(--elev-1);
    padding: var(--space-5);
    margin-bottom: var(--space-4);
  }

  .card-title {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-tight);
  }

  .card-title .ic {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: var(--radius-md);
    background: var(--card-elevated);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* O traco do icone e o coral da marca (o de letra, que le no creme). Era
     url(#gstroke), um degrade de tres cores declarado em cada pagina. */
  .card-title .ic svg {
    width: 16px;
    height: 16px;
    stroke: var(--accent-text);
    fill: none;
    stroke-width: 2;
  }

  /* -- formulario --------------------------------------------------------- */
  .gp-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
  }

  /* gap no formulario cuida do ritmo vertical, entao a linha nao carrega
     margem propria. Antes cada .form-row tinha margin-bottom fixo e qualquer
     campo com dica ou medidor saia do compasso. */
  .form-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  /* Rotulo em caixa alta, pequeno e espacado. E este degrau que permite uma
     interface densa se organizar SEM caixa em volta de cada grupo. Antes era
     12px em peso 700, quase do tamanho do proprio campo, competindo com o
     conteudo em vez de rotular. */
  .form-label {
    font-size: var(--text-label);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--subtle-foreground);
    padding-left: 0;
  }

  .field {
    width: 100%;
    padding: 11px var(--space-3);
    background: var(--input);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    color: var(--foreground);
    font-size: var(--text-base);
    line-height: var(--leading-snug);
    outline: none;
    transition:
      border-color var(--duration) var(--ease),
      box-shadow var(--duration) var(--ease),
      background var(--duration) var(--ease);
  }

  .field::placeholder { color: var(--subtle-foreground); }
  .field:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }

  /* O anel do campo e box-shadow, e nao outline, porque acompanha o
     border-radius e nao briga com o slot do olho da senha. */
  .field:focus-visible,
  .field:focus {
    border-color: var(--ring);
    box-shadow: 0 0 0 3px var(--ring-halo);
    outline: none;
  }

  /* Invalido por classe (JS) ou por atributo ARIA. Os dois caminhos pintam
     igual, entao nao existe estado que o leitor de tela ve e o olho nao. */
  .field.invalido,
  .field[aria-invalid='true'] {
    border-color: var(--destructive);
  }

  .field.invalido:focus-visible,
  .field.invalido:focus,
  .field[aria-invalid='true']:focus-visible,
  .field[aria-invalid='true']:focus {
    border-color: var(--destructive);
    box-shadow: 0 0 0 3px var(--destructive-halo);
  }

  .field:disabled {
    opacity: .5;
    cursor: not-allowed;
  }

  /* Preenchimento automatico do navegador. Sem isto o Chrome pinta o campo de
     azul claro com texto escuro, e o formulario inteiro perde o tema. */
  .field:-webkit-autofill,
  .field:-webkit-autofill:hover,
  .field:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--foreground);
    -webkit-box-shadow: 0 0 0 100px var(--input) inset;
    caret-color: var(--foreground);
  }

  .row { display: flex; gap: var(--space-3); }
  .row > * { flex: 1; }

  /* -- senha -------------------------------------------------------------- */
  .pwd-wrap { position: relative; display: flex; flex-direction: column; }
  .pwd-wrap .field { padding-right: 48px; }

  .pwd-eye {
    position: absolute;
    right: var(--space-1);
    top: 0;
    width: 44px;
    height: 48px;
    padding: 0;
    background: none;
    border: none;
    border-radius: var(--radius-md);
    color: var(--subtle-foreground);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: color var(--duration) var(--ease);
  }

  .pwd-eye svg { width: 20px; height: 20px; }
  .pwd-eye:hover { color: var(--foreground); }
  .pwd-eye .eye-hide { display: none; }
  .pwd-wrap.show .pwd-eye { color: var(--brand-3); }
  .pwd-wrap.show .pwd-eye .eye-show { display: none; }
  .pwd-wrap.show .pwd-eye .eye-hide { display: block; }

  /* -- mensagens de campo -------------------------------------------------- */
  /* O <p> fica sempre no DOM e sempre com aria-live: um no que aparece e
     some do DOM nao e anunciado de forma confiavel. Quem esconde e o
     display, e o texto vazio nao ocupa altura. */
  .field-err {
    display: none;
    align-items: flex-start;
    gap: 6px;
    padding-left: var(--space-1);
    color: var(--destructive);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    line-height: var(--leading-snug);
  }

  .field-err.on { display: flex; }

  .field-err::before {
    content: '';
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    margin-top: 1px;
    background: currentColor;
    -webkit-mask: var(--icon-alert) center / contain no-repeat;
    mask: var(--icon-alert) center / contain no-repeat;
  }

  .field-hint {
    padding-left: var(--space-1);
    color: var(--subtle-foreground);
    font-size: var(--text-2xs);
    line-height: var(--leading-snug);
  }

  /* -- medidor de senha ----------------------------------------------------
     As barras e o rotulo sao UMA peca, agrupada por .pw-strength. Soltos, com
     8px de gap do formulario dos dois lados, os 4px de barra liam como uma
     borda quebrada sob o campo em vez de um medidor. Agora o grupo fica a 12px
     do campo e as duas partes a 4px uma da outra, entao a leitura e obvia.

     O rotulo fica embaixo, e nao ao lado: ele chega a 58 caracteres
     ("Muito fraca - Essa senha e conhecida demais. Escolha outra."), e lado a
     lado espremeria o medidor justo quando ele tem mais a dizer. */
  .pw-strength {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-top: var(--space-1);
  }

  .pw-meter {
    display: flex;
    gap: var(--space-1);
  }

  .pw-meter i {
    flex: 1;
    height: 6px;
    border-radius: var(--radius-full);
    background: var(--border-strong);
    transition: background var(--duration-slow) var(--ease);
  }

  .pw-meter[data-score='1'] i:nth-child(1) { background: var(--destructive); }
  .pw-meter[data-score='2'] i:nth-child(-n+2) { background: var(--warning); }
  .pw-meter[data-score='3'] i:nth-child(-n+3) { background: var(--brand-1); }
  .pw-meter[data-score='4'] i { background: var(--success); }

  .pw-label {
    padding-left: var(--space-1);
    color: var(--muted-foreground);
    font-size: var(--text-2xs);
    font-weight: var(--weight-semibold);
  }

  /* -- caixa de marcar ----------------------------------------------------- */
  .check-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    cursor: pointer;
    user-select: none;
  }

  .check-row input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
  }

  .check-box {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    margin-top: 1px;
    border: 1.5px solid var(--border-hover);
    border-radius: var(--radius-xs);
    background: var(--input);
    display: flex;
    align-items: center;
    justify-content: center;
    transition:
      background var(--duration) var(--ease),
      border-color var(--duration) var(--ease);
  }

  .check-box svg {
    width: 13px;
    height: 13px;
    opacity: 0;
    transform: scale(.5);
    stroke: var(--on-brand);
    fill: none;
    stroke-width: 3;
    transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
  }

  .check-row:hover .check-box { border-color: var(--ring); }
  .check-row input:checked + .check-box { background: var(--accent); border-color: transparent; }
  .check-row input:checked + .check-box svg { opacity: 1; transform: scale(1); }

  .check-row input:focus-visible + .check-box {
    outline: 2px solid var(--ring);
    outline-offset: 2px;
  }

  .check-text {
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
  }

  .check-text a {
    color: var(--accent-text);
    font-weight: var(--weight-semibold);
    text-decoration: none;
    border-radius: var(--radius-xs);
  }

  .check-text a:hover { text-decoration: underline; }

  /* Acoes secundarias em UMA linha de texto, nao em pilulas empilhadas.
     Tres botoes de largura cheia um embaixo do outro dao o mesmo peso visual
     para entrar, criar conta e ver preco. Sao tres importancias diferentes, e
     a tela precisa dizer isso. */
  .auth-alt {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: 1px solid var(--border);
    color: var(--muted-foreground);
    font-size: var(--text-sm);
  }
  .auth-alt .link-btn { font-weight: var(--weight-medium); }

  .auth-alt .link-btn { padding: 0; }
  .auth-alt .sep { margin-inline: var(--space-1); color: var(--border-hover); }

  .login-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
  }

  .link-btn {
    display: inline-block;
    padding: var(--space-2) var(--space-1);
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    text-decoration: underline;
    text-decoration-color: var(--border-hover);
    text-underline-offset: 4px;
    cursor: pointer;
    transition: color var(--duration) var(--ease), text-decoration-color var(--duration) var(--ease);
  }

  /* Link em texto sublinhado, e nao em cor.
     Estava no ciano da marca enquanto o botao ficou no violeta do acento: duas
     cores fortes disputando a mesma tela e o mesmo defeito do gradiente, so
     que mais discreto. Uma cor de acento por interface. O link se distingue
     pelo sublinhado, que e o que link sempre foi. */
  .link-btn:hover { color: var(--accent-text); text-decoration-color: var(--accent-text); }

  /* -- botao --------------------------------------------------------------- */
  .btn {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    min-height: 44px;
    padding: 9px var(--space-4);
    border: 1px solid var(--hairline-strong);
    /* Mesmo raio do campo. Botao em pilula de 999px ao lado de campo de 12px
       sao duas linguagens de forma na mesma tela, e a incoerencia le como
       peca colada de outro lugar. */
    border-radius: var(--raio-controle);
    background: transparent;
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    transition:
      transform var(--duration-fast) var(--ease),
      background var(--duration) var(--ease),
      border-color var(--duration) var(--ease),
      box-shadow var(--duration) var(--ease),
      opacity var(--duration) var(--ease);
  }

  .btn svg { width: 17px; height: 17px; flex-shrink: 0; }
  .btn:hover { background: rgb(var(--tinta) / .04); border-color: var(--border-hover); }
  .btn:active { transform: scale(.97); }

  /* Primario CHAPADO, com fio de luz no topo.
     Era o gradiente inteiro da marca mais um brilho roxo de 24px. Cinco cores
     e um halo num unico botao competem com o proprio rotulo, e e a assinatura
     mais reconhecivel de tema pronto. Uma cor chapada com uma quina iluminada
     le como objeto, aguenta texto por cima e nao briga com nada. */
  .btn.primary {
    background: var(--accent);
    border-color: transparent;
    color: var(--accent-foreground);
    box-shadow: var(--highlight-strong);
  }

  .btn.primary:hover { background: var(--accent-hover); }
  /* O brilho coral so sob o ponteiro, como na pagina de venda. */
  @media (hover: hover) and (pointer: fine) {
    .btn.primary:hover:not(:disabled) { box-shadow: var(--highlight-strong), var(--glow-cta); }
  }
  .btn.primary:active { background: var(--accent-active); }

  .btn.ghost { background: transparent; }
  .btn.ghost:hover { background: var(--card); }

  .btn.danger {
    color: var(--destructive);
    border-color: var(--destructive-border);
    background: transparent;
  }

  .btn.danger:hover { background: var(--destructive-bg); }

  .btn.small {
    min-height: 42px;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-sm);
  }

  /* Desabilitado NAO usa pointer-events:none. Aquilo tira o cursor de recusa,
     mata o title e, se o elemento ja estava com foco, prende o teclado num
     alvo que nao responde. :disabled ja bloqueia o clique sozinho. */
  .btn:disabled,
  .btn[aria-disabled='true'] {
    opacity: .45;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
  }

  .btn:disabled:active,
  .btn[aria-disabled='true']:active { transform: none; }

  /* Carregando: anel girando ANTES do rotulo, nunca no lugar dele.
     O JS troca o texto para "Entrando..." e "Criando sua conta...", e esse
     texto e a unica confirmacao de que o clique foi recebido. Trocar por um
     spinner mudo economiza pixel e custa a resposta que o usuario precisa.

     ::before entra como item do flex, entao o `gap` do proprio botao ja
     posiciona. E pseudo-elemento sobrevive ao textContent que o JS reescreve,
     entao o estado nao depende da ordem das chamadas.

     opacity vem depois de :disabled de proposito: o JS liga os dois juntos, e
     .45 do desabilitado deixaria o rotulo ilegivel justo enquanto ele importa. */
  .btn.loading {
    opacity: .9;
    cursor: progress;
    pointer-events: none;
  }

  .btn.loading::before {
    content: '';
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    border: 2px solid var(--border-hover);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: gp-spin .7s linear infinite;
  }

  .btn.primary.loading::before {
    border-color: rgb(var(--luz) / .35);
    border-top-color: var(--accent-foreground);
  }

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

  /* -- avisos -------------------------------------------------------------- */
  .aviso {
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--warning-border);
    border-radius: var(--radius-lg);
    background: var(--warning-bg);
    color: var(--warning);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
    margin-bottom: var(--space-4);
  }

  .aviso.erro {
    background: var(--destructive-bg);
    border-color: var(--destructive-border);
    color: var(--destructive);
  }

  .aviso.ok {
    background: var(--success-bg);
    border-color: var(--success-border);
    color: var(--success);
  }

  .aviso[hidden] { display: none; }

  /* -- planos -------------------------------------------------------------- */
  .plan-grid {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
  }

  /* TRES colunas, uma por plano, e nao duas.
     Sao tres planos: em duas colunas o terceiro cai sozinho na linha de baixo,
     e o que fica sozinho e justamente o anual, que e o de maior valor e o
     unico com selo de recomendado. Comparar preco exige ver os tres lado a
     lado; empilhado, o ultimo parece um adendo.

     auto-fit com minmax mantem duas colunas onde nao cabem tres, e uma
     coluna no celular, sem media query adicional. */
  @media (min-width: 760px) and (hover: hover) and (pointer: fine) {
    .plan-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
      gap: var(--space-4);
      align-items: stretch;
    }
    /* Com plano pago vigente a vitrine mostra so o atual e os maiores: um ou
       dois cartoes. Centralizados e com a largura de sempre, em vez de um
       cartao esticado ate a borda. */
    .plan-grid[data-qtd="1"] { grid-template-columns: minmax(0, 400px); justify-content: center; }
    .plan-grid[data-qtd="2"] { grid-template-columns: repeat(2, minmax(0, 400px)); justify-content: center; }
  }

  .plan {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: var(--space-5);
    background: linear-gradient(180deg, rgb(var(--tinta) / .025), transparent 40%), var(--card);
    border: 1px solid var(--hairline);
    border-radius: var(--raio-cartao);
    box-shadow: var(--elev-1);
    transition: border-color var(--duration) var(--ease), background var(--duration) var(--ease);
  }

  .plan:hover { border-color: var(--hairline-strong); background: var(--card-elevated); }

  /* O recomendado e a escolha primaria da pagina: fio coral e o halo baixo,
     o mesmo da musica que toca. */
  .plan.best {
    border-color: var(--coral-fio);
    box-shadow: var(--elev-1), var(--glow-linha);
  }

  /* Selo do plano recomendado. Acento chapado, com o mesmo raio do resto.
     Era uma pilula de 999px com o gradiente de cinco cores e halo, colada por
     cima da borda do cartao: a peca mais colorida da unica pagina cujo unico
     trabalho e vender, e ela chamava mais atencao que o proprio preco. */
  .plan-flag {
    position: absolute;
    top: -10px;
    left: var(--space-5);
    padding: 4px var(--space-3);
    background: var(--accent);
    border-radius: var(--radius-sm);
    color: var(--accent-foreground);
    font-size: var(--text-2xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
  }

  .plan-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
  }

  .plan-name {
    font-size: var(--text-lg);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-tight);
  }

  .plan-off {
    padding: var(--space-1) var(--space-3);
    background: var(--success-bg);
    border: 1px solid var(--success-border);
    border-radius: var(--radius-full);
    color: var(--success);
    font-size: var(--text-2xs);
    font-weight: var(--weight-bold);
    white-space: nowrap;
  }

  .plan-price {
    font-size: var(--text-2xl);
    font-weight: var(--weight-bold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tighter);
  }

  .plan-cycle {
    margin-top: var(--space-1);
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
  }

  /* "Equivale a R$ 10,41 por mes" e a informacao que fecha a venda do plano
     longo, entao ela vem no branco do corpo. Estava pintada com o gradiente
     recortado no texto: alem de repetir as cinco cores, texto com
     background-clip perde contraste no meio das paradas de cor e fica
     ilegivel justamente no numero. */
  .plan-per {
    margin-top: var(--space-2);
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
  }

  .plan-feats {
    list-style: none;
    margin: var(--space-4) 0;
    padding: 0;
  }

  .plan-feats li {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: 5px 0;
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
  }

  /* VISTO, nao circulo vazio. O marcador era uma bola oca com borda, que numa
     lista de beneficios le exatamente como caixa DESMARCADA: quatro itens que
     o plano entrega pareciam quatro itens que ele nao tem. O traco usa
     currentColor e a cor vem do proprio item. */
  .plan-feats li::before {
    content: '';
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    margin-top: 2px;
    color: var(--success);
    background: currentColor;
    -webkit-mask: var(--icon-check) center / 15px 15px no-repeat;
    mask: var(--icon-check) center / 15px 15px no-repeat;
  }

  .plan .btn { margin-top: auto; }

  .cupom-row {
    display: flex;
    align-items: stretch;
    gap: var(--space-2);
  }

  .cupom-row .field { flex: 1; text-transform: uppercase; }
  .cupom-row .btn { width: auto; flex: 0 0 auto; padding-inline: var(--space-5); }

  /* -- pagamento ----------------------------------------------------------- */
  .pay-state { text-align: center; padding: var(--space-2) 0; }

  .pay-ic {
    width: 64px;
    height: 64px;
    margin: 0 auto var(--space-4);
    border-radius: var(--radius-xl);
    background: var(--coral);
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .pay-ic svg {
    width: 32px;
    height: 32px;
    stroke: var(--on-brand);
    fill: none;
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .pay-ic.falha { background: var(--gradiente-falha); }
  .pay-ic.espera { background: var(--gradiente-espera); }

  .pay-title {
    font-size: var(--text-xl);
    font-weight: var(--weight-semibold);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-tight);
  }

  .pay-body {
    margin-top: var(--space-2);
    color: var(--muted-foreground);
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
  }

  .spin {
    width: 44px;
    height: 44px;
    margin: 0 auto var(--space-4);
    border: 3px solid var(--border-strong);
    border-top-color: var(--coral);
    border-radius: 50%;
    animation: gp-spin .9s linear infinite;
  }

  /* Nota de contrato da pagina de planos: o audio mora no aparelho e trocar de
     aparelho gasta cota. Usava .gp-sub, que e o subtitulo da tela, entao a
     nota saia do mesmo tamanho da promessa la de cima e colada no ultimo
     cartao. Nota e nota: menor, com respiro, e com a barra a esquerda que
     separa o aviso do catalogo sem precisar de caixa. */
  .nota-aparelho {
    margin-top: var(--space-8);
    padding-left: var(--space-4);
    border-left: 2px solid var(--border-strong);
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-relaxed);
    text-wrap: pretty;
  }

  /* -- rodape -------------------------------------------------------------- */
  /* Alinhado a esquerda como o resto da pagina, e em --muted-foreground.
     Estava centrado e em --subtle-foreground, que sobre esta superficie da
     cerca de 4:1 e nao alcanca o minimo de 4.5:1 para texto pequeno. E o que
     esta escrito ali e "o valor cobrado e sempre o da tabela do servidor",
     que e justamente a linha que ninguem pode alegar nao ter conseguido ler. */
  .gp-foot {
    margin-top: var(--space-6);
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-normal);
    text-wrap: pretty;
  }

  .gp-foot a {
    color: var(--foreground);
    text-decoration: underline;
    text-decoration-color: var(--border-hover);
    text-underline-offset: 3px;
    border-radius: var(--radius-xs);
  }

  .gp-foot a:hover { text-decoration-color: var(--foreground); }

  /* -- toast --------------------------------------------------------------- */
  .gp-toast {
    position: fixed;
    left: 50%;
    bottom: calc(var(--space-8) + var(--safe-bottom));
    z-index: 99;
    max-width: min(86%, 420px);
    padding: var(--space-3) var(--space-4);
    /* Superficie do sistema, e nao `#22263a`: um azul-ardosia escrito a mao
       que nao aparecia em nenhum outro lugar das quatro paginas. Retangulo com
       o raio do sistema pelo mesmo motivo que no app: a pilula era a ultima
       forma de 999px sobrando. */
    background: var(--card-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    text-align: center;
    opacity: 0;
    visibility: hidden;
    transform: translateX(-50%) translateY(18px);
    pointer-events: none;
    transition:
      opacity var(--duration-slow) var(--ease),
      transform var(--duration-slow) var(--ease),
      visibility 0s linear var(--duration-slow);
  }

  .gp-toast.on {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
    transition:
      opacity var(--duration-slow) var(--ease),
      transform var(--duration-slow) var(--ease);
  }

  .gp-toast.erro { border-color: var(--destructive-border); }

  /* -- documentos legais ---------------------------------------------------- */
  .doc-meta {
    margin: calc(var(--space-4) * -1) 0 var(--space-6);
    color: var(--subtle-foreground);
    font-size: var(--text-2xs);
    text-align: center;
  }

  .doc {
    color: var(--foreground);
    font-size: var(--text-sm);
    line-height: var(--leading-relaxed);
  }

  .doc h2 {
    margin: var(--space-6) 0 var(--space-2);
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-tight);
  }

  .doc h2:first-child { margin-top: 0; }
  .doc p { margin: 0 0 var(--space-3); color: var(--muted-foreground); }
  .doc p:last-child { margin-bottom: 0; }
  .doc ul { margin: 0 0 var(--space-3); padding-left: var(--space-5); color: var(--muted-foreground); }
  .doc li { margin-bottom: var(--space-2); }
  .doc strong { color: var(--foreground); font-weight: var(--weight-semibold); }
  .doc a { color: var(--accent-text); text-decoration: none; border-radius: var(--radius-xs); }
  .doc a:hover { text-decoration: underline; }

  /* Documento legal no desktop: 420px de largura sao 45 caracteres por linha,
     curto demais para ler um contrato. 720px fica na medida de leitura. */
  @media (min-width: 760px) and (hover: hover) and (pointer: fine) {
    .gp-app.doc-pagina { max-width: calc(720px * var(--fs)); padding-inline: var(--space-8); }
  }

  /* -- recuperacao de senha ------------------------------------------------- */
  a.btn { text-decoration: none; }

  .link-esqueci {
    padding: var(--space-2) 0;
    font-size: var(--text-sm);
    color: var(--muted-foreground);
  }

  .link-invalido {
    display: flex;
    flex-direction: column;
    margin-top: var(--space-2);
  }

  /* Uma linha antes do CPF, que vale para os dois campos de baixo. */
  .identidade-hint {
    margin: var(--space-1) 0 calc(var(--space-1) * -1);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
    color: var(--muted-foreground);
    font-size: var(--text-xs);
  }

  /* -- planos: sem renovacao automatica, renovacao antecipada -------------- */
  .nota-sem-renovacao {
    max-width: 60ch;
    margin: var(--space-3) 0 var(--space-5);
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
  }

  .plan-nota {
    margin: 0 0 var(--space-3);
    color: var(--muted-foreground);
    font-size: var(--text-xs);
    line-height: var(--leading-snug);
  }

  .plan-nota[hidden] { display: none; }

  /* Plano que veio escolhido (?plano=, renovacao). Anel do sistema, sem cor
     nova: o destaque e a borda, e o selo de melhor valor continua sendo so do
     anual. */
  .plan.escolhido {
    border-color: var(--ring);
    box-shadow: 0 0 0 1px var(--ring), var(--shadow-md);
  }

  /* -- tela de assinatura vencida (renovar.html) --------------------------- */
  .venc-hero { margin-bottom: var(--space-6); }

  .venc-selo {
    display: inline-block;
    margin-bottom: var(--space-3);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--warning-border);
    border-radius: var(--radius-sm);
    background: var(--warning-bg);
    color: var(--warning);
    font-size: var(--text-2xs);
    font-weight: var(--weight-semibold);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
  }

  .venc-hero .gp-sub { max-width: 60ch; margin-bottom: var(--space-5); }

  .venc-acoes {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  @media (min-width: 760px) {
    .venc-acoes { flex-direction: row; }
    .venc-acoes .btn { width: auto; padding-inline: var(--space-6); }
  }

  .venc-preco {
    margin-top: var(--space-3);
    color: var(--foreground);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
  }

  .venc-nota { margin-top: var(--space-2); }

  .venc-biblioteca h2 { font-size: inherit; font-weight: inherit; }

  .venc-reps {
    margin: var(--space-3) 0 0;
    color: var(--muted-foreground);
    font-size: var(--text-xs);
  }

  .venc-lista {
    list-style: none;
    margin: var(--space-4) 0 var(--space-2);
    padding: 0;
    columns: 1;
    column-gap: var(--space-6);
  }

  @media (min-width: 760px) { .venc-lista { columns: 2; } }

  .venc-lista li {
    break-inside: avoid;
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
    color: var(--foreground);
    font-size: var(--text-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* -- monitor largo -------------------------------------------------------
     Em 2560 e 3440 px as duas colunas da casca de autenticacao esticavam ate
     as bordas: a frase de impacto na esquerda, o formulario a 1700 px dela, o
     meio da tela vazio e os campos em 13 px. Acima de 1600 px a casca vira um
     cartao centralizado com largura maxima, e a escala de texto sobe junto
     (--fs, o mesmo multiplicador que styles/tokens.css usa em toda a escala).
     Larguras que eram fixas acompanham o mesmo fator. */
  /* O cartao de 1440px que existia aqui saiu (ver .auth, no topo): a casca
     de autenticacao e tela cheia em toda largura. Fica so a escala. */
  @media (min-width: 1600px) {
    :root { --fs: 1.12; }
    /* As paginas de moldura (.gp-app: planos, renovar, documentos) seguem
       centradas na tela larga, como antes. A casca de autenticacao nao: ela
       e tela cheia. */
    body:not(:has(.auth)) { display: flex; align-items: center; justify-content: center; }
    .auth-side-titulo { font-size: clamp(56px, 4.2vw, 112px); }
    .gp-app { max-width: calc(420px * var(--fs)); }
    .gp-app.wide { max-width: calc(1040px * var(--fs)); }
    .gp-app.doc-pagina { max-width: calc(720px * var(--fs)); }
  }

  @media (min-width: 2400px) {
    :root { --fs: 1.25; }
  }

  /* -- campos e botao da entrada --------------------------------------------
     CAMPO E LINHA, nao caixa, como no GDrums: caixa arredondada com borda em
     volta e a assinatura mais obvia de formulario generico, e cinco caixas
     empilhadas no cadastro liam como planilha. So na casca de autenticacao;
     conta e cupom continuam com a caixa do sistema.

     O traco tem 3:1 contra o fundo (--linha-campo) e engrossa no foco, que
     tambem pinta no coral do anel. Texto a 17px: acima dos 16px que evitam o
     zoom do iOS ao focar, em qualquer ponteiro. */
  .auth .field {
    height: 52px;
    padding: 0 0 2px 1px;
    background: transparent;
    border: 0;
    border-bottom: 1.5px solid var(--linha-campo);
    border-radius: 0;
    font-size: max(16px, var(--text-lg));
    font-weight: var(--weight-medium);
  }

  .auth .field::placeholder { font-weight: var(--weight-normal); }
  .auth .field:hover:not(:disabled):not(:focus):not(.invalido):not([aria-invalid='true']) { border-bottom-color: var(--foreground); }

  .auth .field:focus,
  .auth .field:focus-visible {
    border-bottom: 2px solid var(--ring);
    padding-bottom: 1.5px;
    box-shadow: 0 1px 0 0 var(--ring);
  }

  .auth .field.invalido,
  .auth .field[aria-invalid='true'] { border-bottom-color: var(--destructive); }

  .auth .field.invalido:focus,
  .auth .field.invalido:focus-visible,
  .auth .field[aria-invalid='true']:focus,
  .auth .field[aria-invalid='true']:focus-visible {
    border-bottom-color: var(--destructive);
    box-shadow: 0 1px 0 0 var(--destructive);
  }

  .auth .field:-webkit-autofill,
  .auth .field:-webkit-autofill:hover,
  .auth .field:-webkit-autofill:focus {
    -webkit-box-shadow: 0 0 0 100px var(--surface) inset;
  }

  .auth .pwd-wrap .field { padding-right: 48px; }
  .auth .pwd-eye { right: calc(var(--space-2) * -1); height: 52px; }

  /* O erro nasce colado no campo que ele critica. */
  .auth .field-err { padding-left: 0; font-size: var(--text-sm); }

  .auth .form-row { gap: var(--space-1); }

  /* Aviso da tela (link vencido, configuracao, e-mail enviado): fio colorido
     a esquerda e a frase na cor do estado, sem caixa, como o erro do GDrums.
     A cor de fundo do estado continua, bem leve, para separar do texto. */
  .auth .aviso {
    border: 0;
    border-left: 2px solid currentColor;
    border-radius: 0;
    font-size: var(--text-sm);
  }

  /* A nota do CPF vira legenda com fio a esquerda, como a do painel da marca.
     Caixa com borda no meio de campos de linha era a unica caixa da tela. */
  .auth .identidade-hint {
    margin: 0;
    padding: var(--space-1) 0 var(--space-1) var(--space-4);
    border: 0;
    border-left: 2px solid var(--border-strong);
    border-radius: 0;
    background: transparent;
    line-height: var(--leading-normal);
  }

  /* O botao principal e o UM da tela: 54px, no alcance do polegar e do
     tamanho do campo, com o rotulo no corpo do texto e nao em letra miuda. */
  .auth .btn.primary {
    min-height: 54px;
    font-size: var(--text-base);
    letter-spacing: var(--tracking-tight);
  }

  .auth .btn.ghost { min-height: 54px; font-size: var(--text-base); }
}

/* ============================================================================
   4. UTILITARIAS
   Ultima camada: vencem componente sem precisar de !important.
   ========================================================================== */
@layer utilities {
  /* [hidden] vence qualquer display de componente (.gp-form e flex). Sem
     isto, um formulario escondido por atributo continuaria na tela. */
  [hidden] { display: none; }
  .center { text-align: center; }
  .grow { flex: 1; }
  .mt-8 { margin-top: var(--space-2); }
  .mt-14 { margin-top: var(--space-3); }
  .mt-22 { margin-top: var(--space-5); }

  /* O LOGO TEM DUAS VERSOES e o tema escolhe: o claro (letras creme) no fundo
     escuro, o escuro (letras preto palco) no fundo claro. As duas estao no
     HTML; uma fica escondida. */
  .marca-no-claro { display: none; }
  :root[data-tema="claro"] .marca-no-escuro { display: none; }
  :root[data-tema="claro"] .marca-no-claro { display: block; }

  /* TITULOS EM ARCHIVO, a fonte da marca: ExtraBold, 112% de largura e -4% de
     espacamento, os quatro juntos. So titulo e numero grande; o corpo fica na
     fonte do sistema. */
  .auth-side-titulo, .auth-hero-title, .gp-title, .h-title,
  .plan-name, .plan-price, .pay-title {
    font-family: var(--font-display);
    font-weight: var(--weight-display);
    font-stretch: var(--stretch-display);
    letter-spacing: var(--tracking-brand);
  }

  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

/* iOS: campo com fonte abaixo de 16px faz o Safari dar zoom ao focar. */
@media (pointer: coarse) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea {
    font-size: max(16px, var(--text-base));
  }
}

/* PLANOS NO MONITOR LARGO: a grade dos planos ocupa a largura toda, mas texto
   corrido e o campo do cupom nao. Numa tela de 2560 a faixa "Voce esta no plano
   Anual..." virava uma linha de 200 caracteres, e o cupom um campo de um metro
   para um codigo de oito letras. */
@media (min-width: 960px) {
  #gp_page_planos > .gp-sub,
  #gp_page_planos > .nota-sem-renovacao,
  #gp_page_planos > .aviso,
  #gp_page_planos > .nota-aparelho,
  #gp_page_planos > .gp-foot { max-width: 72ch; }
  #gp_page_planos > .card { max-width: 560px; }
}

/* ============================================================================
   PLANOS E RENOVAR NA GRADE DO APP (W12)
   As duas paginas sao a continuacao do app (o "Ver os planos" da Minha conta,
   o vencimento), e no monitor eram um cartao de 960px no meio da tela, com
   outra largura, outra margem e sem caminho de volta. Agora usam a grade do
   app (tokens.css, --app-*): a barra com o logo na margem e "Voltar para o
   app" na outra ponta, o conteudo na mesma largura e o mesmo respiro.
   Aqui nao ha o zoom do #app: as medidas multiplicam por --app-escala, que e
   o mesmo fator, para baterem em pixel com o app.
   ========================================================================== */
.pagina-barra { display: none; }
@media (min-width: 1024px) {
  .pagina-app {
    --pagina-largura: calc(var(--app-largura) * var(--app-escala));
    --pagina-margem: max(calc(var(--app-gutter) * var(--app-escala)), calc((100% - var(--pagina-largura)) / 2));
    display: block;
    background: var(--background);
  }
  .pagina-barra {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
    /* A altura da barra do app (61px no layout dele, com o zoom junto). */
    box-sizing: border-box; min-height: calc(61px * var(--app-escala));
    padding: 0 var(--pagina-margem);
    background: var(--surface); border-bottom: 1px solid var(--hairline);
  }
  .pagina-barra-marca { display: flex; border-radius: var(--radius-sm); }
  .pagina-barra-marca img { height: calc(28px * var(--app-escala)); width: auto; }
  .pagina-barra-volta {
    display: inline-flex; align-items: center; gap: var(--space-2);
    color: var(--muted-foreground); font-size: calc(14px * var(--app-escala));
    font-weight: var(--weight-medium); text-decoration: none;
  }
  .pagina-barra-volta::before { content: '\2190'; }
  .pagina-barra-volta:hover { color: var(--foreground); }
  .pagina-barra a:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }

  .pagina-app > .gp-app.wide {
    max-width: none; min-height: 0; margin: 0;
    padding: calc(var(--app-respiro) * var(--app-escala)) var(--pagina-margem) var(--space-16);
    background: none; border: 0; border-radius: 0; box-shadow: none;
  }
  .pagina-app > .gp-app > .gp-brand { display: none; }
  .pagina-app > .gp-app .gp-title { margin-top: 0; font-size: calc(var(--titulo-tela) / var(--fs) * var(--app-escala)); line-height: 1; }
  .pagina-app .venc-hero { margin-top: 0; }
  .pagina-app .gp-sub, .pagina-app .nota-sem-renovacao, .pagina-app .aviso,
  .pagina-app .nota-aparelho, .pagina-app .gp-foot { max-width: calc(var(--app-leitura) * var(--app-escala)); }

  /* Os planos atravessam a grade; o cupom vem depois deles, na largura de um
     formulario e encostado na margem. */
  #gp_page_planos .plan-grid { margin-top: var(--space-6); grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #gp_page_planos .plan-grid[data-qtd="1"],
  #gp_page_planos .plan-grid[data-qtd="2"] { grid-template-columns: repeat(3, minmax(0, 1fr)); justify-content: start; }
  #gp_page_planos > .card { max-width: calc(560px * var(--app-escala)); margin-top: var(--space-6); }
}

/* CARTOES DE PLANO ALINHADOS PELO CONTEUDO. O Mensal nao tem a linha
   "Equivale a" e o desconto: sem reservar a altura delas, a lista de
   beneficios dele subia e as tres colunas ficavam desencontradas. No celular
   os cartoes vem um embaixo do outro e nao ha o que alinhar. */
@media (min-width: 760px) {
  .plan-head { min-height: 28px; }
  .plan-per { min-height: calc(var(--text-sm) * 1.5); }
}
/* O selo "Recomendado" sai 10px acima do cartao: a grade guarda essa folga
   para ele nao ser cortado por quem vem antes. */
.plan-grid { padding-top: 12px; }
