/*
 * Legalizeer: o movimento. Cada animação diz uma coisa verdadeira (plano de 2026-11-08, frente B, tabela 1–15).
 * Curvas da casa: CHEGA --ease-in (.16,1,.3,1), MUDA --ease-move (.77,0,.18,1), SAI --ease-out (.7,0,.84,0). Sem ressaltos.
 * Tempos: --t-fast 180ms, --t-ui 320ms, --t-move 450ms. As saídas duram ~70 % da entrada e aceleram.
 * Orçamento: no máximo 3 coisas a mexer e 2 a começar ao mesmo tempo.
 * prefers-reduced-motion: mostra logo o estado final (fim do ficheiro).
 * O JavaScript que acompanha está em public/js/motion.js.
 */

html { background: var(--paper); }

/* ── 1. Entre páginas: é a mesma app, não um site a recarregar. ─────────── */
/* O conteúdo sai em 220 ms e entra desfocado a focar (6 → 0 px, +8 px) em 320 ms. Nunca um ecrã branco:
   a página antiga fica à vista até a nova estar pronta, e por baixo está o papel. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: vt-out 220ms var(--ease-out) both; }
::view-transition-new(root) { animation: vt-in var(--t-ui) var(--ease-in) both; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; filter: blur(6px); transform: translateY(8px); } }
/* A barra de cima e a de baixo ficam: não piscam. */
::view-transition-old(topbar), ::view-transition-old(tabbar) { animation: none; opacity: 0; }
::view-transition-new(topbar), ::view-transition-new(tabbar) { animation: none; }
::view-transition-group(topbar), ::view-transition-group(tabbar) { animation: none; z-index: 2; }

/* ── 2. A chapa voa da lista para o processo (e volta): é este carro. ───── */
::view-transition-group(*.plate) { animation-duration: var(--t-move); animation-timing-function: var(--ease-move); z-index: 3; }
::view-transition-old(*.plate), ::view-transition-new(*.plate) { animation-duration: var(--t-move); animation-timing-function: var(--ease-move); height: 100%; object-fit: fill; }

/* ── 13. O traço do separador ativo desliza (Hoje, Processos, Emails). ─── */
::view-transition-group(nav-ink), ::view-transition-group(tab-ink) { animation-duration: var(--t-move); animation-timing-function: var(--ease-move); z-index: 3; }

/* ── 3. Listas: as primeiras 5 linhas entram em cascata; as outras já lá estão. */
.cascade-in { animation: row-in var(--t-ui) var(--ease-in) both; animation-delay: calc(80ms + var(--i, 0) * 60ms); }
@keyframes row-in { from { opacity: 0; transform: translateY(8px); filter: blur(4px); } }

/* ── 4. Os contadores rolam como um conta-quilómetros, de 0 até ao valor. ── */
.odo-col { display: inline-block; height: 1em; overflow: hidden; vertical-align: top; line-height: 1; }
.odo-strip { display: flex; flex-direction: column; transform: translateY(calc(var(--d, 0) * -1em)); transition: transform 600ms var(--ease-in); transition-delay: var(--delay, 0ms); }
.odo-strip > span { display: block; height: 1em; line-height: 1; }
.odo-still .odo-strip { transition: none; }

/* ── 5. Avançar passo: o círculo desenha o visto, a ligação enche-se, o anel passa ao seguinte. ── */
/* 400 ms (visto) + 450 ms (ligação, MUDA, a começar aos 300) + 320 ms (anel e cartão, aos 650): ~1 s ao todo.
   O cartão não fica vazio à espera: o texto do passo novo já lá está, desfocado, e foca. */
.steps li.just-done .n { animation: n-done 300ms var(--ease-in) both; }
.steps li.just-done .n path, .steps li.just.done .n path { stroke-dasharray: 24; stroke-dashoffset: 24; animation: draw 400ms var(--ease-in) 120ms forwards; }
.steps li.just::after { animation: line-fill var(--t-move) var(--ease-move) 300ms both; }
.steps li.just.current .n { animation: ring-in var(--t-ui) var(--ease-in) 650ms both; }
.steps li.just.done .n { animation: n-done 300ms var(--ease-in) 650ms both; }
.steps li.just.done .n path { animation-delay: 730ms; }
.steps li.just > span:last-child { animation: label-in var(--t-ui) var(--ease-in) 650ms both; }
@keyframes n-done { from { background: var(--cobalt); border-color: var(--cobalt); box-shadow: 0 0 0 4px var(--cobalt-soft); } }
@keyframes line-fill { from { transform: scaleX(0); } }
@keyframes ring-in { from { background: var(--white); border-color: var(--line-strong); color: var(--muted); box-shadow: 0 0 0 0 var(--cobalt-soft); } }
@keyframes label-in { from { color: var(--muted); } }
.now.is-just .now-swap { animation: now-in 420ms var(--ease-in) 650ms both; }
@keyframes now-in { from { opacity: .3; filter: blur(8px); } }
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes focus-in { from { opacity: 0; filter: blur(6px); transform: translateY(6px); } }

/* ── 6 e as outras conclusões: a chapa monta-se, o visto desenha-se, diz-se o que aconteceu. ── */
.done-overlay { --tick-at: 650ms; animation: fade-in 260ms var(--ease-in) both; }
.done-overlay.done-swap { --tick-at: 820ms; }
.done-overlay.is-out { animation: fade-out 230ms var(--ease-out) forwards; }
.done-overlay .plate-xl { animation: plate-rise 420ms var(--ease-in) both; }
.done-card h2 { animation: rise 420ms var(--ease-in) calc(var(--tick-at) + 150ms) both; }
.done-card p { animation: rise 420ms var(--ease-in) calc(var(--tick-at) + 250ms) both; }
.done-card .btn { animation: rise 420ms var(--ease-in) calc(var(--tick-at) + 400ms) both; }
.done-card p .btn { animation: none; }
.done-tick .ring { stroke-dasharray: 1; stroke-dashoffset: 1; transform: rotate(-90deg); transform-origin: center; transform-box: fill-box; animation: draw 450ms var(--ease-in) var(--tick-at) forwards; }
.done-tick .fill { opacity: 0; animation: fade-to 220ms var(--ease-in) calc(var(--tick-at) + 330ms) forwards; }
.done-tick .mark { stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw 280ms var(--ease-in) calc(var(--tick-at) + 420ms) forwards; }
@keyframes plate-rise { from { opacity: 0; transform: translateY(14px) scale(.97); filter: blur(6px); } }
@keyframes rise { from { opacity: 0; transform: translateY(10px); filter: blur(4px); } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-to { to { opacity: 1; } }
@keyframes fade-out { to { opacity: 0; visibility: hidden; } }

/* A matrícula atribuída: a chapa estrangeira troca letra a letra pela portuguesa (~1,4 s, uma vez). */
.plate-swap .plate-text, .plate-swap .plate-band { display: grid; }
.plate-swap .layer { grid-area: 1 / 1; display: flex; justify-content: center; align-items: center; }
.plate-swap .plate-band .layer { align-items: end; }
.plate-swap .ch { display: inline-block; white-space: pre; }
.plate-swap .layer-new .ch { opacity: 0; }
.plate-swap.is-run .layer-old .ch { animation: ch-out 240ms var(--ease-out) both; animation-delay: calc(300ms + var(--i, 0) * 40ms); }
.plate-swap.is-run .layer-new .ch { animation: ch-in 380ms var(--ease-in) both; animation-delay: calc(360ms + var(--i, 0) * 40ms); }
.plate-swap.is-run .plate-band { animation: band-pt 400ms var(--ease-in) 300ms both; }
.plate-swap.is-run { animation: plate-rise 420ms var(--ease-in) both, plate-pt 400ms var(--ease-in) 760ms both; }
@keyframes ch-out { to { opacity: 0; transform: translateY(-.45em); filter: blur(6px); } }
@keyframes ch-in { from { opacity: 0; transform: translateY(.45em); filter: blur(6px); } to { opacity: 1; transform: none; filter: none; } }
@keyframes band-pt { from { background: var(--cobalt-deep); } to { background: var(--cobalt); } }
@keyframes plate-pt { from { border-color: var(--ink); } to { border-color: var(--go-ink); } }
.plate-swap { border-color: var(--go-ink); }

/* A chapa monta-se: as letras entram uma a uma, desfocadas, a focar (data-assemble). */
.plate[data-assemble] .ch { display: inline-block; opacity: 0; filter: blur(6px); transform: translateY(.35em); }
.plate[data-assemble].is-in .ch {
  opacity: 1; filter: blur(0); transform: none;
  transition: opacity .38s var(--ease-in), filter .5s var(--ease-in), transform .5s var(--ease-in);
  transition-delay: calc(var(--i) * 45ms + 120ms);
}

/* ── 7. (frente D) Leitura com IA: «a ler…» com o tempo, campos escritos em mono, o código acende. ── */
.reading-chip { display: inline-flex; align-items: center; gap: 8px; min-height: 32px; padding: 0 10px; border-radius: var(--r-pill); background: var(--cobalt-soft); color: var(--cobalt-ink); font: 700 17px/1.2 var(--font); }
.reading-chip [data-elapsed-since] { font-family: var(--mono); font-variant-numeric: tabular-nums; }
[data-typewrite] { font-family: var(--mono); }
.is-typing::after { content: ''; display: inline-block; width: .55em; height: 1.05em; margin-left: 1px; vertical-align: text-bottom; background: currentColor; opacity: .55; }
[data-field-code] { transition: background-color var(--t-ui) var(--ease-in), color var(--t-ui) var(--ease-in); border-radius: 4px; }
[data-field-code].is-lit { background: var(--cobalt-soft); color: var(--cobalt-ink); }

/* ── 8. Juntar um papel: a miniatura desliza para o quadro e o nome escreve-se. ── */
.doc.is-new .doc-ic { animation: slide-in 350ms var(--ease-in) both; }
.doc.is-new { animation: new-row 1.6s var(--ease-in) both; }
@keyframes slide-in { from { opacity: 0; transform: translateX(-24px); } }
@keyframes new-row { from { background-color: var(--go-soft); } to { background-color: transparent; } }

/* ── 9. Diálogo «Sim, apagar»: o fundo escurece, o diálogo sobe; ao fechar, o inverso. ── */
dialog.confirm[open] { animation: dlg-in var(--t-ui) var(--ease-in) both; }
dialog.confirm[open]::backdrop { animation: fade-in 200ms var(--ease-in) both; }
dialog.confirm.is-closing { animation: dlg-out 220ms var(--ease-out) both; }
dialog.confirm.is-closing::backdrop { animation: fade-out 220ms var(--ease-out) both; }
@keyframes dlg-in { from { opacity: 0; transform: translateY(16px) scale(.98); } }
@keyframes dlg-out { to { opacity: 0; transform: translateY(12px) scale(.98); } }

/* ── 10. Guardado: um aviso pequeno em baixo, o visto a desenhar-se e uma linha fina a encolher. ── */
.toast { animation: toast-in var(--t-ui) var(--ease-in) both; }
.toast-tick path { stroke-dasharray: 24; stroke-dashoffset: 24; animation: draw var(--t-ui) var(--ease-in) 240ms forwards; }
.toast-line { animation: line-shrink var(--toast-dur, 4s) linear both; }
.toast:hover .toast-line, .toast:focus-within .toast-line { animation-play-state: paused; }
.toast.is-out { animation: toast-out 220ms var(--ease-out) forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(16px); filter: blur(4px); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(12px); } }
@keyframes line-shrink { to { transform: scaleX(0); } }

/* ── 11. O que abre, cresce: a altura cresce e o conteúdo entra desfocado a focar. ── */
:root { interpolate-size: allow-keywords; }
details.more::details-content { height: 0; overflow: clip; transition: height 220ms var(--ease-out), content-visibility 220ms allow-discrete; }
details.more[open]::details-content { height: auto; transition: height var(--t-ui) var(--ease-in), content-visibility var(--t-ui) allow-discrete; }
details.more[open] > :not(summary) { animation: focus-in var(--t-ui) var(--ease-in) both; }
.menu[open] .menu-list { animation: drop 200ms var(--ease-in) both; }
@keyframes drop { from { opacity: 0; transform: translateY(-6px); } }

/* ── 12. Filtros e pesquisa: os resultados trocam no sítio (180 ms). ── */
[data-swap] { transition: opacity 120ms var(--ease-out); }
[data-swap].is-out { opacity: .45; }
.is-swapped-in { animation: swap-in var(--t-fast) var(--ease-in) both; }
@keyframes swap-in { from { opacity: 0; filter: blur(3px); } }
.swap-skeleton { display: none; }
[data-swap-root].is-waiting [data-swap="results"] { display: none; }
[data-swap-root].is-waiting .swap-skeleton { display: grid; animation: fade-in var(--t-fast) var(--ease-in) both; }
/* (frente D) Na pesquisa com IA, os filtros entendidos entram como pílulas, uma a uma. */
[data-understood] > * { animation: rise var(--t-ui) var(--ease-in) both; animation-delay: calc(var(--i, 0) * 60ms); }

/* ── 14. (frente D) Resumo do dia: o texto aparece palavra a palavra, uma vez. ── */
[data-words] .w { opacity: 0; animation: word-in 260ms var(--ease-in) forwards; animation-delay: calc(var(--i, 0) * var(--step, 40ms)); }
@keyframes word-in { from { opacity: 0; filter: blur(4px); } to { opacity: 1; filter: none; } }

/* ── 15. Carregamento: a forma da página, sem brilho a passar, até o conteúdo chegar. ── */
html.is-loading main.page > :not(.page-skeleton) { display: none; }
html.is-loading .page-skeleton { display: block; animation: fade-in var(--t-fast) var(--ease-in) both; }

/* O aviso de emails novos do Hoje (pulso) entra a focar. */
.pulse-news.is-new { animation: rise var(--t-ui) var(--ease-in) both; }

/* ── Movimento reduzido: o estado final, já. ───────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-delay: 0ms !important; transition-duration: .01ms !important; transition-delay: 0ms !important; }
  .plate[data-assemble] .ch { opacity: 1; filter: none; transform: none; }
  [data-words] .w { opacity: 1; }
}
