/* =============================================================================
 * NYU NODE · movimento e estados
 * -----------------------------------------------------------------------------
 * Sete estados, e a regra que os governa é uma só: só `loading` tem laço.
 * Todo o resto acontece uma vez e para. Personagem que se mexe o tempo todo
 * ao lado de um gráfico disputa a atenção com o número, e o número é o produto.
 *
 * TOKENS · este arquivo não cria cor nenhuma. Usa `--nb-teal`, `--nb-amber` e
 * `--nb-down` do sistema, com valor de reserva literal só para o caso de o
 * arquivo ser carregado antes da folha base. Critério: zero token
 * novo, zero valor de token alterado.
 *
 * A CURVA LINEAR DA ÓRBITA É DELIBERADA, e contraria a regra de movimento.
 * A regra diz "easing nunca linear", e ele está certo para transição: curva
 * é o que faz uma entrada parecer física. Rotação contínua é outra coisa —
 * não tem entrada nem saída, tem só meio. Pôr `ease-in-out` num giro de 360°
 * em laço produz um solavanco visível no ponto de emenda, porque a velocidade
 * chega a zero no fim e recomeça do zero no início do ciclo seguinte. Linear
 * é a única curva sem costura aparente aqui. A exceção está NOMEADA em
 * `tools/movimento.test.js` e é aferida: se esta regra sumir, o teste reprova
 * a exceção órfã.
 * ========================================================================== */

.nyu-node {
  --nyu-node-size: 48px;
  --nyu-node-t: 240ms;
  --nyu-node-curva: cubic-bezier(.22, .8, .24, 1);

  position: relative;
  display: inline-grid;
  place-items: center;
  inline-size: var(--nyu-node-size);
  block-size: var(--nyu-node-size);
  flex: 0 0 auto;
  /* `contain` impede que a animação do mascote force recálculo de layout na
     página inteira — ele vive numa caixa de tamanho fixo e o que muda dentro
     não sai dela. */
  contain: layout paint;
  isolation: isolate;
}

.nyu-node__art,
.nyu-node__fallback {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  display: block;
}

/* O SVG estático aparece PRIMEIRO e sozinho. Só sai quando o inline entrou —
   e se o JavaScript nunca rodar, ele fica, que é o comportamento correto. */
.nyu-node__fallback { object-fit: contain; opacity: 1; transition: opacity var(--nyu-node-t) ease; }
.nyu-node__art      { opacity: 0; transition: opacity var(--nyu-node-t) ease; }
.nyu-node.is-pronto .nyu-node__fallback { opacity: 0; }
.nyu-node.is-pronto .nyu-node__art      { opacity: 1; }

/* ── as peças, dentro do SVG inline ──────────────────────────────────────── */

/* `transform-box: fill-box` faz o transform-origin valer sobre a caixa do
   próprio elemento e não sobre a do SVG. Sem ele, `center` é o centro do
   viewBox e a peça gira em volta do lugar errado. */
.nyu-node__core,
.nyu-node__visor,
.nyu-node__no { transform-box: fill-box; transform-origin: center; }

/* A ÓRBITA gira em volta do centro do CORPO, que fica em (64,54) num viewBox
   de 128 — ou seja 50% 42,19%. Não é o centro da caixa: o nó de baixo e a base
   puxam o desenho para baixo, e girar em volta de 50% 50% faria a constelação
   inteira bambolear. Aqui `fill-box` seria errado de propósito: a origem tem de
   ser a do SVG, não a da caixa do grupo. */
.nyu-node__orbit { transform-origin: 50% 42.19%; }

/* ── loading · o único laço ──────────────────────────────────────────────── */

.nyu-node[data-state="loading"] .nyu-node__orbit {
  animation: nyu-orbita 2400ms linear infinite;
}
.nyu-node[data-state="loading"] .nyu-node__core {
  animation: nyu-respira 1800ms ease-in-out infinite;
}
.nyu-node[data-state="loading"] .nyu-node__visor {
  animation: nyu-pisca 2400ms ease-in-out infinite;
}
.nyu-node[data-state="loading"] .nyu-node__links {
  animation: nyu-sincroniza 2400ms ease-in-out infinite;
}

/* ── updated e success · uma vez, e para ─────────────────────────────────── */

.nyu-node[data-state="updated"] .nyu-node__core,
.nyu-node[data-state="success"] .nyu-node__core {
  animation: nyu-confirma var(--nyu-node-t) var(--nyu-node-curva) both;
}
.nyu-node[data-state="updated"] .nyu-node__ring,
.nyu-node[data-state="success"] .nyu-node__ring {
  animation: nyu-anel var(--nyu-node-t) var(--nyu-node-curva) both;
}

/* ── warning e error · estáticos, e é de propósito ───────────────────────── */

/* Aviso que pisca é aviso que a pessoa aprende a ignorar, e num produto de
   mercado alavancado o aviso é a informação. Aqui a cor muda e FICA. */
.nyu-node[data-state="warning"] .nyu-node__core   { filter: drop-shadow(0 0 7px var(--nb-amber, #F1A928)); }
.nyu-node[data-state="warning"] .nyu-node__visor  { fill: var(--nb-amber, #F1A928); }
.nyu-node[data-state="error"]   .nyu-node__core   { filter: drop-shadow(0 0 7px var(--nb-down, #F16A6B)); }
.nyu-node[data-state="error"]   .nyu-node__visor  { fill: var(--nb-down, #F16A6B); }
.nyu-node[data-state="connected"] .nyu-node__ring { filter: drop-shadow(0 0 5px var(--nb-teal, #00E5C0)); }

/* `idle` não tem regra nenhuma. É o estado em repouso, e um mascote em repouso
   não se mexe — a ausência de bloco aqui é a decisão, não o esquecimento. */

/* ── os quadros ──────────────────────────────────────────────────────────── */

@keyframes nyu-orbita {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* 3% no máximo, que é o número da especificação visual do NYU Node. Acima disso o
   núcleo "bombeia" e o olho vai para ele em vez de ir para o dado. */
@keyframes nyu-respira {
  0%, 100% { transform: scale(1);    opacity: .86; }
  50%      { transform: scale(1.03); opacity: 1; }
}

/* Dois piscares por ciclo, nos tempos da especificação: 0,65s e 1,85s dentro
   de 2,4s — 27% e 77%. O segundo é mais curto que o primeiro, que é como
   piscar de verdade acontece: o par não é simétrico. */
@keyframes nyu-pisca {
  0%, 24%, 31%, 74%, 79%, 100% { opacity: 1; }
  27%, 77%                     { opacity: .12; }
}

/* As ligações acendem em sequência sugerindo sincronização. Amplitude baixa:
   entre .45 e .95, nunca apagando de vez — linha que some vira falha, e o que
   se quer comunicar é fluxo, não queda. */
@keyframes nyu-sincroniza {
  0%, 100% { opacity: .5; }
  30%      { opacity: .95; }
  62%      { opacity: .55; }
}

@keyframes nyu-confirma {
  0%   { transform: scale(.97); opacity: .74; }
  62%  { transform: scale(1.03); opacity: 1; }
  100% { transform: scale(1);   opacity: 1; }
}

@keyframes nyu-anel {
  0%   { transform: scale(.92); opacity: .55; }
  55%  { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1);   opacity: 1; }
}

/* ── tamanhos ────────────────────────────────────────────────────────────── */

.nyu-node--pequeno { --nyu-node-size: 30px; }
.nyu-node--grande  { --nyu-node-size: 96px; }

/* ── balão de ajuda · o ponto de contato ─────────────────────────────────── */

/* `min-block-size: 44px` no gatilho porque ele é alvo de toque, e 44 é o
   número que este projeto adotou. Não é enfeite: o portão `toque.spec.js`
   mede isto no pixel com ponteiro grosso. */
.nyu-help { position: relative; min-width: 0; margin-top: var(--sp-3, 12px); }

.nyu-help__trigger {
  display: inline-flex; align-items: center; gap: 8px;
  min-block-size: 44px; max-inline-size: 100%;
  padding: 4px 12px 4px 4px;
  font: inherit; font-size: 13px; color: var(--nb-ink-2, #b8c6da);
  background: transparent;
  border: 1px solid var(--nb-line, rgba(255,255,255,.1));
  border-radius: var(--r-md, 10px);
  cursor: pointer; text-align: left;
}
.nyu-help__trigger:hover,
.nyu-help__trigger:focus-visible {
  color: var(--nb-ink, #E7EEF8);
  border-color: var(--nb-line-2, rgba(0,229,192,.3));
}

.nyu-help__painel {
  max-inline-size: min(380px, 100%);
  margin-block-start: 8px; padding: 12px 14px;
  font-size: 13px; line-height: 1.55;
  color: var(--nb-ink-2, #b8c6da);
  background: var(--nb-panel, #101E33);
  border: 1px solid var(--nb-line-2, rgba(0,229,192,.24));
  border-radius: var(--r-md, 10px);
}
.nyu-help__painel p { margin: 0 0 8px; }
.nyu-help__painel a { color: var(--nb-teal, #00E5C0); }
/* `[hidden]` sozinho perde para `display:flex`/`grid` herdado de um pai —
   por isso o `!important`, que aqui não é preguiça, é a única forma de o
   atributo continuar significando o que diz. */
.nyu-help__painel[hidden] { display: none !important; }

@media (max-width: 620px) {
  .nyu-node          { --nyu-node-size: 40px; }
  .nyu-node--pequeno { --nyu-node-size: 28px; }
  .nyu-node--grande  { --nyu-node-size: 72px; }
}

/* ── quem pede menos movimento ───────────────────────────────────────────── */

/* Congela no quadro neutro, não some. O mascote continua ali dizendo o que
   diz; o que ele perde é o movimento. E `animation-iteration-count:1` está
   aqui porque duração de .01ms sozinha não para um `infinite` — ela reinicia,
   e reiniciar milhares de vezes por segundo é pior que a animação original. */
@media (prefers-reduced-motion: reduce) {
  .nyu-node *,
  .nyu-node::before,
  .nyu-node::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ── AGENTE · o Node que responde ────────────────────────────────────────────
   Cada cor aqui é TOKEN, nunca literal, e cada token foi conferido como
   redefinido no bloco do tema claro: `--nb-panel`, `--nb-ink`, `--nb-ink-2`,
   `--nb-teal`, `--nb-line` e `--nb-line-2`. A armadilha já medida nesta casa é
   trocar a tinta e esquecer a superfície — o texto vira, o fundo não, e a
   leitura morre. Nenhum gradiente entra aqui justamente por isso: gradiente é
   a superfície que os temas esquecem.

   `position: fixed` de propósito: elemento fora do fluxo não empurra nada e
   por isso não entra na conta de CLS, que é frente aberta neste produto. */
.nyu-agente {
  position: fixed;
  right: max(16px, env(safe-area-inset-right));
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.nyu-agente__gatilho {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 8px;
  border: 1px solid var(--nb-line-2);
  border-radius: 999px;
  background: var(--nb-panel);
  color: var(--nb-ink);
  font: inherit;
  font-size: .92rem;
  cursor: pointer;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .28);
}
.nyu-agente__gatilho:hover { border-color: var(--nb-teal); }
/* O foco não depende de `:hover` e é visível por si: quem navega por teclado
   precisa ver onde está, e `:hover` não existe em teclado nem em toque. */
.nyu-agente__gatilho:focus-visible {
  outline: 2px solid var(--nb-teal);
  outline-offset: 2px;
}

.nyu-agente__painel {
  width: min(92vw, 380px);
  max-height: min(70vh, 520px);
  overflow-y: auto;
  padding: 14px;
  border: 1px solid var(--nb-line-2);
  border-radius: var(--r-md, 12px);
  background: var(--nb-panel);
  color: var(--nb-ink);
  box-shadow: 0 10px 40px rgba(0, 0, 0, .34);
}
/* Mesmo motivo da linha 198: `[hidden]` sozinho perde para o `display:flex`
   herdado do contêiner, e o atributo deixaria de significar o que diz. */
.nyu-agente__painel[hidden] { display: none !important; }

.nyu-agente__forma { display: flex; gap: 6px; margin: 0 0 10px; }
.nyu-agente__forma input[type=search] {
  flex: 1 1 auto;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--nb-line);
  border-radius: 8px;
  background: transparent;
  color: var(--nb-ink);
  font: inherit;
}
.nyu-agente__forma input[type=search]:focus-visible {
  outline: 2px solid var(--nb-teal);
  outline-offset: 1px;
}
.nyu-agente__forma button {
  padding: 8px 12px;
  border: 1px solid var(--nb-teal);
  border-radius: 8px;
  background: transparent;
  color: var(--nb-teal);
  font: inherit;
  cursor: pointer;
}

/* O FIO DE CONVERSA. Cada troca é um bloco, e os anteriores continuam à vista —
   é o que separa um agente de uma caixa de busca, que esquece a pergunta
   anterior no instante em que recebe a próxima. */
.nyu-agente__troca { padding: 10px 0; border-top: 1px solid var(--nb-line); }
.nyu-agente__troca:first-child { border-top: 0; padding-top: 0; }
.nyu-agente__pergunta {
  margin: 0 0 8px;
  font-size: .88rem;
  color: var(--nb-ink);
}
.nyu-agente__pergunta span {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--nb-teal);
  margin-right: 6px;
}

.nyu-agente__intro,
.nyu-agente__nada,
.nyu-agente__pensando { margin: 0 0 8px; font-size: .88rem; color: var(--nb-ink-2); }
.nyu-agente__nada b { color: var(--nb-ink); }

.nyu-agente__lista { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.nyu-agente__lista li {
  display: grid;
  gap: 2px;
  padding: 8px 10px;
  border: 1px solid var(--nb-line);
  border-radius: 8px;
}
.nyu-agente__lista a { color: var(--nb-teal); font-weight: 600; text-decoration: none; }
.nyu-agente__lista a:hover,
.nyu-agente__lista a:focus-visible { text-decoration: underline; }
.nyu-agente__doc { font-size: .74rem; text-transform: uppercase; letter-spacing: .04em; color: var(--nb-ink-2); }
.nyu-agente__resumo { font-size: .84rem; color: var(--nb-ink-2); }

@media (max-width: 620px) {
  .nyu-agente__gatilho span:not(.nyu-node) { font-size: .86rem; }
}

/* O componente carrega o próprio esconderijo de rótulo. A capa define `.sr-so`
   num `<style>` inline, mas o agente se monta em qualquer página que inclua
   este arquivo — e numa página sem aquele inline o rótulo do campo apareceria
   solto na tela. Regra idêntica à da capa: duplicata que não conflita. */
.sr-so {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* ── camada 3 · o parágrafo escrito ───────────────────────────────────────────
 * O PARÁGRAFO É VISUALMENTE SECUNDÁRIO AOS PONTEIROS, e isso é decisão, não
 * sobra de espaço: quem lê tem de ver primeiro DE ONDE veio, e só depois o
 * resumo. Ponteiro errado a pessoa descarta num olhar; parágrafo errado que
 * chega antes da fonte ela acredita. */
.nyu-agente__escrito {
  margin: 0 0 10px;
  padding: 8px 10px;
  border-left: 2px solid var(--nb-teal);
  background: var(--nb-panel);
  border-radius: 0 8px 8px 0;
  font-size: .88rem;
  line-height: 1.5;
  color: var(--nb-ink);
}
.nyu-agente__marca {
  display: block;
  margin-top: 6px;
  font-size: .72rem;
  color: var(--nb-ink-2);
}

/* O pedido de consentimento. Aparece UMA vez, e as duas saídas são reais: quem
   recusa continua com o assistente inteiro. É essa reversibilidade que torna o
   consentimento livre — e consentimento que não é livre é nulo. */
.nyu-agente__consulta {
  margin: 0 0 10px;
  padding: 10px;
  border: 1px dashed var(--nb-line-2);
  border-radius: 8px;
  font-size: .84rem;
  color: var(--nb-ink-2);
}
.nyu-agente__consulta b { color: var(--nb-ink); }
.nyu-agente__escolhas { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.nyu-agente__escolhas button {
  font: inherit;
  padding: 6px 12px;
  min-height: 32px;
  border: 1px solid var(--nb-line-2);
  border-radius: 6px;
  background: transparent;
  color: var(--nb-ink);
  cursor: pointer;
}
.nyu-agente__escolhas button[data-sim] { border-color: var(--nb-teal); }
.nyu-agente__escolhas button:focus-visible { outline: 2px solid var(--nb-teal); outline-offset: 2px; }

/* ═══ NO TELEFONE ESTREITO O GATILHO PERDE O RÓTULO, NÃO A FUNÇÃO ═══════════
   Medido por `tools/visual/deslizador.spec.js`, em 320px:

     sDup: COBERTO por button.nyu-agente__gatilho

   O gatilho mede 178px numa tela de 320 — 56% da largura — e fica fixo sobre o
   conteúdo. O deslizador do simulador que cai atrás dele não pode ser usado nem
   fotografado, e o defeito não é do deslizador: é de um botão flutuante ocupando
   mais da metade da tela justamente onde a tela é menor.

   Aqui ele encolhe para o ícone. O rótulo NÃO é removido — `display:none`
   levaria junto o nome acessível do botão, e quem usa leitor de tela ouviria
   «botão» e mais nada. Ele é clipado pela mesma técnica do `.sr-so` deste
   arquivo: sai da pintura, fica na árvore de acessibilidade.

   28px de ícone + 9px de cada lado = 46px de alvo, acima dos 44px que
   `tools/visual/toque.spec.js` exige. */
@media (max-width: 420px) {
  .nyu-agente__gatilho { padding: 9px; gap: 0; }
  .nyu-agente__gatilho > span:not(.nyu-node) {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }
}
