/* A TELA DE EXERCICIO DO DEVLINGO, NO NAVEGADOR.
 *
 * As cores NAO foram escolhidas aqui: sao as mesmas de app/lib/ui/paleta.dart,
 * copiadas uma a uma. O CLAUDE.md registra que "nenhuma cor e escolhida ate ser
 * vista renderizada", e estas ja passaram por isso no aparelho.
 *
 * O que muda em relacao ao app e a MOLDURA, nao a identidade: aqui ha tela
 * larga, cursor e teclado de verdade, e o texto e texto -- seleciona, o leitor
 * de tela le, a busca indexa. Era isso que o motor grafico do Flutter web
 * custaria. */

:root {
  /* Sem isto a barra de rolagem da escolha de trilha saia BRANCA, a do
     sistema -- a borda direita inteira brilhando numa pagina escura. Diz ao
     navegador para desenhar os controles nativos no tema escuro. */
  color-scheme: dark;

  --fundo: #170A31;
  --superficie: #1E0F3E;
  --linha: #3D2A66;
  --texto: #F2F0FF;
  --suave: #9B8FC7;
  --acerto: #FF2D95;
  --erro: #FF5F57;
  --destaque: #00E5FF;
  --visor: #39FF14;
  --telemetria: #FFE14D;
  --termo: #8FDCE8;

  /* CERTO x ACERTO: nomes parecidos, papeis opostos, e eu ja troquei um pelo
     outro. `--certo` e o VERDE que sinaliza resposta certa; `--acerto` e o
     magenta de marca do botao primario. Copiados de paleta.dart. */
  --certo: #39FF14;
  --certo-tenue: rgba(57, 255, 20, .2);
  --erro-tenue: rgba(255, 95, 87, .2);
  --alt-selecionada: #1D2C4A;

  --ide-fundo: #1B1235;
  --ide-aba: #241847;
  --ide-numero: #5F4B8B;

  --sx-palavra: #FF7AD9;
  --sx-texto: #FFE14D;
  --sx-numero: #FF7AD9;
  --sx-funcao: #39FF14;
  --sx-nome: #00E5FF;
  --sx-pontuacao: #F2F0FF;
  --sx-comentario: #7A68B0;

  --mono: ui-monospace, "Cascadia Mono", "Consolas", "DejaVu Sans Mono", monospace;
}

* { box-sizing: border-box; }

/* `hidden` TEM QUE VENCER, e sem isto ele perde. Seletor de classe tem
 * precedencia sobre a regra padrao do navegador para [hidden], entao
 * `.alternativas { display: grid }` mantinha a caixa no layout mesmo
 * "escondida" -- nas questoes de escrita ela ficava la, vazia, e por isso
 * ninguem viu. Com VISTAS inteiras escondidas por `hidden`, o defeito deixaria
 * de ser invisivel: a tela de exercicio (display: grid) apareceria por cima da
 * trilha. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--fundo);
  color: var(--texto);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.55;
}

/* TRES FAIXAS, e a do meio e a unica que rola.
 *
 * O CLAUDE.md fixa isso: topo e rodape nao saem da tela, porque a explicacao e
 * "o pagamento do exercicio" e nao pode depender de o aluno descobrir que
 * precisa rolar. */
.tela {
  display: grid;
  grid-template-rows: auto 1fr auto;
  height: 100%;
  max-width: 820px;
  margin: 0 auto;
  border-left: 1px solid var(--linha);
  border-right: 1px solid var(--linha);
}

/* ---------------------------------------------------------------- o topo */
.topo {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--linha);
  background: var(--fundo);
}

.sair {
  background: none;
  border: none;
  color: var(--suave);
  font: inherit;
  font-size: 20px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
}
.sair { text-decoration: none; }
.sair:hover { color: var(--texto); }

/* Ela mede a LICAO, nunca a linguagem: barra que nao sai do lugar desmotiva. */
.barra {
  flex: 1;
  height: 8px;
  background: var(--linha);
  border-radius: 4px;
  overflow: hidden;
}
.barra > i {
  display: block;
  height: 100%;
  background: var(--destaque);
  transition: width .25s ease;
}

.contador { color: var(--suave); font-size: 13px; white-space: nowrap; }

/* -------------------------------------------------------------- o miolo */
.miolo {
  overflow-y: auto;
  padding: 18px 16px 8px;
}

.topico {
  display: inline-block;
  color: var(--destaque);
  border: 1px solid var(--destaque);
  border-radius: 999px;
  padding: 2px 12px;
  font-size: 12px;
  letter-spacing: .06em;
  text-transform: uppercase;
  margin-bottom: 14px;
}

.enunciado { font-size: 17px; margin: 0 0 18px; }
/* Termo tecnico em italico e cor propria -- e `--termo`, nao `--destaque`:
 * ciano puro e cor de acao, e espalhado pelo paragrafo faria o texto piscar. */
.enunciado em { color: var(--termo); font-style: italic; }
.enunciado strong { color: var(--texto); }

/* --------------------------------------------------------- a IDE de faz-conta */
.ide {
  background: var(--ide-fundo);
  border: 1px solid var(--linha);
  border-radius: 8px;
  margin: 0 0 18px;
  overflow: hidden;
}

.ide-aba {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--ide-aba);
  padding: 7px 10px;
  border-bottom: 1px solid var(--linha);
}
.bolinhas { display: flex; gap: 6px; }
.bolinhas i { width: 10px; height: 10px; border-radius: 50%; display: block; }
.bolinhas i:nth-child(1) { background: var(--erro); }
.bolinhas i:nth-child(2) { background: var(--telemetria); }
.bolinhas i:nth-child(3) { background: var(--visor); }
.ide-nome { color: var(--suave); font-size: 12px; flex: 1; }

.copiar {
  background: none;
  border: 1px solid var(--linha);
  color: var(--suave);
  font: inherit;
  font-size: 11px;
  border-radius: 5px;
  padding: 2px 8px;
  cursor: pointer;
}
.copiar:hover { color: var(--texto); border-color: var(--suave); }

/* NUNCA quebra linha. Quebra automatica destroi a indentacao, e em Python a
 * indentacao e sintaxe -- esta e a regra que obriga a rolagem horizontal. */
.codigo {
  margin: 0;
  padding: 12px 0;
  overflow-x: auto;
  font-size: 14px;
}
.codigo .ln { display: flex; white-space: pre; }
.codigo .num {
  color: var(--ide-numero);
  min-width: 3ch;
  padding: 0 12px 0 10px;
  text-align: right;
  user-select: none;
  position: sticky;
  left: 0;
  background: var(--ide-fundo);
}
.codigo .src { padding-right: 16px; }

.t-palavraChave { color: var(--sx-palavra); }
.t-texto       { color: var(--sx-texto); }
.t-numero      { color: var(--sx-numero); }
.t-funcao      { color: var(--sx-funcao); }
.t-nome        { color: var(--sx-nome); }
.t-pontuacao,
.t-espaco      { color: var(--sx-pontuacao); }
.t-comentario  { color: var(--sx-comentario); font-style: italic; }
.t-lacuna {
  background: var(--destaque);
  color: #062230;
  border-radius: 3px;
  padding: 0 4px;
}

/* ---------------------------------------------------------- alternativas */
.alternativas { display: grid; gap: 10px; margin-bottom: 14px; }

.alt {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  text-align: left;
  background: var(--superficie);
  color: var(--texto);
  border: 1px solid var(--linha);
  border-radius: 8px;
  padding: 12px 14px;
  font: inherit;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.alt:hover:not(:disabled) { border-color: var(--suave); }
.alt .rotulo {
  color: var(--suave);
  font-size: 12px;
  border: 1px solid var(--linha);
  border-radius: 4px;
  padding: 0 6px;
  flex: none;
  margin-top: 2px;
}

.alt[aria-pressed="true"] { border-color: var(--destaque); background: var(--alt-selecionada); }
.alt[aria-pressed="true"] .rotulo { color: var(--destaque); border-color: var(--destaque); }

/* RISCADA, nao apagada: ver o que ja foi descartado faz parte do raciocinio
 * por exclusao. Por isso ela continua na lista, com borda e risco vermelhos --
 * como no app, e nao apenas esmaecida. */
.alt.eliminada {
  text-decoration: line-through;
  text-decoration-color: var(--erro);
  color: var(--suave);
  border-color: var(--erro);
  background: var(--erro-tenue);
  cursor: not-allowed;
}
.alt.eliminada .rotulo { color: var(--erro); border-color: var(--erro); }

.alt.certa { border-color: var(--certo); background: var(--certo-tenue); }
.alt.certa .rotulo { color: var(--certo); border-color: var(--certo); }

/* ----------------------------------------------------------- escrita livre */
.molde {
  color: var(--suave);
  font-size: 13px;
  margin-bottom: 6px;
}
.molde b { color: var(--telemetria); font-weight: normal; letter-spacing: .12em; }

.campo {
  width: 100%;
  background: var(--ide-fundo);
  color: var(--texto);
  border: 1px solid var(--linha);
  border-radius: 8px;
  padding: 12px 14px;
  font: inherit;
  margin-bottom: 14px;
}
.campo:focus { outline: none; border-color: var(--destaque); }

/* --------------------------------------------------------------- o rodape */
.rodape { border-top: 1px solid var(--linha); background: var(--fundo); }

/* O painel de retorno e FIXO acima da barra de acoes, nunca dentro da
 * rolagem. */
.retorno {
  margin: 12px 16px 0;
  border: 1px solid;
  border-left-width: 4px;
  border-radius: 8px;
  padding: 10px 14px;
}
/* ACERTAR E REVELAR USAM A MESMA COR, e isso e deliberado no app: revelar nao
   e falhar, e o `VAMOS JUNTOS` da tela. Pintar de vermelho transformaria
   "errar nao termina a questao" em mentira. */
.retorno[data-fase="acertou"] { border-color: var(--certo); background: var(--certo-tenue); }
.retorno[data-fase="revelado"] { border-color: var(--certo); background: var(--certo-tenue); }
.retorno[data-fase="respondendo"] { border-color: var(--erro); background: var(--erro-tenue); }

.retorno .titulo {
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-bottom: 4px;
}
.retorno[data-fase="acertou"] .titulo { color: var(--certo); }
.retorno[data-fase="revelado"] .titulo { color: var(--certo); }
.retorno[data-fase="respondendo"] .titulo { color: var(--erro); }
/* O CORPO CONTINUA BRANCO. Verde ou vermelho saturado em texto longo sobre
 * fundo escuro reprova em contraste, e a explicacao e o texto mais longo da
 * tela: pinta-la a tornaria dificil de ler justo quando mais importa. */
.retorno .corpo { color: var(--texto); }
.retorno .corpo code { color: var(--visor); }

.acoes { display: flex; gap: 12px; padding: 12px 16px; }

.btn {
  flex: 1;
  border-radius: 8px;
  padding: 12px;
  font: inherit;
  font-size: 14px;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn:disabled { opacity: .4; cursor: default; }

/* Dica e secundaria de proposito. Com o mesmo peso da acao principal, ela
 * viraria o caminho de menor resistencia. */
.btn.dica { flex: 0 0 34%; background: transparent; color: var(--telemetria); border: 1px solid var(--telemetria); }
.btn.principal { background: var(--acerto); color: #FFF; border: 1px solid var(--acerto); }

/* --------------------------------------------------------------- telefone */
@media (max-width: 560px) {
  body { font-size: 14px; }
  .tela { border: none; }
  .miolo { padding: 14px 16px 6px; }
  .enunciado { font-size: 16px; }
  .acoes { padding: 10px 16px; }
}

/* ================================================== escolha e trilha
 *
 * Aqui entra a liberdade estetica que o Gustavo deu ao navegador -- "da ate
 * pra ser mais criativo com os elementos esteticos" --, mas dentro da mesma
 * paleta e da mesma mono. A liberdade e de MOLDURA, nao de identidade. */

.vista:not(.tela) { min-height: 100%; }
.coluna { max-width: 820px; margin: 0 auto; padding: 36px 20px 48px; }

/* A marca do CLAUDE.md: mono com deslocamento em ciano e magenta, a
 * aberracao cromatica. Feita com sombra de texto, sem fonte baixada -- fonte
 * cyberpunk de terceiro quebra onde nao esta instalada. */
.logo {
  margin: 0;
  font-size: 44px;
  letter-spacing: .02em;
  color: var(--texto);
  text-shadow: -2px 0 var(--destaque), 2px 0 var(--acerto);
}
.logo span { color: var(--visor); text-shadow: -2px 0 var(--destaque), 2px 0 var(--acerto); }
.lema { color: var(--suave); margin: 6px 0 34px; }

.rotulo-secao {
  font-size: 12px;
  font-weight: normal;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--suave);
  margin: 0 0 12px;
}

.cartoes { display: grid; gap: 12px; }

.cartao {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 16px;
  align-items: center;
  background: var(--superficie);
  border: 1px solid var(--linha);
  border-radius: 10px;
  padding: 16px 18px;
  color: var(--texto);
  text-decoration: none;
  transition: border-color .15s, transform .15s;
}
.cartao:hover, .cartao:focus-visible {
  border-color: var(--destaque);
  outline: none;
  transform: translateX(3px);
}
.cartao .titulo-cartao { font-size: 18px; }
.cartao .sub { color: var(--suave); font-size: 13px; grid-column: 1; }
.cartao .lado {
  grid-row: 1 / span 2;
  grid-column: 2;
  color: var(--destaque);
  font-size: 12px;
  text-align: right;
  white-space: nowrap;
}

.cabecalho { display: flex; align-items: center; gap: 14px; margin-bottom: 6px; }
.voltar {
  color: var(--suave);
  text-decoration: none;
  font-size: 24px;
  line-height: 1;
}
.voltar:hover { color: var(--texto); }
.nome-trilha { margin: 0; font-size: 28px; font-weight: normal; }
.descricao-trilha { color: var(--suave); margin: 0 0 26px; }

/* O numero da licao em destaque, como no app: "Licao 03" e o que a pessoa
 * procura na lista. */
.num-licao {
  color: var(--destaque);
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.falha { max-width: 640px; margin: 60px auto; padding: 0 20px; color: var(--erro); }

@media (max-width: 560px) {
  .coluna { padding: 24px 16px 36px; }
  .logo { font-size: 36px; }
}

/* =============================================================== entrada */
.coluna.estreita { max-width: 440px; }
.formulario { display: grid; gap: 4px; margin-top: 28px; }
.titulo-form { margin: 0; font-size: 22px; font-weight: normal; }
.explica { color: var(--suave); margin: 4px 0 18px; }
.rotulo-campo { color: var(--suave); font-size: 13px; margin-top: 8px; }
.formulario .campo { margin-bottom: 4px; }
.dica-campo { color: var(--suave); font-size: 12px; margin: 0 0 8px; }
.erro-form, .aviso-form {
  border-radius: 8px;
  padding: 10px 12px;
  margin: 8px 0 4px;
  font-size: 14px;
}
.erro-form { border: 1px solid var(--erro); background: var(--erro-tenue); }
.aviso-form { border: 1px solid var(--certo); background: var(--certo-tenue); }
.btn.largo { width: 100%; margin-top: 12px; }
.trocar-modo { display: flex; justify-content: space-between; gap: 12px; margin-top: 16px; }
.trocar-modo a, .conta a { color: var(--destaque); font-size: 13px; }

/* A conta e a PRIMEIRA linha da tela, e discreta. Ela ficava entre o lema e os
   cartoes, partindo o cabecalho em duas metades sem relacao. */
.conta {
  color: var(--suave);
  font-size: 13px;
  margin: 0 0 4px;
  text-align: right;
}

/* O mascote ao lado do titulo, como no app -- la ele tem 82px e fica a direita
   do bloco de texto. A arte e `tronikat.svg`, a MESMA que o app carrega. */
.marca.com-mascote {
  display: flex;
  /* CENTRO, e nao a base. O app usa um `Row` sem `crossAxisAlignment`, cujo
     padrao e `center`. Com a base alinhada, o mascote -- que e alto -- empurrava
     o titulo para baixo e abria um buraco de 140px a esquerda dele. */
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 30px;
}
.marca.com-mascote .lema { margin-bottom: 0; }

.mascote-lado {
  width: 124px;
  flex: none;
  /* Ele nao respira aqui. A entrada tem um gato so, em close, e o movimento e
     o convite; nesta tela ele divide espaco com seis cartoes, e um desenho
     pulsando ao lado de uma lista disputa a leitura em vez de enfeita-la. */
}

@media (max-width: 560px) {
  .mascote-lado { width: 78px; }
}

/* O progresso na trilha: o numero e o que a pessoa procura, e a licao
   concluida ganha o verde de CERTO -- concluir e acertar tem o mesmo sabor. */
.cartao.concluida { border-color: var(--certo); }
.cartao.concluida .lado { color: var(--certo); }

/* ============================ a faixa e a barra, copiadas de _CartaoDaTrilha
 *
 * A COR DA FAIXA E O ESTADO, e e assim no app: apagada quando a trilha nunca
 * foi tocada, ciano quando esta em andamento, verde quando acabou. Sem ela a
 * lista inteira tem o mesmo peso visual, e descobrir onde se parou exige ler
 * seis numeros.
 *
 * Tres pixels, a esquerda, como la. */
.cartao { border-left: 3px solid var(--linha); }
.cartao.comecada { border-left-color: var(--destaque); }
.cartao.concluida { border-left-color: var(--certo); }

/* A barra ocupa a largura inteira do cartao, embaixo. `grid-column: 1 / -1`
   porque o cartao e uma grade de duas colunas e ela nao pertence a nenhuma. */
.progresso-trilha {
  grid-column: 1 / -1;
  height: 8px;
  margin-top: 10px;
  background: var(--linha);
  border-radius: 4px;
  overflow: hidden;
}
.progresso-trilha > i {
  display: block;
  height: 100%;
  background: var(--destaque);
  border-radius: 4px;
}
.cartao.concluida .progresso-trilha > i { background: var(--certo); }

/* A linha de metadados, que substituiu o numero solto. Ela e `--suave` e nao
   `--destaque`: e informacao de apoio, e pintar tudo de ciano faria a lista
   competir consigo mesma. */
.meta-trilha {
  grid-column: 1 / -1;
  color: var(--suave);
  font-size: 12px;
}

/* Enquanto a conta e o progresso chegam. Sem isto a primeira coisa na tela
   seria o fundo vazio, que se le como pagina quebrada. */
.carregando { max-width: 640px; margin: 80px auto; padding: 0 20px; color: var(--suave); text-align: center; }

/* ============================================ o cenario da tela de entrada
 *
 * Tudo aqui e `transform` e `opacity` no que se move, e gradiente no que nao
 * se move: e o que o navegador compoe sem repintar. O site do Tr∅nikAt ja
 * custou tres rodadas de limpeza por causa de pintura cara, e esta tela e a
 * PRIMEIRA que qualquer pessoa ve. */

#vista-entrada { position: relative; }

/* `fixed`, e isso importa por dois motivos. O cenario e da PAGINA, entao toda
   tela o herda sem ninguem repetir marcacao; e ele nao rola junto, entao nao
   ha repintura a cada rolagem numa lista longa de licoes.

   O `overflow` mora AQUI, e nao no corpo. A grade transborda de proposito
   (`left` e `right` em -25%), e alguem precisa conter isso -- mas se quem
   contivesse fosse a pagina, numa janela baixa o formulario da entrada seria
   cortado sem rolagem e ninguem alcancaria o botao de entrar. */
/* As vistas sobem UM nivel, para ficarem na frente do cenario. Sem isto o
   cenario, que vem antes no documento, ainda perderia para nada -- mas com
   `position: fixed` ele passa a pintar por cima do conteudo estatico. */
.vista { position: relative; z-index: 1; }

.cenario {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;

  /* NAO use z-index negativo aqui. Foi a primeira tentativa, e o cenario
     sumiu: um filho com `z-index: -1` vai parar atras do fundo do proprio
     `body`, que e opaco. O print mostrou fundo chapado e nenhuma grade.
     A ordem certa e cenario em 0 e conteudo em 1. */
  z-index: 0;
  /* O ceu. Sao TRES camadas, e cada uma cobre uma faixa que as outras deixam
     chapada -- a de cima entrou depois do print da escolha, onde os primeiros
     300px, que e por onde o olho entra, nao tinham nada. */
  background:
    radial-gradient(90% 40% at 50% 0%, rgba(0, 229, 255, .10), transparent 70%),
    radial-gradient(120% 60% at 50% 88%, rgba(255, 45, 149, .18), transparent 62%),
    linear-gradient(180deg, #120725 0%, var(--fundo) 45%);
}

/* O SOL E CONTRALUZ DO MASCOTE, e nao paisagem de fundo.
 *
 * Na primeira versao ele ficava no horizonte, como manda o synthwave. O print
 * mostrou por que nao da: o formulario ocupa o centro da pagina, entao as
 * fatias escuras do disco apareciam DENTRO do painel de login e liam como
 * falha de renderizacao. Atras da cabeca do gato nada passa por cima dele.
 *
 * O recorte e obrigatorio: sem ele as fatias sobram para os lados no topo,
 * onde o circulo e estreito, e viram tracos soltos -- defeito que ja apareceu
 * na tela de titulo do app. Aqui quem recorta e o proprio border-radius. */
.palco { position: relative; }

.sol {
  position: absolute;
  left: 50%;
  top: 4px;
  width: 190px;
  height: 190px;
  margin-left: -95px;
  border-radius: 50%;
  overflow: hidden;
  background:
    repeating-linear-gradient(180deg,
      transparent 0 9px, rgba(23, 10, 49, .8) 9px 13px),
    linear-gradient(180deg, var(--telemetria) 0%, var(--acerto) 78%);
  opacity: .42;
  filter: blur(1px);
}

/* A grade em fuga: linhas que se aproximam perto do horizonte. */
.grade {
  position: absolute;
  left: -25%;
  right: -25%;
  bottom: 0;
  height: 46%;
  background:
    repeating-linear-gradient(90deg,
      transparent 0 58px, rgba(0, 229, 255, .22) 58px 60px),
    repeating-linear-gradient(180deg,
      transparent 0 26px, rgba(0, 229, 255, .18) 26px 28px);
  transform: perspective(200px) rotateX(58deg);
  transform-origin: bottom center;
  mask-image: linear-gradient(180deg, transparent, #000 45%);
}

#vista-entrada .coluna { position: relative; }
#vista-entrada .marca { text-align: center; }
#vista-entrada .lema { margin: 6px 0 0; }

/* O retrato e um BUSTO QUE SANGRA de proposito: o CLAUDE.md registra que os
   ombros vao de x=-40 a x=440 num viewBox de 400, porque "enquadramento que
   cabe todo dentro da moldura nao e close". No app ele encosta na borda da
   tela e o corte nao existe; aqui ele flutua no meio da pagina, e o corte reto
   aparecia. O `mask-image` desmancha a base em vez de corta-la. */
.mascote {
  position: relative;
  display: block;
  width: 168px;
  margin: 2px auto -4px;
  animation: respirar 3.6s ease-in-out infinite;
  transform-origin: bottom center;
  mask-image: linear-gradient(180deg, #000 72%, transparent);
}

/* 2%, ancorada embaixo: ancorar no centro afastaria a cabeca dos ombros, que
   nao e respirar. Copiado da tela de titulo do app. */
@keyframes respirar {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.02); }
}

/* Quem pediu menos movimento no sistema nao ve movimento nenhum -- a mesma
   regra que o app cumpre com "reduzir animacoes" do Android. */
@media (prefers-reduced-motion: reduce) {
  .mascote { animation: none; }
}

.formulario {
  background: rgba(30, 15, 62, .72);
  border: 1px solid var(--linha);
  border-radius: 14px;
  padding: 20px 22px 24px;
  backdrop-filter: blur(2px);
}

/* O disco acompanha o mascote. Deixar o valor da versao de horizonte aqui
   fazia o sol ficar MAIOR no celular que no computador, engolindo o gato. */
@media (max-width: 560px) {
  .mascote { width: 132px; }
  .sol { width: 150px; height: 150px; margin-left: -75px; }
}

/* =================================================== a janela do Tr∅nikAt
 *
 * Ela flutua sobre tudo, e por isso e a unica coisa da pagina com `z-index`
 * alto -- o cenario e 0, as vistas sao 1, e ela e 50. */

/* So para leitor de tela. O botao e um rosto, e rosto nao tem nome acessivel. */
.sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.btn-tronikat {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 50;
  width: 62px;
  height: 62px;
  padding: 0;
  border: 2px solid var(--destaque);
  border-radius: 50%;
  background: var(--superficie);
  cursor: pointer;
  overflow: hidden;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .45);
  transition: transform .15s, border-color .15s;
}
.btn-tronikat:hover { transform: translateY(-2px); border-color: var(--visor); }

/* O RETRATO CANONICO, recortado na cabeca. `object-position: top` porque o
   arquivo e um busto: sem isso o botao redondo mostraria o meio do moletom. */
.btn-tronikat img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}

.tronikat-janela {
  position: fixed;
  right: 20px;
  bottom: 94px;
  z-index: 50;
  width: min(380px, calc(100vw - 40px));
  max-height: min(520px, calc(100vh - 130px));
  display: flex;
  flex-direction: column;
  background: var(--superficie);
  border: 1px solid var(--destaque);
  border-radius: 12px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .5);
  overflow: hidden;
}

.tronikat-topo {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--linha);
}
.tronikat-nome { color: var(--visor); font-weight: 700; }
/* O ESCOPO DELE ESTA ESCRITO NA JANELA, e isso e deliberado: o site do
   portfolio ja aprendeu que mascote que desconversa sem avisar do que fala
   parece quebrado. Dizer antes evita a pergunta que vai ser barrada. */
.tronikat-sub { color: var(--suave); font-size: 11px; flex: 1; }
.tronikat-fechar {
  background: none; border: none; color: var(--suave);
  font: inherit; cursor: pointer; padding: 0 2px; line-height: 1;
}
.tronikat-fechar:hover { color: var(--texto); }

.tronikat-conversa {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 14px;
}

.fala {
  padding: 8px 11px;
  border-radius: 10px;
  max-width: 86%;
  line-height: 1.45;
}
/* A pergunta sai a direita em ciano; a resposta a esquerda, na superficie. */
.fala-minha {
  align-self: flex-end;
  background: var(--alt-selecionada);
  border: 1px solid var(--destaque);
}
.fala-dele {
  align-self: flex-start;
  background: var(--fundo);
  border: 1px solid var(--linha);
}
.fala.pensando { color: var(--suave); font-style: italic; }
/* Vermelho de ALERTA, nao de punicao -- e o mesmo `--erro` do pontinho da IDE,
   e nao uma cor nova. */
.fala.falhou { border-color: var(--erro); color: var(--texto); }

.tronikat-form {
  display: flex;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--linha);
}
.tronikat-form .campo { flex: 1; margin: 0; }
.tronikat-form .btn { flex: none; padding: 8px 14px; }

/* No celular ela ocupa a largura toda, menos o respiro das bordas. */
@media (max-width: 560px) {
  .btn-tronikat { width: 54px; height: 54px; right: 14px; bottom: 14px; }
  .tronikat-janela { right: 14px; left: 14px; width: auto; bottom: 78px; }
}

/* ================================================ o Tr∅nikAt sem conexao
 *
 * Cinza, chuviscando, esperando -- e nao um aviso de erro. Ideia do Gustavo:
 * offline o app inteiro continua de pe, entao a unica peca que precisa de rede
 * avisa por conta propria, sem contaminar o resto. */

.tronikat-standby {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 18px 16px 22px;
  text-align: center;
}

.standby-arte {
  position: relative;
  width: 150px;
  line-height: 0;
  /* SEM COR. O personagem inteiro perde a saturacao, inclusive o verde do
     visor e o rosa do focinho -- e o que diz "transmissao morta" antes de
     qualquer texto ser lido. */
  filter: grayscale(1) brightness(.78) contrast(1.1);
}
.standby-arte img { width: 100%; display: block; }

/* A interferencia da CAMERA. Posicao tirada do SVG: o halo do visor ocupa
   x 204..344 e y 152..224 num viewBox de 400x520. */
.ruido-visor {
  position: absolute;
  left: 51%;
  top: 29.2%;
  width: 35%;
  height: 13.8%;
  background: repeating-linear-gradient(
    0deg,
    rgba(255, 255, 255, .55) 0 1px,
    transparent 1px 3px);
  mix-blend-mode: overlay;
  animation: chuvisco .28s steps(2) infinite;
}

/* As linhas de varredura, sobre o retrato todo, com uma faixa clara descendo
   devagar -- a barra de sincronismo da TV velha. */
.varredura {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, transparent 0 46%, rgba(255, 255, 255, .13) 48% 52%, transparent 54% 100%),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, .35) 0 1px, transparent 1px 3px);
  background-size: 100% 300%, 100% 100%;
  animation: rolar 3.4s linear infinite;
}

@keyframes chuvisco {
  0%   { transform: translateX(0);     opacity: .85; }
  50%  { transform: translateX(-2px);  opacity: .45; }
  100% { transform: translateX(2px);   opacity: .85; }
}
@keyframes rolar {
  from { background-position: 0 -100%, 0 0; }
  to   { background-position: 0 200%, 0 0; }
}

/* Quem pediu menos movimento no sistema fica com a imagem parada: cinza, com
   as linhas, e sem nada piscando. A mesma regra que o app cumpre com "reduzir
   animacoes" do Android -- e aqui ela pesa mais, porque chuvisco e o tipo de
   movimento que incomoda quem e sensivel a ele. */
@media (prefers-reduced-motion: reduce) {
  .ruido-visor, .varredura { animation: none; }
}

.standby-titulo {
  margin: 14px 0 0;
  color: var(--erro);
  font-size: 13px;
  letter-spacing: .16em;
}
.standby-recado { margin: 6px 0 0; color: var(--texto); font-size: 13px; }
.standby-nota { margin: 8px 0 0; color: var(--suave); font-size: 12px; }

/* O botao flutuante tambem despinta, senao o unico aviso ficaria escondido
   atras de um clique. */
.btn-tronikat.offline {
  border-color: var(--linha);
  filter: grayscale(1) brightness(.8);
}

/* O campo nao some quando esta desligado -- some seria dizer que a conversa
   acabou. Ele fica visivelmente inerte, e o placeholder explica por que. */
.tronikat-form .campo:disabled {
  opacity: .45;
  cursor: not-allowed;
}
.tronikat-form .btn:disabled {
  opacity: .45;
  cursor: not-allowed;
}

/* ======================================= a chamada: "tem alguem aqui"
 *
 * Pedido do Gustavo. O botao sozinho e um gato de 62px num canto, e nada nele
 * diz "converse comigo" -- num portfolio, recurso que ninguem descobre e igual
 * a recurso que nao existe.
 *
 * ELA SOME AO PRIMEIRO TOQUE, e volta na proxima visita. Quem ja sabe que ele
 * existe nao precisa de um balao pulsando no canto o tempo todo: aviso que nao
 * para de avisar vira ruido, e o projeto ja decidiu isso quando recusou que o
 * app sugerisse o modo desafio. */

.tronikat-chamada {
  position: fixed;
  right: 92px;
  bottom: 34px;
  z-index: 49;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 9px 12px;
  background: var(--superficie);
  border: 1px solid var(--destaque);
  border-radius: 14px;
  pointer-events: none;
  animation: chamada-entra .5s ease both, chamada-boia 2.8s ease-in-out .5s infinite;
}

/* A cauda, apontando para o botao. Dois triangulos sobrepostos: o de tras faz
   a borda ciano, o da frente tapa com a cor do balao. Sem o segundo, a cauda
   sairia com um risco no meio. */
.tronikat-chamada::before,
.tronikat-chamada::after {
  content: "";
  position: absolute;
  right: -7px;
  top: 50%;
  margin-top: -6px;
  border: 6px solid transparent;
  border-left-color: var(--destaque);
}
.tronikat-chamada::after {
  right: -5px;
  border-left-color: var(--superficie);
}

.tronikat-chamada i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--visor);
  animation: pontinho 1.25s ease-in-out infinite;
}
/* O atraso escalonado e o que faz ler como "digitando" em vez de tres luzes
   piscando juntas. */
.tronikat-chamada i:nth-child(2) { animation-delay: .16s; }
.tronikat-chamada i:nth-child(3) { animation-delay: .32s; }

@keyframes pontinho {
  0%, 60%, 100% { opacity: .28; transform: translateY(0); }
  30%           { opacity: 1;   transform: translateY(-4px); }
}

@keyframes chamada-entra {
  from { opacity: 0; transform: translateX(10px) scale(.9); }
  to   { opacity: 1; transform: translateX(0) scale(1); }
}

/* Boia de leve. Dois pixels: mais que isso vira um balao saltitante, e a
   regra da respiracao do mascote (2%) vale pelo mesmo motivo. */
@keyframes chamada-boia {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

/* O BRILHO DO BOTAO, que e a outra metade do "em destaque" que ele pediu.
   Ele pulsa so enquanto a chamada esta na tela. */
.btn-tronikat.chamando {
  animation: pulso 2.4s ease-in-out infinite;
}
@keyframes pulso {
  0%, 100% { box-shadow: 0 6px 22px rgba(0, 0, 0, .45), 0 0 0 0 rgba(0, 229, 255, .45); }
  50%      { box-shadow: 0 6px 22px rgba(0, 0, 0, .45), 0 0 0 10px rgba(0, 229, 255, 0); }
}

/* Parado para quem pediu menos movimento -- mas VISIVEL, porque a chamada
   existe para ser notada e esconde-la tiraria o recurso de quem ja tem menos
   pistas na tela. */
@media (prefers-reduced-motion: reduce) {
  .tronikat-chamada,
  .tronikat-chamada i,
  .btn-tronikat.chamando { animation: none; }
  .tronikat-chamada i { opacity: 1; }
}

@media (max-width: 560px) {
  .tronikat-chamada { right: 78px; bottom: 26px; padding: 7px 10px; }
}

/* ==================================== o retrato do codec, na janela do jogo
 *
 * O desenho vem de `../site/codec.js`, o MESMO arquivo que o site carrega --
 * pedido do Gustavo: "tem que ser igual a da home do site, estilo metal gear,
 * talvez reaproveitar aquela mesmo". Reaproveitar, e nao copiar: mascote
 * desenhado em dois lugares diverge, e aqui a divergencia seria na cara dele.
 */
.tronikat-vivo {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;   /* sem isto o filho que rola estoura a altura da janela */
}

.tronikat-retrato {
  padding: 10px 12px 0;
  display: flex;
  justify-content: center;
}

/* O canvas e de 128x96 e sobe ampliado. `pixelated` e o que produz o pixel
   grande do codec -- o desenho la dentro e feito com anti-serrilhado, em baixa
   resolucao, e a ampliacao faz o resto. Desenhar em quadradinhos daria Atari,
   e nao PlayStation. */
#retrato {
  width: 168px;
  height: 126px;
  image-rendering: pixelated;
  border: 1px solid var(--linha);
  border-radius: 6px;
  background: #06110C;
}
