/* ==========================================================================
   Folego, componentes
   Peças reutilizadas pelas telas do app. Depende dos tokens de app.css.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Estrutura do shell
   -------------------------------------------------------------------------- */
.app-corpo {
  padding-bottom: calc(var(--altura-nav) + var(--gap));
}

.app-cabecalho {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
  min-height: 3.5rem;
  padding: 0 var(--gap);
  padding-top: env(safe-area-inset-top, 0px);
  border-bottom: 1px solid var(--borda);
}

.app-titulo {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* Lupa mais o que a tela tiver a acrescentar. Sem isto os dois disputam o
   `justify-content: space-between` do cabecalho e a lupa vai parar no meio. */
.cabecalho-acoes {
  display: flex;
  align-items: center;
  gap: var(--espaco-2);
}

.app-tela {
  display: grid;
  gap: var(--gap-grande);
  padding: var(--gap);
  max-width: 40rem;
  margin-inline: auto;
}

.secao {
  display: grid;
  gap: var(--gap-pequeno);
}

.secao-cabecalho {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gap-pequeno);
}

.secao-titulo {
  font-size: var(--texto-2);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--texto-suave);
}

/* Serve para `<a>` e para `<button>`: link que navega e link que fecha uma
   folha antes de navegar sao a mesma coisa para quem olha, e o botao existe
   porque o `<a href>` deixava o observador de folha desfazer a navegacao. */
.link-acao {
  font-size: var(--texto-2);
  font-weight: 500;
  color: var(--primaria);
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   Navegacao inferior
   O item central e elevado porque lancar e a acao primaria do app e precisa
   ficar no alcance do polegar, conforme os padroes do MAPA_TELAS.
   -------------------------------------------------------------------------- */
.nav-inferior {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 30;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: center;
  height: var(--altura-nav);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  border-top: 1px solid var(--borda);
}

.nav-item {
  display: grid;
  justify-items: center;
  gap: var(--espaco-1);
  padding: 0.375rem 0;
  color: var(--texto-suave);
  font-size: 0.625rem;
  font-weight: 500;
  transition: color var(--rapido) ease;
}

/* Atalhos que so existem na lateral. No celular a barra tem cinco itens fixos,
   e essa e uma decisao de alcance do polegar, nao de espaco. */
.nav-so-lateral,
.nav-separador {
  display: none;
}

.nav-item[aria-current="page"] {
  color: var(--primaria);
}

.nav-item svg {
  width: 1.375rem;
  height: 1.375rem;
}

.nav-central {
  justify-self: center;
  display: grid;
  place-content: center;
  width: 3.25rem;
  height: 3.25rem;
  margin-top: -1.25rem;
  border-radius: 50%;
  color: var(--primaria-texto);
  box-shadow: 0 6px 20px color-mix(in oklab, var(--primaria) 40%, transparent);
  transition: transform var(--medio) var(--mola);
}

.nav-central:active {
  transform: scale(0.94);
}

.nav-central svg {
  width: 1.5rem;
  height: 1.5rem;
}

/* O rotulo do botao central so aparece no desktop, onde ele deixa de ser um
   circulo flutuante e vira um botao de barra lateral com texto */
.nav-central-rotulo {
  display: none;
}

/* --------------------------------------------------------------------------
   O botao flutuante do assistente

   Canto inferior direito, acima da barra de baixo e fora da area segura do
   aparelho. Fica abaixo das folhas (50) e dos menus (60), que precisam
   cobri-lo, e acima do conteudo. A tela ganha um respiro embaixo para o
   ultimo botao de um formulario poder rolar para cima dele.
   -------------------------------------------------------------------------- */
.botao-flutuante {
  position: fixed;
  right: calc(var(--gap) + env(safe-area-inset-right, 0px));
  bottom: calc(var(--altura-nav) + var(--gap));
  z-index: 40;
  display: grid;
  place-content: center;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  color: var(--primaria-texto);
  box-shadow: 0 6px 20px color-mix(in oklab, var(--primaria) 40%, transparent);
  transition: transform var(--medio) var(--mola);
}

.botao-flutuante:active {
  transform: scale(0.94);
}

.botao-flutuante svg {
  width: 1.5rem;
  height: 1.5rem;
}

.app-corpo:has(.botao-flutuante:not([hidden])) .app-tela {
  padding-bottom: calc(var(--gap) + 3.25rem + var(--gap));
}

/* --------------------------------------------------------------------------
   Metrica, o cartao de numero do painel
   -------------------------------------------------------------------------- */
.metricas {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--gap-pequeno);
}

.metrica {
  display: grid;
  gap: var(--espaco-1);
  padding: var(--espaco-5);
  border-radius: var(--raio);
  background: var(--cartao);
  border: 1px solid var(--borda);
}

.metrica-rotulo {
  font-size: var(--texto-1);
  font-weight: 500;
  color: var(--texto-suave);
}

.metrica-valor {
  font-family: var(--fonte-numero);
  font-variant-numeric: tabular-nums;
  font-size: var(--texto-5);
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* Painel de destaque com gradiente, o cabecalho do Inicio */
.painel-destaque {
  position: relative;
  overflow: hidden;
  border-radius: var(--raio-grande);
  padding: var(--gap-grande);
  color: #fff;
}

.painel-destaque {
  box-shadow: var(--brilho-primaria);
}

.painel-destaque .metrica {
  background: rgb(255 255 255 / 0.14);
  border-color: rgb(255 255 255 / 0.16);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background var(--medio) var(--curva), transform var(--medio) var(--curva);
}

.painel-destaque .metrica:hover {
  background: rgb(255 255 255 / 0.2);
  transform: translateY(-2px);
}

.painel-destaque .metrica-rotulo {
  /* 70% e nao 40%: rotulo pequeno sobre gradiente precisa de contraste real
     para continuar legivel no celular sob sol */
  color: rgb(255 255 255 / 0.7);
}

.painel-destaque .metrica-valor {
  color: #fff;
}

/* --------------------------------------------------------------------------
   Listas
   -------------------------------------------------------------------------- */
.lista {
  display: grid;
  border-radius: var(--raio);
  background: var(--cartao);
  border: 1px solid var(--borda);
  overflow: hidden;
}

.lista-item {
  display: flex;
  align-items: center;
  gap: var(--espaco-4);
  width: 100%;
  padding: 0.75rem var(--gap);
  text-align: start;
  transition: background var(--rapido) ease, transform var(--rapido) var(--curva);
  border-bottom: 1px solid var(--borda);
}

.lista-item:last-child {
  border-bottom: 0;
}
.lista-item:hover {
  background: color-mix(in oklab, var(--primaria) 5%, transparent);
}

.lista-item:active {
  background: var(--elevado);
  transform: scale(0.995);
}

.lista-icone {
  flex-shrink: 0;
  display: grid;
  place-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--raio-pequeno);
  background: color-mix(in oklab, var(--primaria) 12%, transparent);
  color: var(--primaria);
  font-size: var(--texto-1);
  font-weight: 700;
}

.lista-corpo {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: var(--espaco-1);
}

.lista-titulo {
  font-size: var(--texto-4);
  font-weight: 500;
  /* Duas linhas, e nao uma. Descricao de Pix comeca sempre igual, em
     "Transferencia enviada pelo Pix", e cortar na primeira linha fazia toda
     linha da lista parecer a mesma: o que distingue, que e o destinatario,
     era justamente o pedaco cortado. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.lista-apoio {
  font-size: var(--texto-1);
  color: var(--texto-suave);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Terceiro nivel da linha, abaixo do apoio. Nasceu para o estabelecimento que
   o banco mandou: "Conta de gas" na descricao e "Comgas" aqui embaixo. Menor
   que o apoio de proposito, porque e detalhe que so interessa quando
   interessa, e nao pode disputar a leitura com a descricao. */
.lista-miudo {
  font-size: 0.6875rem;
  color: var(--texto-suave);
  opacity: 0.8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lista-fim {
  flex-shrink: 0;
  display: grid;
  justify-items: end;
  gap: var(--espaco-1);
}

/* --------------------------------------------------------------------------
   Barras de proporcao, usadas no gasto por categoria
   -------------------------------------------------------------------------- */
.barra {
  height: 0.375rem;
  border-radius: 999px;
  background: var(--elevado);
  overflow: hidden;
}

.barra-preenchida {
  position: relative;
  overflow: hidden;
  height: 100%;
  border-radius: 999px;
  position: relative;
  overflow: hidden;
  transition: width var(--lento) var(--curva);
}

/* --------------------------------------------------------------------------
   Formularios
   -------------------------------------------------------------------------- */
.formulario {
  display: grid;
  gap: var(--gap);
}

.campo {
  display: grid;
  gap: var(--espaco-2);
}

.campo-rotulo {
  font-size: var(--texto-2);
  font-weight: 500;
  color: var(--texto-suave);
}

.campo input,
.campo select,
.campo textarea {
  width: 100%;
  min-height: 2.875rem;
  padding: 0 0.875rem;
  border: 1px solid var(--borda);
  border-radius: var(--raio-pequeno);
  background: var(--cartao);
  color: var(--texto);
  font-size: var(--texto-4);
}

.campo textarea {
  padding: 0.75rem 0.875rem;
  min-height: 5rem;
  resize: vertical;
}

.campo input,
.campo select,
.campo textarea {
  transition: border-color var(--rapido) ease, box-shadow var(--medio) var(--curva);
}

.campo input:focus,
.campo select:focus,
.campo textarea:focus {
  border-color: var(--primaria);
  box-shadow: var(--anel-foco);
  outline: 2px solid transparent;
  outline-offset: -1px;
  border-color: transparent;
}

.campo-duplo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-pequeno);
}

/* Campo de valor, protagonista da tela de lancar */
.campo-valor input {
  min-height: 4rem;
  font-family: var(--fonte-numero);
  font-variant-numeric: tabular-nums;
  font-size: var(--texto-7);
  font-weight: 700;
  text-align: center;
  letter-spacing: -0.02em;
}

/* Alternador de despesa e receita */
.alternador {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--espaco-1);
  padding: var(--espaco-1);
  border-radius: var(--raio-pequeno);
  background: var(--elevado);
}

.alternador button {
  padding: var(--espaco-4);
  border-radius: calc(var(--raio-pequeno) - 2px);
  font-size: var(--texto-3);
  font-weight: 600;
  color: var(--texto-suave);
  transition: background var(--medio) var(--curva), color var(--medio) var(--curva);
}

.alternador button[aria-pressed="true"] {
  background: var(--cartao);
  box-shadow: var(--sombra);
}

.alternador button[aria-pressed="true"][data-tipo="despesa"] { color: var(--despesa); }
.alternador button[aria-pressed="true"][data-tipo="receita"] { color: var(--receita); }
/* Transferencia nao e verde nem vermelha: o dinheiro so trocou de conta. */
.alternador button[aria-pressed="true"][data-tipo="transferencia"] { color: var(--primaria); }

/* O atributo hidden perde para qualquer display declarado por classe, e aqui
   quase todo componente declara o seu. Sem esta linha, `elemento.hidden = true`
   nao esconde nada num elemento com classe, e o bloco fica na tela achando que
   sumiu. Achado em 22/08, escondendo categoria no modo de transferencia. */
[hidden] {
  display: none !important;
}

/* --------------------------------------------------------------------------
   Botoes
   -------------------------------------------------------------------------- */
.botao {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--espaco-3);
  min-height: 2.875rem;
  padding: 0 1.25rem;
  border-radius: var(--raio-pequeno);
  font-size: var(--texto-4);
  font-weight: 600;
  transition: transform var(--medio) var(--mola), box-shadow var(--medio) var(--curva),
              opacity var(--rapido) ease, background var(--rapido) ease;
}

.botao:active:not(:disabled) {
  transform: scale(0.98);
}

.botao:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.botao-primario {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  color: var(--primaria-texto);
  background: linear-gradient(135deg, var(--primaria), var(--acento));
  box-shadow: var(--brilho-primaria);
}

/* Reflexo que atravessa uma vez, ao passar o mouse. O brilho e pseudo-elemento
   inclinado: nao existe ate ser preciso e nao mexe na caixa do botao. */
.botao-primario::after {
  content: "";
  position: absolute;
  inset-block: -50%;
  inset-inline-start: -60%;
  width: 40%;
  background: linear-gradient(100deg, transparent, rgb(255 255 255 / 0.3), transparent);
  transform: skewX(-18deg) translateX(-140%);
  pointer-events: none;
  opacity: 0;
}

.botao-primario:hover::after {
  animation: atravessar var(--lento) var(--curva);
}

.botao:hover:not(:disabled) {
  transform: translateY(-1px);
}

.botao:active:not(:disabled) {
  transform: translateY(0) scale(0.97);
}

.botao:disabled {
  box-shadow: none;
}

.botao-contorno {
  border: 1px solid var(--borda);
  background: var(--cartao);
}

.botao-perigo {
  color: var(--despesa);
  border: 1px solid color-mix(in oklab, var(--despesa) 30%, transparent);
  background: color-mix(in oklab, var(--despesa) 8%, transparent);
}

.botao-largo {
  width: 100%;
}

.botao-icone {
  display: grid;
  place-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--raio-pequeno);
  color: var(--texto-suave);
}

.botao-icone:active {
  background: var(--elevado);
}

/* Atalhos de audio e foto, visiveis e desabilitados ate a onda 3 */
.atalhos-ia {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-pequeno);
}

.atalho-ia {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--espaco-3);
  min-height: 2.75rem;
  border: 1px dashed var(--borda);
  border-radius: var(--raio-pequeno);
  color: var(--texto-suave);
  font-size: var(--texto-2);
  font-weight: 500;
}

.atalho-ia:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* --------------------------------------------------------------------------
   Estado vazio, aviso e carregamento
   -------------------------------------------------------------------------- */
.estado-vazio {
  display: grid;
  justify-items: center;
  gap: var(--espaco-4);
  padding: var(--gap-grande);
  text-align: center;
  border: 1px dashed var(--borda);
  border-radius: var(--raio);
  color: var(--texto-suave);
}

.estado-vazio-titulo {
  font-size: var(--texto-4);
  font-weight: 600;
  color: var(--texto);
}

.aviso {
  padding: 0.75rem var(--gap);
  border-radius: var(--raio-pequeno);
  font-size: var(--texto-2);
}

.aviso-erro {
  background: color-mix(in oklab, var(--despesa) 12%, transparent);
  color: var(--despesa);
}

.aviso-ok {
  background: color-mix(in oklab, var(--receita) 14%, transparent);
  color: var(--receita);
}

.aviso:empty {
  display: none;
}

/* Brilho que atravessa, no lugar de piscar. Piscar sinaliza erro; brilho que
   corre sinaliza que algo esta vindo, que e o que um esqueleto quer dizer. */
.esqueleto {
  position: relative;
  overflow: hidden;
  border-radius: var(--raio-pequeno);
  background: var(--elevado);
}

.esqueleto::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 20%,
              color-mix(in oklab, var(--texto) 7%, transparent) 50%, transparent 80%);
  transform: translateX(-100%);
  animation: varrer 1.5s var(--curva) infinite;
}

@keyframes varrer {
  to { transform: translateX(100%); }
}

/* Entrada escalonada de lista e de bloco de painel.
   O atraso sai de nth-child, e nao de uma variavel escrita no elemento: assim
   o efeito vale para as vinte telas sem nenhum modulo precisar mudar. Para de
   escalonar no decimo item, porque lista de duzentas linhas terminaria de
   entrar meio minuto depois de abrir. */
.lista-item,
.painel-bloco {
  animation: entrar var(--medio) var(--curva) backwards;
}

.lista-item:nth-child(2),  .painel-bloco:nth-child(2)  { animation-delay: 40ms; }
.lista-item:nth-child(3),  .painel-bloco:nth-child(3)  { animation-delay: 80ms; }
.lista-item:nth-child(4),  .painel-bloco:nth-child(4)  { animation-delay: 120ms; }
.lista-item:nth-child(5),  .painel-bloco:nth-child(5)  { animation-delay: 160ms; }
.lista-item:nth-child(6),  .painel-bloco:nth-child(6)  { animation-delay: 200ms; }
.lista-item:nth-child(7),  .painel-bloco:nth-child(7)  { animation-delay: 240ms; }
.lista-item:nth-child(8),  .painel-bloco:nth-child(8)  { animation-delay: 280ms; }
.lista-item:nth-child(n + 9),
.painel-bloco:nth-child(n + 9) { animation-delay: 320ms; }

/* Bloco de painel responde ao toque, porque em modo de edicao ele e alvo. */
.painel-bloco {
  transition: box-shadow var(--medio) var(--curva), transform var(--medio) var(--curva);
}

.painel-bloco:hover {
  box-shadow: var(--sombra-2);
}

/* --------------------------------------------------------------------------
   Folha inferior, usada para criar e editar
   -------------------------------------------------------------------------- */
.folha {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  align-items: end;
}

.folha-fundo {
  position: absolute;
  inset: 0;
  background: oklch(0% 0 0 / 0.5);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

.folha-painel {
  position: relative;
  max-height: 88dvh;
  overflow-y: auto;
  padding: var(--gap) var(--gap) calc(var(--gap) + env(safe-area-inset-bottom, 0px));
  border-radius: var(--raio-grande) var(--raio-grande) 0 0;
  background: var(--fundo);
  animation: subir var(--medio) var(--mola);
}

@keyframes subir {
  from { transform: translateY(12px); opacity: 0; }
}

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

/* Grade do painel configuravel.
   Tres colunas no desktop, e o bloco escolhe span de 1 a 3. No celular vira
   coluna unica: grafico espremido em um terco de tela nao informa nada, entao
   a largura escolhida vale onde ela cabe. */
.painel-grade {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap);
  margin-top: var(--gap);
}

.painel-bloco {
  min-width: 0;
  /* Sombra so no toque do ponteiro. Borda mais sombra em vinte blocos ao mesmo
     tempo e moldura demais para dado nenhum: o cartao tem que sumir e deixar o
     grafico aparecer. */
  box-shadow: none;
  transition: border-color var(--medio) var(--curva), box-shadow var(--medio) var(--curva);
}

@media (hover: hover) {
  .painel-bloco:hover {
    border-color: color-mix(in oklab, var(--primaria) 35%, var(--borda));
    box-shadow: var(--sombra-1);
  }
}

/* --------------------------------------------------------------------------
   Arrastar bloco no modo de edicao
   -------------------------------------------------------------------------- */
.painel-grade.arrastando-bloco {
  /* Sem isso o dedo rola a pagina em vez de arrastar o bloco, e no
     computador o arrasto vira selecao de texto. */
  touch-action: none;
  user-select: none;
  cursor: grabbing;
}

/* A mao aberta so aparece em modo de edicao: fora dele o bloco nao se move, e
   prometer arrasto que nao acontece e pior que nao prometer. */
.painel-grade.editando .painel-bloco {
  cursor: grab;
}

.painel-bloco.arrastando {
  cursor: grabbing;
  opacity: 0.9;
  transform: scale(1.02);
  box-shadow: var(--sombra-3);
  border-color: var(--primaria);
  /* Acima dos vizinhos enquanto passa por cima deles. */
  position: relative;
  z-index: 5;
}

/* Os vizinhos deslizam para o lugar novo, em vez de pularem. */
.painel-grade.editando .painel-bloco:not(.arrastando) {
  transition: transform var(--medio) var(--curva);
}

@media (prefers-reduced-motion: reduce) {
  .painel-bloco.arrastando {
    transform: none;
  }

  .painel-grade.editando .painel-bloco:not(.arrastando) {
    transition: none;
  }
}

/* A quina de redimensionar. So em modo de edicao, e so onde ha grade de doze
   avos: no celular existe uma coluna, e arrastar a quina nao teria destino. */
.pegador-bloco {
  display: none;
}

@media (min-width: 64rem) {
  .painel-grade.editando .pegador-bloco {
    display: block;
    position: absolute;
    right: 2px;
    bottom: 2px;
    width: 1.25rem;
    height: 1.25rem;
    cursor: ew-resize;
    touch-action: none;
    border-radius: 0 0 var(--raio) 0;
    /* Duas riscas na diagonal, como toda quina de redimensionar. */
    background:
      linear-gradient(135deg, transparent 45%, var(--borda) 45%, var(--borda) 55%, transparent 55%),
      linear-gradient(135deg, transparent 70%, var(--borda) 70%, var(--borda) 80%, transparent 80%);
  }

  .painel-grade.editando .painel-bloco {
    position: relative;
  }

  .painel-grade.editando .painel-bloco:hover .pegador-bloco {
    background:
      linear-gradient(135deg, transparent 45%, var(--primaria) 45%, var(--primaria) 55%, transparent 55%),
      linear-gradient(135deg, transparent 70%, var(--primaria) 70%, var(--primaria) 80%, transparent 80%);
  }
}

/* Titulo de bloco: caixa alta com espacamento de letra le como cabecalho de
   relatorio antigo. Aqui o titulo e uma frase, e o que precisa de peso e o
   numero embaixo dele. */
.bloco-titulo {
  margin: 0;
  font-size: var(--texto-3);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--texto);
}

/* --------------------------------------------------------------------------
   Bloco de valor

   Ele nao e um grafico com um numero dentro: e um bloco de outra especie, e
   por isso tem altura propria. Igualado ao bloco de grafico, sobrava um palmo
   de branco embaixo do numero e a grade inteira parecia frouxa.
   -------------------------------------------------------------------------- */
.bloco-valor {
  display: grid;
  gap: var(--espaco-1);
  align-content: start;
}

.bloco-valor-numero {
  font-size: var(--texto-6);
  line-height: 1.1;
  font-weight: 700;
  /* Numero grande usa figura proporcional: com tabular, 121 fica solto em
     tamanho de display. A tabular fica para coluna de tabela, que precisa
     alinhar. */
  font-variant-numeric: proportional-nums;
}

/* Doze avos, e nao tercos.
   Com tres colunas todo bloco era um terco, dois tercos ou a linha inteira, e
   o painel tinha o mesmo ritmo em toda linha. Doze divide por 2, 3, 4 e 6:
   cabem um quarto, um terco, metade e dois tercos, e uma linha pode ter tres
   tamanhos diferentes. */
@media (min-width: 64rem) {
  .painel-grade {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    /* Cada bloco com a altura que ele precisa, e nao a do vizinho mais alto.
       Esticado, um bloco de numero ao lado de um grafico ficava com um vao de
       branco embaixo, e era esse vao que fazia a grade parecer frouxa. */
    align-items: start;
  }
}

/* Entre o celular e o computador o painel vira duas colunas: doze avos numa
   tela de tablet dariam blocos de largura de dedo. O bloco estreito ocupa
   metade e o largo ocupa a linha. */
@media (min-width: 48rem) and (max-width: 63.99rem) {
  .painel-grade {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }

  .painel-bloco {
    grid-column: span 1 !important;
  }

  .painel-bloco[data-largura-larga] {
    grid-column: span 2 !important;
  }
}

@media (max-width: 47.99rem) {
  /* No celular o span escolhido nao vale: so existe uma coluna. */
  .painel-bloco {
    grid-column: span 1 !important;
  }
}

/* Linha de botoes de acao, acima ou abaixo de uma grade.
   Quebra em varias linhas no celular em vez de rolar de lado: botao que so
   aparece rolando e botao que ninguem encontra. */
.barra-acoes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espaco-3);
  align-items: center;
  margin-top: var(--espaco-4);
}

.barra-acoes .botao {
  flex: 0 1 auto;
}

/* Barra de filtros das grades de ano inteiro.
   Quebra em quantas colunas couberem, em vez de rolar de lado como os filtros
   do extrato: sao oito campos, e um filtro que so aparece rolando e um filtro
   que ninguem usa. */
.filtros-grade {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--espaco-4);
  align-items: end;
}

.filtros-grade select,
.filtros-grade input {
  min-height: 2.5rem;
}

/* --------------------------------------------------------------------------
   Filtros do extrato
   -------------------------------------------------------------------------- */
.filtros {
  display: flex;
  gap: var(--espaco-3);
  overflow-x: auto;
  padding-bottom: 0.25rem;
  scrollbar-width: none;
}

.filtros::-webkit-scrollbar {
  display: none;
}

.filtros select,
.filtros input {
  flex-shrink: 0;
  min-height: 2.25rem;
  padding: 0 0.625rem;
  border: 1px solid var(--borda);
  border-radius: 999px;
  background: var(--cartao);
  color: var(--texto);
  font-size: var(--texto-2);
}

/* Seletor de mes */
.seletor-mes {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-pequeno);
  padding: var(--espaco-2);
  border-radius: var(--raio-pequeno);
  background: var(--elevado);
}

.seletor-mes-nome {
  font-size: var(--texto-3);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   Arvore de categorias
   -------------------------------------------------------------------------- */
.categoria-pai {
  display: flex;
  align-items: center;
  gap: var(--espaco-4);
  padding: 0.75rem var(--gap);
  font-weight: 600;
  font-size: var(--texto-4);
  border-bottom: 1px solid var(--borda);
}

.categoria-filha {
  display: flex;
  align-items: center;
  gap: var(--espaco-4);
  padding: 0.625rem var(--gap) 0.625rem 3.25rem;
  font-size: var(--texto-3);
  border-bottom: 1px solid var(--borda);
}

.categoria-ponto {
  flex-shrink: 0;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
}

/* ==========================================================================
   Desktop
   Mobile first nao quer dizer mobile so. A partir de 64rem a barra inferior
   vira lateral, o polegar deixa de ser a restricao e o cursor assume.
   Os modulos sao exatamente os mesmos: muda o enquadramento, nao o codigo.
   ========================================================================== */
@media (min-width: 64rem) {
  :root {
    --largura-lateral: 15rem;
    --altura-nav: 0px;
  }

  .app-corpo {
    padding-bottom: var(--gap-grande);
    padding-inline-start: var(--largura-lateral);
  }

  /* A barra sai de baixo e vai para a lateral */
  .nav-inferior {
    inset-inline-end: auto;
    top: 0;
    bottom: 0;
    width: var(--largura-lateral);
    height: 100dvh;
    grid-template-columns: 1fr;
    align-content: start;
    gap: var(--espaco-1);
    padding: var(--gap) 0.75rem;
    border-top: 0;
    border-inline-end: 1px solid var(--borda);
  }

  /* Item deixa de ser icone com legenda embaixo e vira linha com texto ao lado */
  .nav-item {
    grid-template-columns: auto 1fr;
    justify-items: start;
    align-items: center;
    gap: var(--espaco-4);
    padding: 0.625rem 0.75rem;
    border-radius: var(--raio-pequeno);
    font-size: var(--texto-4);
    font-weight: 500;
  }

  .nav-item:hover {
    background: var(--elevado);
    color: var(--texto);
  }

  .nav-item[aria-current="page"] {
    background: color-mix(in oklab, var(--primaria) 12%, transparent);
  }

  .nav-item svg {
    width: 1.25rem;
    height: 1.25rem;
  }

  .nav-so-lateral {
    display: grid;
  }

  /* Separa os cinco de sempre dos atalhos. Sem a linha, onze itens iguais
     viram uma lista sem hierarquia. */
  .nav-separador {
    display: block;
    height: 1px;
    margin: var(--espaco-3) 0.75rem;
    background: var(--borda);
  }

  /* A lateral pode passar da altura da tela com onze itens numa janela baixa. */
  .nav-inferior {
    overflow-y: auto;
    scrollbar-width: thin;
  }

  /* Lancar sobe para o topo da lateral e vira botao com rotulo.
     No celular ele e o circulo elevado no centro porque ali o alcance do
     polegar manda. Aqui nao existe polegar, entao vale a hierarquia visual. */
  .nav-central {
    order: -1;
    justify-self: stretch;
    display: grid;
    grid-template-columns: auto 1fr;
    place-content: start;
    align-items: center;
    gap: var(--espaco-4);
    width: auto;
    height: auto;
    margin: 0 0 var(--gap-pequeno);
    padding: 0.75rem 0.875rem;
    border-radius: var(--raio-pequeno);
    font-size: var(--texto-4);
    font-weight: 600;
  }

  .nav-central svg {
    width: 1.125rem;
    height: 1.125rem;
  }

  .nav-central-rotulo {
    display: block;
    text-align: start;
  }

  /* O assistente sobe para logo abaixo de Lancar e ganha borda na cor do
     app. Entre onze atalhos iguais ele sumia, e e a segunda porta de entrada. */
  .nav-assistente {
    order: -1;
    margin-bottom: var(--gap-pequeno);
    border: 1px solid color-mix(in oklab, var(--primaria) 45%, var(--borda));
    background: color-mix(in oklab, var(--primaria) 8%, transparent);
    color: var(--primaria);
    font-weight: 600;
  }

  .nav-assistente:hover {
    background: color-mix(in oklab, var(--primaria) 14%, transparent);
    color: var(--primaria);
  }

  /* Na lateral o botao flutuante fica no canto da area de conteudo, e nao
     no canto da janela: a lateral e um lugar diferente. */
  .botao-flutuante {
    right: var(--gap-grande);
    bottom: var(--gap-grande);
  }

  /* Cabecalho e conteudo acompanham a lateral */
  .app-cabecalho {
    padding-inline: var(--gap-grande);
    min-height: 4rem;
  }

  .app-tela {
    max-width: 52rem;
    padding: var(--gap-grande);
    gap: var(--gap-grande);
  }

  /* Com largura sobrando, quatro metricas cabem em linha */
  .painel-destaque .metricas {
    grid-template-columns: repeat(4, 1fr);
  }

  /* A folha inferior deixa de subir de baixo e vira dialogo centralizado */
  .folha {
    align-items: center;
    justify-items: center;
  }

  .folha-painel {
    width: min(32rem, 92vw);
    max-height: 82dvh;
    border-radius: var(--raio-grande);
    animation: aparecer var(--medio) var(--mola);
  }

  @keyframes aparecer {
    from { transform: scale(0.97); opacity: 0; }
  }
}

/* Tela larga de verdade, para as grades de ano inteiro que chegam na onda 7.
   Quem quiser a largura toda pede por classe, em vez de todo modulo herdar
   uma medida boa para tabela e ruim para formulario. */
@media (min-width: 64rem) {
  .app-tela.tela-larga {
    max-width: none;
  }

  /* Meio termo entre as 52rem de leitura e a largura toda. O Inicio pede esta
     medida: com 52rem, os tres graficos da carteira ficam com 250px cada e o
     rotulo da barra nao cabe. Com teto nenhum, num monitor largo, cinco cards
     de conta viram cinco faixas vazias. */
  .app-tela.tela-ampla {
    max-width: 80rem;
  }
}

/* Quadrado da visao anual que abre a folha da celula.
   Precisa parecer clicavel sem ganhar peso: sao ate 24 quadrados por linha, e
   qualquer borda ou fundo permanente transformaria a grade em xadrez. O sinal
   so aparece sob o cursor e sob o foco de teclado. */
.celula-abrivel {
  cursor: pointer;
}

.celula-abrivel:hover {
  background: color-mix(in oklab, var(--primaria) 14%, transparent);
}

.celula-abrivel:focus-visible {
  outline: 2px solid var(--primaria);
  outline-offset: -2px;
}

/* Botao de gravar audio da tela de IA.
   Classe propria de proposito. Antes ele emprestava a `.nav-central`, e no
   desktop a media query que transforma a navegacao em barra lateral vinha
   junto: o microfone virava um retangulo colado na esquerda, com o icone no
   canto. Botao que nao e de navegacao nao veste roupa de navegacao. */
.botao-microfone {
  display: grid;
  place-content: center;
  width: 5rem;
  height: 5rem;
  border-radius: 50%;
  color: var(--primaria-texto);
  box-shadow: 0 6px 20px color-mix(in oklab, var(--primaria) 40%, transparent);
  transition: transform var(--medio) var(--mola);
}

.botao-microfone:active {
  transform: scale(0.94);
}

.botao-microfone svg {
  width: 1.875rem;
  height: 1.875rem;
}

/* Pulsando enquanto grava */
.botao-microfone.gravando {
  background: linear-gradient(135deg, var(--despesa), var(--aviso));
  animation: pulsar-gravacao 1.4s ease-in-out infinite;
}

@keyframes pulsar-gravacao {
  0%, 100% { box-shadow: 0 6px 20px color-mix(in oklab, var(--despesa) 40%, transparent); }
  50%      { box-shadow: 0 6px 32px color-mix(in oklab, var(--despesa) 75%, transparent); }
}

/* --------------------------------------------------------------------------
   Area de soltar arquivo

   Arrastar arquivo e gesto de computador: no celular nao existe, e a dica em
   texto so aparece onde ha ponteiro fino. A borda tracejada permanente diria
   "solte aqui" o tempo todo, inclusive num aparelho onde isso e impossivel,
   entao ela so nasce quando o arquivo esta no ar.
   -------------------------------------------------------------------------- */
.zona-arrasto {
  position: relative;
  border-radius: var(--raio-pequeno);
  transition: background var(--rapido) ease, box-shadow var(--rapido) ease;
}

.zona-arrasto.arrastando {
  background: color-mix(in oklab, var(--primaria) 8%, transparent);
  box-shadow: 0 0 0 2px var(--primaria);
}

/* Com ponteiro fino a zona ganha borda tracejada, para dizer que aceita
   arquivo antes de alguem arrastar. No celular a borda seria promessa vazia. */
@media (hover: hover) and (pointer: fine) {
  .zona-arrasto { border: 1.5px dashed var(--borda); }
  .zona-arrasto.arrastando { border-color: var(--primaria); }
}

/* A dica pertence a area, e nao a cada tela: escrever o texto em cada uma
   deixaria quatro copias para desatualizar. */
.zona-arrasto .dica-arrasto {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .zona-arrasto .dica-arrasto {
    display: block;
  }
}

.zona-arrasto.arrastando .dica-arrasto {
  color: var(--primaria);
}

/* A area de soltar da folha de Lancar. So existe com ponteiro fino: no
   celular nao ha o que arrastar, e um retangulo tracejado ali seria promessa
   vazia. Acende quando um arquivo passa por cima da folha. */
.solte-aqui {
  display: none;
  align-items: center;
  gap: var(--espaco-4);
  margin-top: var(--gap-pequeno);
  padding: var(--espaco-4) var(--espaco-5);
  border: 1.5px dashed var(--borda);
  border-radius: var(--raio-pequeno);
  color: var(--texto-suave);
  font-size: var(--texto-2);
  line-height: 1.45;
  transition: border-color var(--rapido) ease, background var(--rapido) ease, color var(--rapido) ease;
}

.solte-aqui strong { color: var(--texto); font-weight: 600; }
.solte-aqui svg { flex-shrink: 0; }

@media (hover: hover) and (pointer: fine) {
  .solte-aqui { display: flex; }
}

.solte-aqui.arrastando {
  border-color: var(--primaria);
  background: color-mix(in oklab, var(--primaria) 8%, transparent);
  color: var(--primaria);
}

/* --------------------------------------------------------------------------
   Grades: pegador de largura, ordenacao e dobra

   As quatro tabelas do app usam os mesmos gestos, entao o estilo mora aqui e
   nao no estilo inline de cada uma.
   -------------------------------------------------------------------------- */
.pegador-coluna {
  position: absolute;
  top: 0;
  right: 0;
  width: 0.5rem;
  height: 100%;
  cursor: col-resize;
  touch-action: none;
  user-select: none;
}

.pegador-coluna::after {
  content: '';
  position: absolute;
  top: 20%;
  right: 2px;
  width: 2px;
  height: 60%;
  border-radius: 999px;
  background: transparent;
  transition: background var(--rapido) ease;
}

.pegador-coluna:hover::after,
.redimensionando .pegador-coluna::after {
  background: var(--primaria);
}

/* Enquanto arrasta, o texto nao pode ser selecionado nem a celula ordenar. */
.redimensionando {
  user-select: none;
  cursor: col-resize;
}

.coluna-ordenavel {
  cursor: pointer;
  user-select: none;
}

.coluna-ordenavel:hover {
  color: var(--primaria);
}

/* A seta de ordem ocupa lugar sempre, para a coluna nao pular de largura ao
   ser ordenada pela primeira vez. */
.coluna-ordenavel::before {
  content: '';
  display: inline-block;
  width: 0.75em;
  margin-right: 0.125em;
  font-size: 0.75em;
  opacity: 0.75;
}

.coluna-ordenavel[data-ordem='crescente']::before {
  content: '▲';
}

.coluna-ordenavel[data-ordem='decrescente']::before {
  content: '▼';
}

/* A celula do grupo vira uma linha: seta, e o que a tela ja tinha posto ali.
   O embrulho existe porque mudar o display do proprio td o tiraria do modelo
   de tabela, levando junto a coluna grudada. */
.grupo-cabeca {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.seta-dobra {
  flex-shrink: 0;
  border: 0;
  background: none;
  /* Alvo de toque decente sem empurrar a linha: o padding vertical some no
     alinhamento da linha flex. */
  padding: 0.25rem;
  margin: 0 -0.125rem 0 -0.25rem;
  color: inherit;
  font: inherit;
  font-size: 0.8em;
  line-height: 1;
  cursor: pointer;
  opacity: 0.65;
  transition: opacity var(--rapido) ease, color var(--rapido) ease;
}

.seta-dobra:hover,
.seta-dobra:focus-visible {
  opacity: 1;
  color: var(--primaria);
}

/* --------------------------------------------------------------------------
   Leitura do que a celula e: entrada, saida, movimento neutro, e o tempo

   Cor diz a natureza do dinheiro e o tempo diz se ja aconteceu. Sao dois eixos
   diferentes, e por isso um e cor e o outro e peso e traco: usar cor para os
   dois deixaria "receita prevista" indistinguivel de "despesa realizada".
   -------------------------------------------------------------------------- */
.celula-receita {
  color: var(--receita);
}

.celula-despesa {
  color: var(--despesa);
}

/* Transferencia, aporte e resgate ficam sem cor de propósito: o dinheiro
   mudou de lugar, e o patrimonio nao mudou. */
.celula-neutra {
  color: var(--texto-suave);
}

/* Ainda nao aconteceu: traco pontilhado embaixo, como numero provisorio. */
.celula-futura {
  opacity: 0.7;
  border-bottom: 1px dotted currentColor !important;
}

/* Ja foi conferido contra o extrato do banco. */
.celula-conciliada {
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   Menu de contexto das grades

   Desenhado, e nao o do sistema: o do navegador nao aceita item proprio. Fica
   em position: fixed porque o ponto vem do cursor, que e coordenada de tela, e
   nao do documento.
   -------------------------------------------------------------------------- */
.menu-contexto {
  position: fixed;
  z-index: 60;
  min-width: 12rem;
  padding: var(--espaco-2);
  display: grid;
  gap: 2px;
  border: 1px solid var(--borda);
  border-radius: var(--raio-pequeno);
  background: var(--cartao);
  box-shadow: var(--sombra-2);
  animation: menu-entra var(--rapido) var(--curva);
}

@keyframes menu-entra {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

.menu-contexto button {
  display: grid;
  gap: 1px;
  justify-items: start;
  text-align: left;
  width: 100%;
  padding: 0.5rem 0.625rem;
  border: 0;
  border-radius: var(--raio-pequeno);
  background: none;
  color: var(--texto);
  font: inherit;
  font-size: var(--texto-3);
  cursor: pointer;
}

.menu-contexto button:hover,
.menu-contexto button:focus-visible {
  background: var(--elevado);
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  .menu-contexto {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   Graficos

   A dica aparece no hover e no foco, e a camada dela e desenhada por ultimo no
   SVG: nao ha z-index em SVG, quem vem depois fica por cima.
   -------------------------------------------------------------------------- */
.grafico .g-dica {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--rapido) ease;
}

.grafico .g-alvo:hover .g-dica,
.grafico .g-alvo:focus-visible .g-dica {
  opacity: 1;
}

/* Sem ponteiro fino nao ha hover, e a dica so apareceria presa depois do
   toque. O valor continua na tabela e no rotulo direto. */
@media (hover: none) {
  .grafico .g-dica {
    display: none;
  }
}

.grafico text {
  font-family: inherit;
  font-variant-numeric: tabular-nums;
}

.grafico-legenda {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espaco-3) var(--espaco-5);
  margin-top: var(--espaco-3);
}

.legenda-item {
  display: flex;
  align-items: center;
  gap: var(--espaco-2);
  /* O item nao pode passar da largura do bloco: com "Home 2 Invest
     Participacoes Ltda" o percentual saia da moldura e ficava cortado pela
     metade. O nome encolhe com reticencias e o numero fica inteiro. */
  max-width: 100%;
  min-width: 0;
}

.legenda-marca {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.legenda-nome {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

@media (prefers-reduced-motion: reduce) {
  .grafico .g-dica {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   Grafico que responde

   Tres coisas moram aqui: a marca que se sabe clicavel, o menu que o toque
   longo abre, e a entrada em 3D.

   O 3D e de CSS, sem biblioteca: `perspective` mais `rotateX` dao profundidade
   de verdade, com a placa girando para o lugar, e custam zero byte de download
   num app que nao tem nenhuma dependencia. A alternativa era WebGL, e num PWA
   que abre no celular alheio isso e bateria e megabyte por enfeite.
   -------------------------------------------------------------------------- */
.grafico .g-clicavel {
  cursor: pointer;
  outline: none;
}

/* A fatia cresce a partir do proprio centro, e nao empurra a vizinha */
.grafico .g-clicavel:hover .g-fatia,
.grafico .g-clicavel:focus-visible .g-fatia {
  stroke-width: 130%;
  filter: brightness(1.08);
}

.grafico .g-clicavel .g-fatia {
  transition: stroke-width var(--rapido) ease, filter var(--rapido) ease;
}

.grafico .g-clicavel:hover .g-coluna,
.grafico .g-clicavel:hover .g-barra,
.grafico .g-clicavel:focus-visible .g-coluna,
.grafico .g-clicavel:focus-visible .g-barra {
  filter: brightness(1.12);
}

.grafico .g-clicavel:focus-visible rect[fill="transparent"] {
  stroke: var(--primaria);
  stroke-width: 2;
  rx: 6;
}

/* No toque nao ha hover, entao a dica so faria sentido presa depois do dedo.
   Ela aparece enquanto o dedo esta em cima, e sai quando ele levanta. */
@media (hover: none) {
  .grafico .g-alvo:active .g-dica {
    display: block;
    opacity: 1;
  }
}

/* --------------------------------------------------------------------------
   Menu do grafico
   -------------------------------------------------------------------------- */
.menu-grafico {
  position: fixed;
  z-index: 90;
  min-width: 13rem;
  padding: var(--espaco-2);
  border-radius: var(--raio-grande);
  background: var(--cartao);
  border: 1px solid var(--borda);
  box-shadow: var(--sombra-3);
  display: grid;
  gap: 2px;
  opacity: 0;
  transform: perspective(600px) rotateX(-8deg) translateY(-6px);
  transform-origin: top center;
  transition: opacity var(--rapido) ease, transform var(--rapido) ease;
}

.menu-grafico.aberto {
  opacity: 1;
  transform: none;
}

.menu-grafico button {
  display: flex;
  align-items: center;
  gap: var(--espaco-3);
  width: 100%;
  padding: var(--espaco-3) var(--espaco-3);
  border: 0;
  border-radius: var(--raio);
  background: transparent;
  color: var(--texto);
  font: inherit;
  font-size: var(--texto-2);
  text-align: left;
  cursor: pointer;
  min-height: 2.5rem;
}

.menu-grafico button:hover,
.menu-grafico button:focus-visible {
  background: var(--fundo);
  outline: none;
}

.menu-grafico button svg {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  color: var(--texto-suave);
}

/* --------------------------------------------------------------------------
   Entrada em 3D

   A placa chega inclinada e se endireita, e as marcas crescem depois dela: a
   coluna sobe da linha zero, a barra abre da esquerda, a fatia se desenha no
   sentido do relogio. A cascata entre blocos vem de --ordem, que o painel
   escreve em cada bloco.
   -------------------------------------------------------------------------- */
@keyframes entra-placa {
  from {
    opacity: 0;
    transform: perspective(900px) rotateX(14deg) translate3d(0, 14px, -60px);
  }
  to {
    opacity: 1;
    transform: perspective(900px) rotateX(0) translate3d(0, 0, 0);
  }
}

@keyframes sobe-coluna { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes abre-barra  { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes desenha-fatia { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }

.bloco-anima {
  animation: entra-placa .5s cubic-bezier(.22, 1, .36, 1) backwards;
  animation-delay: calc(var(--ordem, 0) * 45ms);
}

.bloco-anima .g-coluna {
  transform-box: fill-box;
  transform-origin: bottom;
  animation: sobe-coluna .45s cubic-bezier(.22, 1, .36, 1) backwards;
  animation-delay: calc(var(--ordem, 0) * 45ms + 120ms);
}

.bloco-anima .g-barra {
  transform-box: fill-box;
  transform-origin: left;
  animation: abre-barra .45s cubic-bezier(.22, 1, .36, 1) backwards;
  animation-delay: calc(var(--ordem, 0) * 45ms + 120ms);
}

/* O `pathLength="100"` do path e o que faz este traco funcionar: com ele o
   arco inteiro mede 100 unidades, qualquer que seja o raio, e o mesmo keyframe
   serve para fatia de qualquer tamanho.
   Sem ele, `stroke-dasharray: 100` vira 100 pixels de traco e 100 de vao, e a
   fatia grande fica tracejada para sempre, porque o dasharray e propriedade do
   elemento e nao some quando a animacao acaba. Foi o que aconteceu quando a
   fatia "Outros" do gasto por categoria chegou a 64% do ano: 448px de arco
   viraram quatro pedacos com buraco entre eles. */
.bloco-anima .g-fatia {
  stroke-dasharray: 100;
  animation: desenha-fatia .7s cubic-bezier(.32, .72, .28, 1) backwards;
  animation-delay: calc(var(--ordem, 0) * 45ms + 100ms);
}

/* Quem pediu menos movimento no sistema recebe o grafico pronto, sem giro,
   sem crescimento e sem cascata. */
@media (prefers-reduced-motion: reduce) {
  .bloco-anima,
  .bloco-anima .g-coluna,
  .bloco-anima .g-barra,
  .bloco-anima .g-fatia {
    animation: none;
  }
  .menu-grafico { transition: none; }
}

/* Aviso rapido, para acao que nao abre tela: copiou, baixou. Some sozinho. */
.aviso-flutuante {
  position: fixed;
  left: 50%;
  bottom: calc(var(--espaco-6) + env(safe-area-inset-bottom, 0px) + 4rem);
  transform: translate(-50%, 1rem);
  z-index: 95;
  padding: var(--espaco-3) var(--espaco-5);
  border-radius: var(--raio-redondo);
  background: var(--texto);
  color: var(--fundo);
  font-size: var(--texto-2);
  box-shadow: var(--sombra-3);
  opacity: 0;
  transition: opacity var(--rapido) ease, transform var(--rapido) ease;
  pointer-events: none;
}

.aviso-flutuante.aberto {
  opacity: 1;
  transform: translate(-50%, 0);
}

@media (prefers-reduced-motion: reduce) {
  .aviso-flutuante { transition: none; }
}

/* --------------------------------------------------------------------------
   Inicio: metricas em quatro, cards e a fileira de graficos
   -------------------------------------------------------------------------- */
/* Quatro metricas em duas linhas no celular e uma no computador. Tres seguem
   a mesma regra. */
@media (min-width: 720px) {
  .metricas-4 { grid-template-columns: repeat(4, 1fr); }
  .metricas-3 { grid-template-columns: repeat(3, 1fr); }
}

/* O alternador de estilo cabe no cabecalho de secao: menor que o do Lancar,
   porque aqui ele escolhe um arranjo, e nao o tipo do dinheiro. */
.alternador-mini {
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
}

.alternador-mini button {
  padding: var(--espaco-2) var(--espaco-4);
  font-size: var(--texto-2);
}

/* Cards: a mesma informacao da lista, um item por caixa. Dois por linha no
   celular, e no computador quantos couberem com 200px cada. */
.cards-grade {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gap-pequeno);
}

@media (min-width: 720px) {
  .cards-grade {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  }
}

.card-item {
  display: grid;
  gap: var(--espaco-1);
  align-content: start;
  width: 100%;
  min-width: 0;
  padding: var(--espaco-5);
  border-radius: var(--raio);
  background: var(--cartao);
  border: 1px solid var(--borda);
  color: inherit;
  font: inherit;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--medio) var(--curva), box-shadow var(--medio) var(--curva),
              transform var(--medio) var(--curva);
}

@media (hover: hover) {
  .card-item:hover {
    border-color: color-mix(in oklab, var(--primaria) 35%, var(--borda));
    box-shadow: var(--sombra-1);
    transform: translateY(-1px);
  }
}

.card-item:active {
  transform: scale(0.99);
}

.card-rotulo {
  font-size: var(--texto-3);
  font-weight: 600;
  /* Duas linhas, e nao uma com reticencias: "CDB C6 Empresarial Pos-fixado 2
     anos" e "CDB C6 Empresarial Pos-Fixado Liquidez Diaria" cortam no mesmo
     ponto, e o card passa a nomear duas aplicacoes diferentes do mesmo jeito. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  /* Duas linhas de altura sempre, para os cards da fileira alinharem o valor */
  min-height: calc(var(--texto-3) * 2 * 1.35);
}

.card-apoio {
  font-size: var(--texto-1);
  color: var(--texto-suave);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-valor {
  margin-top: var(--espaco-2);
  font-family: var(--fonte-numero);
  font-variant-numeric: tabular-nums;
  font-size: var(--texto-5);
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* O card de aplicacao usa o bloco de valor do painel, com a linha do tempo
   atras do numero. O numero grande do bloco e grande demais para um card de
   duas colunas, entao aqui ele desce um degrau. */
.card-item .bloco-valor-numero {
  font-size: var(--texto-5);
}

/* Tres graficos lado a lado no computador, um por linha no celular. */
.inicio-graficos {
  display: grid;
  gap: var(--gap-pequeno);
}

@media (min-width: 900px) {
  .inicio-graficos {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.inicio-graficos .cartao {
  min-width: 0;
  box-shadow: none;
}

/* Item de lista que e botao: mesma cara da linha, e o cursor diz que abre. */
button.lista-item {
  cursor: pointer;
  color: inherit;
  font: inherit;
}

/* --------------------------------------------------------------------------
   Assistente: a conversa
   -------------------------------------------------------------------------- */
.sugestoes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espaco-3);
  margin-top: var(--gap-pequeno);
}

.chip-sugestao {
  padding: var(--espaco-3) var(--espaco-5);
  border-radius: 999px;
  border: 1px solid var(--borda);
  background: var(--elevado);
  font-size: var(--texto-2);
  color: var(--texto-suave);
  text-align: start;
  transition: border-color var(--medio) var(--curva), color var(--medio) var(--curva);
}

@media (hover: hover) {
  .chip-sugestao:hover {
    border-color: color-mix(in oklab, var(--primaria) 45%, var(--borda));
    color: var(--texto);
  }
}

.conversa {
  display: grid;
  /* minmax(0, 1fr), e nao a coluna implicita: a coluna implicita cresce ate o
     conteudo, e uma tabela larga numa resposta empurrava a bolha para fora da
     tela do celular. Com o minimo em zero, a tabela rola dentro da bolha. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap-pequeno);
}

/* Chips de continuacao, dentro da bolha da resposta. O respiro e o do corpo da
   mensagem, para o chip nascer alinhado com o texto que ele continua. */
.mensagem .continuacao {
  margin-top: var(--espaco-3);
  padding-inline: var(--espaco-3);
}

.mensagem {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  min-width: 0;
  /* A pergunta encosta à direita e a resposta à esquerda: sem isso as duas se
     confundem numa conversa longa, e reler quem disse o quê custa atenção. */
  max-width: min(46rem, 92%);
}

.mensagem-minha {
  justify-self: end;
  justify-items: end;
}

.mensagem-dele {
  justify-self: start;
}

.mensagem-corpo {
  min-width: 0;
  padding: var(--espaco-5) var(--gap);
  border-radius: var(--raio);
  background: var(--cartao);
  border: 1px solid var(--borda);
  font-size: var(--texto-3);
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.mensagem-minha .mensagem-corpo {
  background: color-mix(in oklab, var(--primaria) 12%, var(--cartao));
  border-color: color-mix(in oklab, var(--primaria) 28%, var(--borda));
}

.mensagem-corpo p {
  margin: 0 0 var(--espaco-4);
}

.mensagem-corpo p:last-child,
.mensagem-corpo ul:last-child {
  margin-bottom: 0;
}

.mensagem-corpo ul {
  margin: 0 0 var(--espaco-4);
  padding-inline-start: 1.25rem;
  display: grid;
  gap: var(--espaco-2);
}

.mensagem-corpo table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--texto-2);
}

.mensagem-corpo th,
.mensagem-corpo td {
  padding: var(--espaco-2) var(--espaco-3);
  border-bottom: 1px solid var(--borda);
  text-align: start;
}

/* Quem alinha à direita é a coluna que é número, decidida pelo conteúdo, e não
   "toda coluna menos a primeira": numa tabela "Categoria | Conta | Valor" a
   conta ficava encostada à direita como se fosse valor. */
.mensagem-corpo td.col-num,
.mensagem-corpo th.col-num {
  text-align: end;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tabela-copiavel {
  display: grid;
  gap: var(--espaco-1);
  margin: 0 0 var(--espaco-4);
}

.tabela-acoes {
  display: flex;
  justify-content: flex-end;
}

.tabela-acoes .link-acao {
  font-size: var(--texto-1);
}

.mensagem-fonte {
  margin-top: var(--espaco-2);
  padding-inline: var(--espaco-3);
}

.mensagem-fonte summary {
  cursor: pointer;
  list-style-position: outside;
}

/* Três pontos pulsando enquanto ele consulta. O aria-live anuncia o texto
   escondido, então quem usa leitor de tela não fica esperando em silêncio. */
.pensando {
  display: flex;
  gap: var(--espaco-3);
  align-items: center;
}

.pensando span:not(.visualmente-oculto) {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--texto-suave);
  animation: pulsa-ponto 1.2s ease-in-out infinite;
}

.pensando span:nth-child(2) { animation-delay: .18s; }
.pensando span:nth-child(3) { animation-delay: .36s; }

@keyframes pulsa-ponto {
  0%, 60%, 100% { opacity: .25; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

@media (prefers-reduced-motion: reduce) {
  .pensando span { animation: none; opacity: .5; }
}

/* A barra de pergunta gruda no fim da tela, acima da barra de navegação. */
.barra-pergunta {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: var(--espaco-3);
  align-items: flex-end;
  padding: var(--gap-pequeno) 0;
  background: linear-gradient(to top, var(--fundo) 70%, transparent);
}

.barra-pergunta textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  padding: var(--espaco-4) var(--espaco-5);
  border-radius: var(--raio);
  border: 1px solid var(--borda);
  background: var(--cartao);
  font-size: var(--texto-3);
  line-height: 1.5;
}

.barra-pergunta textarea:focus-visible {
  outline: none;
  border-color: var(--primaria);
  box-shadow: var(--anel-foco);
}

.barra-pergunta button {
  flex-shrink: 0;
  display: grid;
  place-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
}

.visualmente-oculto {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Início: os cinco números e os cards de destino
   --------------------------------------------------------------------------
   A cor de cada card vem de --grafico-1 a 5, sempre por color-mix e nunca
   chapada. Fundo translúcido de 10%, borda de 30%, ícone na cor cheia: assim o
   card se distingue do vizinho sem virar um bloco de cor sólida, e o texto
   continua legível com a mesma tinta em todos.

   Cada card declara --cor uma vez, e todo o resto deriva dela. Trocar o tema
   troca a paleta inteira sem tocar nestas regras. */
.cor-1 { --cor: var(--grafico-1); }
.cor-2 { --cor: var(--grafico-2); }
.cor-3 { --cor: var(--grafico-3); }
.cor-4 { --cor: var(--grafico-4); }
.cor-5 { --cor: var(--grafico-5); }

.home-topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
  flex-wrap: wrap;
}

.home-saudacao {
  font-size: var(--texto-6);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}

/* O botão do olho é a única ação do topo, então ele carrega o texto junto:
   um ícone sozinho ali obrigaria a descobrir o que ele faz tocando. */
.botao-olho {
  display: inline-flex;
  align-items: center;
  gap: var(--espaco-3);
  padding: var(--espaco-3) var(--espaco-5);
  border-radius: 999px;
  border: 1px solid var(--borda);
  background: var(--vidro);
  backdrop-filter: var(--vidro-borrao);
  -webkit-backdrop-filter: var(--vidro-borrao);
  font-size: var(--texto-2);
  font-weight: 600;
  color: var(--texto-suave);
  transition: border-color var(--medio) var(--curva), color var(--medio) var(--curva);
}

.botao-olho:hover { border-color: color-mix(in oklab, var(--primaria) 45%, var(--borda)); color: var(--texto); }

.olho-icone svg { width: 1.15rem; height: 1.15rem; display: block; }

/* O corte sobre o olho aparece quando está oculto, e se retrai ao revelar. O
   traço anima pelo próprio comprimento, então não há duas versões do ícone. */
.olho-corte {
  stroke-dasharray: 26;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--medio) var(--curva);
}

.botao-olho[aria-pressed="true"] .olho-corte { stroke-dashoffset: 26; }

/* Os cinco números */
.indicadores {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gap-pequeno);
}

@media (min-width: 48rem) {
  .indicadores { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 64rem) {
  .indicadores { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

.indicador {
  position: relative;
  display: grid;
  gap: var(--espaco-2);
  align-content: start;
  padding: var(--gap);
  border-radius: var(--raio);
  border: 1px solid color-mix(in oklab, var(--cor) 30%, transparent);
  background:
    linear-gradient(155deg,
      color-mix(in oklab, var(--cor) 14%, transparent) 0%,
      color-mix(in oklab, var(--cor) 5%, transparent) 60%,
      transparent 100%),
    var(--vidro);
  backdrop-filter: var(--vidro-borrao);
  -webkit-backdrop-filter: var(--vidro-borrao);
  color: inherit;
  text-decoration: none;
  overflow: hidden;
  animation: entra-card .5s cubic-bezier(.22, 1, .36, 1) backwards;
  animation-delay: calc(var(--ordem, 0) * 60ms);
  transition: transform var(--medio) var(--curva), border-color var(--medio) var(--curva);
}

/* O brilho que passa pela quina superior. Fica no ::before para não pesar o
   layout: é composição pura, e some junto com o card. */
.indicador::before {
  content: '';
  position: absolute;
  inset: -40% -10% auto -10%;
  height: 120%;
  background: radial-gradient(60% 50% at 30% 0%,
              color-mix(in oklab, var(--cor) 22%, transparent) 0%, transparent 70%);
  pointer-events: none;
}

@media (hover: hover) {
  .indicador:hover { transform: translateY(-2px); border-color: color-mix(in oklab, var(--cor) 55%, transparent); }
}

.indicador-rotulo {
  position: relative;
  font-size: var(--texto-1);
  font-weight: 600;
  color: var(--texto-suave);
  text-transform: uppercase;
  letter-spacing: .04em;
}

.indicador-valor {
  position: relative;
  font-family: var(--fonte-numero);
  font-variant-numeric: tabular-nums;
  font-size: var(--texto-5);
  font-weight: 700;
  letter-spacing: -0.02em;
  min-height: 1.5em;
  display: flex;
  align-items: center;
}

.indicador-apoio {
  position: relative;
  font-size: var(--texto-1);
  color: var(--texto-suave);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* O oculto: o número continua no DOM com a largura dele, e uma tampa cobre.
   Assim revelar não empurra o layout, e o cartão não pula na frente de quem
   tocou. O filtro no texto é o que impede ler o valor por trás da tampa. */
.valor-tampa {
  position: absolute;
  inset: 0;
  border-radius: var(--raio-pequeno);
  background: repeating-linear-gradient(115deg,
    color-mix(in oklab, var(--texto) 16%, transparent) 0 8px,
    color-mix(in oklab, var(--texto) 8%, transparent) 8px 16px);
  opacity: 0;
  transition: opacity var(--medio) var(--curva);
  pointer-events: none;
}

[data-oculto="sim"] .valor-tampa { opacity: 1; }

[data-oculto="sim"] .valor-texto {
  filter: blur(9px);
  opacity: .55;
  /* O leitor de tela não anuncia o valor enquanto ele está tapado: borrar o
     pixel e deixar o texto no ar seria esconder só de quem enxerga. */
  visibility: hidden;
}

.valor-texto {
  transition: filter var(--medio) var(--curva), opacity var(--medio) var(--curva);
}

/* Os cards de destino */
.destinos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gap-pequeno);
}

@media (min-width: 40rem) {
  .destinos { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 64rem) {
  .destinos { grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }
}

.destino {
  position: relative;
  display: grid;
  gap: var(--espaco-1);
  align-content: start;
  padding: var(--gap);
  border-radius: var(--raio);
  border: 1px solid color-mix(in oklab, var(--cor) 26%, transparent);
  background:
    linear-gradient(155deg,
      color-mix(in oklab, var(--cor) 12%, transparent) 0%,
      color-mix(in oklab, var(--cor) 4%, transparent) 55%,
      transparent 100%),
    var(--vidro);
  backdrop-filter: var(--vidro-borrao);
  -webkit-backdrop-filter: var(--vidro-borrao);
  color: inherit;
  text-decoration: none;
  overflow: hidden;
  animation: entra-card .5s cubic-bezier(.22, 1, .36, 1) backwards;
  animation-delay: calc(var(--ordem, 0) * 45ms + 120ms);
  transition: transform var(--medio) var(--curva), border-color var(--medio) var(--curva),
              box-shadow var(--medio) var(--curva);
}

@media (hover: hover) {
  .destino:hover {
    transform: translateY(-3px);
    border-color: color-mix(in oklab, var(--cor) 60%, transparent);
    box-shadow: 0 8px 24px color-mix(in oklab, var(--cor) 18%, transparent);
  }
}

.destino:active { transform: scale(0.985); }

.destino-icone {
  display: grid;
  place-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin-bottom: var(--espaco-3);
  border-radius: var(--raio-pequeno);
  background: color-mix(in oklab, var(--cor) 16%, transparent);
  color: var(--cor);
}

.destino-icone svg { width: 1.35rem; height: 1.35rem; display: block; }

.destino-nome {
  font-size: var(--texto-4);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.destino-apoio {
  font-size: var(--texto-1);
  color: var(--texto-suave);
  line-height: 1.4;
}

/* --------------------------------------------------------------------------
   Os ícones animados
   --------------------------------------------------------------------------
   A parte marcada com data-anima é a que se move, e ela conta a história do
   destino: o traço do gráfico se desenha, os pontos da conversa pulsam, a
   seta do reembolso volta. O contorno fica parado, senão o ícone inteiro
   balança e vira enfeite.

   Cada ícone anima uma vez na entrada, e de novo sob o ponteiro. No toque não
   há hover, então a entrada é a única chance: por isso ela existe. */
.destino-icone [data-anima] {
  transform-box: fill-box;
  transform-origin: center;
  animation: pisca-icone .6s var(--curva) backwards;
  animation-delay: calc(var(--ordem, 0) * 45ms + 320ms);
}

@media (hover: hover) {
  .destino:hover .destino-icone [data-anima] {
    animation: pisca-icone .55s var(--curva);
  }
}

/* O traço se desenha do começo ao fim. O dasharray é grande o bastante para
   cobrir qualquer um dos traços destes ícones, que cabem em 24 unidades. */
@keyframes pisca-icone {
  from { stroke-dasharray: 40; stroke-dashoffset: 40; opacity: 0; }
  to   { stroke-dasharray: 40; stroke-dashoffset: 0; opacity: 1; }
}

@keyframes entra-card {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* Quem pediu menos movimento recebe a tela pronta. O olho continua funcionando:
   ele é controle, e não animação. */
@media (prefers-reduced-motion: reduce) {
  .indicador,
  .destino,
  .destino-icone [data-anima] {
    animation: none;
  }
  .destino:hover { transform: none; }
  .indicador:hover { transform: none; }
}

/* --------------------------------------------------------------------------
   Tag de estado
   --------------------------------------------------------------------------
   Responde uma coisa só, e por isso é curta: pago, em aberto, vencida. O
   prazo vive na linha de apoio, porque é outra pergunta.

   A cor não carrega a informação sozinha: o texto diz o mesmo, e quem não
   distingue verde de vermelho lê a palavra. */
.tag {
  display: inline-block;
  padding: .125rem var(--espaco-3);
  border-radius: 999px;
  font-size: var(--texto-1);
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  border: 1px solid transparent;
}

.tag-paga {
  background: color-mix(in oklab, var(--receita) 14%, transparent);
  border-color: color-mix(in oklab, var(--receita) 30%, transparent);
  color: var(--receita);
}

.tag-aberta {
  background: color-mix(in oklab, var(--despesa) 12%, transparent);
  border-color: color-mix(in oklab, var(--despesa) 28%, transparent);
  color: var(--despesa);
}

/* Vencida é a única das três que pede ação hoje, então ela pesa mais: fundo
   cheio em vez de tinta sobre transparência. */
.tag-vencida {
  background: var(--despesa);
  border-color: var(--despesa);
  color: #fff;
}

/* O filtro rápido da tela de Faturas: três alvos em vez de dois. */
.filtro-fatura {
  grid-template-columns: repeat(3, 1fr);
  margin-top: var(--gap-pequeno);
}

.filtro-fatura button {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--espaco-2);
}

.filtro-fatura button[aria-pressed="true"] {
  color: var(--texto);
}

/* --------------------------------------------------------------------------
   Fim do mês
   -------------------------------------------------------------------------- */
/* O número que a tela existe para dar. Ele fica com a borda da cor da marca
   porque é a conclusão, e não mais uma métrica ao lado das outras. */
.metrica-fecho {
  border-color: color-mix(in oklab, var(--primaria) 45%, var(--borda));
  background: color-mix(in oklab, var(--primaria) 7%, var(--cartao));
}

/* Quando o mês fica negativo em algum dia. Vermelho de aviso, e não de erro:
   nada quebrou, mas há uma decisão a tomar antes daquele dia. */
.cartao-alerta {
  border-color: color-mix(in oklab, var(--despesa) 45%, var(--borda));
  background: color-mix(in oklab, var(--despesa) 8%, var(--cartao));
}

/* --------------------------------------------------------------------------
   Plano do mês
   --------------------------------------------------------------------------
   A barra é escalada pelo maior entre planejado e realizado, e o traço marca
   onde o plano estava. Passar do plano vira barra que ultrapassa o traço, que
   se lê de relance; o número sozinho obrigaria a fazer a conta.

   O traço mora fora da barra porque `.barra` recorta o que transborda, e ele
   precisa passar de cima a baixo para ser visível numa faixa de 6px. */
.plano-barra {
  position: relative;
  display: block;
  margin-top: var(--espaco-2);
}

.plano-marca {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 2px;
  border-radius: 1px;
  background: color-mix(in oklab, var(--texto) 55%, transparent);
}

/* --------------------------------------------------------------------------
   Etiqueta de recorte, no Extrato
   --------------------------------------------------------------------------
   Ela existe para nunca haver filtro agindo sem estar escrito na tela. Quem
   chega pelo cartão "A pagar no mês" precisa ver, em palavras, por que a lista
   é menor que o extrato do mês, e ter como desfazer num toque. */
.chip-recorte {
  display: inline-flex;
  align-items: center;
  gap: var(--espaco-2);
  margin-top: var(--gap-pequeno);
  padding: .25rem var(--espaco-3);
  border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--primaria) 35%, transparent);
  background: color-mix(in oklab, var(--primaria) 12%, transparent);
  color: var(--primaria);
  font-size: var(--texto-1);
  font-weight: 600;
  cursor: pointer;
}

.chip-recorte:hover {
  background: color-mix(in oklab, var(--primaria) 20%, transparent);
}

/* --------------------------------------------------------------------------
   Escolha de contas, na tela Fim do mês
   --------------------------------------------------------------------------
   Rola de lado em vez de quebrar em várias linhas: com seis contas, quebrar
   empurraria os números para baixo da dobra, e é o número que a tela existe
   para dar. */
.contas-escolha {
  display: flex;
  gap: var(--espaco-2);
  overflow-x: auto;
  padding: var(--gap-pequeno) var(--gap);
  scrollbar-width: none;
}

.contas-escolha::-webkit-scrollbar {
  display: none;
}

.chip-conta {
  flex: 0 0 auto;
  padding: .3rem var(--espaco-4);
  border-radius: 999px;
  border: 1px solid var(--borda);
  background: transparent;
  color: var(--texto-suave);
  font-size: var(--texto-2);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

/* A conta escolhida ganha a cor da marca. Fundo cheio em vez de contorno,
   porque escolhido e não escolhido precisam se separar de relance numa fila
   que rola. */
.chip-conta[aria-pressed="true"],
.chip-opcao[aria-pressed="true"] {
  border-color: color-mix(in oklab, var(--primaria) 45%, transparent);
  background: color-mix(in oklab, var(--primaria) 14%, transparent);
  color: var(--primaria);
}

/* Opções de um bloco do painel: o período das semanas, a medida do caixa.
   Mesmo desenho do chip de conta, menor, porque mora dentro do cartão e
   disputa espaço com o gráfico. Uma fila por grupo, e a fila rola no celular
   em vez de quebrar em duas linhas e empurrar o gráfico para baixo. */
.bloco-opcoes {
  display: flex;
  gap: var(--espaco-2);
  margin: 0 0 var(--espaco-3);
  overflow-x: auto;
  scrollbar-width: none;
}

.bloco-opcoes::-webkit-scrollbar {
  display: none;
}

.chip-opcao {
  flex: 0 0 auto;
  padding: .2rem var(--espaco-3);
  border-radius: 999px;
  border: 1px solid var(--borda);
  background: transparent;
  color: var(--texto-suave);
  font-size: var(--texto-1);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

/* Previsto e cancelado, para acompanhar a de Pago e a de Conciliado.
   Previsto é âmbar porque é o único dos quatro que ainda pede algo de você.
   Cancelado é cinza: não pede nada, só precisa ser reconhecível. */
.tag-prevista {
  background: color-mix(in oklab, var(--aviso) 14%, transparent);
  border-color: color-mix(in oklab, var(--aviso) 32%, transparent);
  color: var(--aviso);
}

.tag-cancelada {
  background: color-mix(in oklab, var(--texto) 8%, transparent);
  border-color: color-mix(in oklab, var(--texto) 18%, transparent);
  color: var(--texto-suave);
}

/* Estimativa: o que a rotina deduziu do histórico, e não uma conta que existe.
   Tracejada de propósito. Cheia ela pesaria igual a "Previsto", que é um
   compromisso com data e valor combinados, e a diferença entre os dois é
   justamente o que a etiqueta existe para dizer. */
.tag-estimada {
  background: transparent;
  border-style: dashed;
  border-color: color-mix(in oklab, var(--texto) 30%, transparent);
  color: var(--texto-suave);
  font-weight: 500;
}

/* A linha de detalhe do item, na confirmação da importação.
   Envolve em vez de rolar: são três controles curtos, e no celular eles cabem
   em duas linhas sem empurrar o valor para fora da tela. */
.linha-detalhe {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espaco-2);
  margin-top: var(--espaco-2);
}

.linha-detalhe select,
.linha-detalhe input {
  min-height: 2.25rem;
  font-size: var(--texto-2);
  width: auto;
  flex: 1 1 7rem;
}

/* Parcelas é um número de dois dígitos e não precisa da largura dos outros. */
.linha-detalhe input.parcelas {
  flex: 0 0 5.5rem;
}

/* O segundo nível do olho.
   Investido, Patrimônio e Patrimônio líquido dizem quanto a casa vale, e
   mostrar o saldo do mês para alguém ao lado não deveria significar mostrar
   isso também. Eles seguem tapados enquanto `data-sigilo` estiver ligado, com
   a mesma tampa do primeiro nível: uma segunda aparência criaria dois jeitos
   de dizer a mesma coisa. */
[data-sigilo="sim"] .indicador-sigiloso .valor-tampa { opacity: 1; }

[data-sigilo="sim"] .indicador-sigiloso .valor-texto {
  filter: blur(9px);
  opacity: .55;
  visibility: hidden;
}

/* --------------------------------------------------------------------------
   Carregando
   --------------------------------------------------------------------------
   O esqueleto cinza que havia antes tinha um brilho de 7% varrendo devagar, e
   ele acertava a intenção e errava o efeito: numa tela que demora dois
   segundos, um retângulo quase parado lê como travado.

   Três arcos girando, um por cor do app, em tempos que não são múltiplos entre
   si. Com tempos redondos os três voltariam a se alinhar toda volta e o
   conjunto pareceria pulsar em vez de girar. O do meio gira ao contrário, que
   é o que impede a leitura de "um anel grosso" quando eles se cruzam.

   Cada arco é uma borda com três lados transparentes: o quarto lado é o que se
   vê girando. Sem imagem, sem biblioteca e sem canvas, porque numa tela que já
   está esperando rede, gastar processador com a espera seria trocar um
   problema por outro. */
.carregando {
  display: grid;
  place-items: center;
  gap: var(--espaco-5);
  padding: clamp(2.5rem, 12vh, 6rem) var(--gap);
}

.carregando-orbita {
  position: relative;
  width: 4.5rem;
  height: 4.5rem;
}

.carregando-orbita span {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid transparent;
  border-top-color: var(--primaria);
  animation: orbita 1.6s linear infinite;
}

.carregando-orbita span:nth-child(2) {
  inset: 12%;
  border-top-color: var(--receita);
  animation-duration: 2.1s;
  animation-direction: reverse;
}

.carregando-orbita span:nth-child(3) {
  inset: 24%;
  border-top-color: var(--aviso);
  animation-duration: 1.3s;
}

@keyframes orbita {
  to { transform: rotate(360deg); }
}

.carregando-texto {
  margin: 0;
  font-size: var(--texto-2);
  color: var(--texto-suave);
  letter-spacing: .04em;
  animation: carregando-respirar 1.8s var(--curva) infinite;
}

@keyframes carregando-respirar {
  0%, 100% { opacity: .45; }
  50%      { opacity: 1; }
}

/* Quem pediu menos movimento recebe menos movimento. Os arcos continuam ali, e
   quem informa passa a ser a opacidade: sem nenhum sinal, a tela voltaria a
   parecer travada, que é o problema que isto veio resolver. */
@media (prefers-reduced-motion: reduce) {
  .carregando-orbita span {
    animation: carregando-respirar 2s var(--curva) infinite;
    transform: none;
  }
  .carregando-texto { animation-duration: 3s; }
}

/* A mesma órbita, agora por cima da tela, enquanto a IA lê.
   Ela cobre porque a espera aqui não é de rota: a tela de trás continua
   inteira, com botão de gravar e campo de arquivo, e deixá-la clicável durante
   a leitura convidaria a mandar o segundo pedido antes de o primeiro voltar. E
   é a espera mais longa do app, a única em que alguém teria tempo de achar que
   travou. */
/* A proposta do assistente, colada na resposta que a gerou. Borda tracejada
   porque ela ainda nao e nada: nada foi lancado nem alterado ate o toque. */
.proposta {
  display: grid;
  gap: var(--espaco-3);
  margin-top: var(--espaco-3);
  border: 1px dashed var(--aviso);
}

.proposta .lista-item {
  cursor: pointer;
}

.carregando-ia {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  gap: var(--espaco-5);
  align-content: center;
  padding: var(--gap);
  background: color-mix(in oklab, var(--fundo) 78%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: carregando-ia-entrar .2s var(--curva);
}

/* A órbita cresce aqui: no meio da tela, no tamanho da rota, ela ficaria
   pequena demais para o tempo que dura. */
.carregando-ia .carregando-orbita {
  width: 6rem;
  height: 6rem;
}

.carregando-ia-passo {
  margin: 0;
  max-width: 22rem;
  text-align: center;
  font-size: var(--texto-3);
  color: var(--texto);
}

.carregando-ia-apoio {
  margin: 0;
  max-width: 22rem;
  text-align: center;
  font-size: var(--texto-1);
  color: var(--texto-suave);
}

@keyframes carregando-ia-entrar {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .carregando-ia { animation: none; }
}
