/* ========================================================================== 
   Movimento compartilhado — web e mobile

   A interface usa fades curtos para explicar trocas de estado, sem transformar
   navegação e listas operacionais em uma sequência de animações. Páginas e
   painéis usam snapshots do navegador; tabelas grandes animam só o contêiner.
   ========================================================================== */
:root {
  --jn-motion-fast: 160ms;
  --jn-motion-base: 240ms;
  --jn-motion-slow: 320ms;
  --jn-motion-ease: cubic-bezier(.22,.82,.28,1);
}

@media (prefers-reduced-motion:no-preference) {
  /* Entrada inicial: a aplicação autenticada e os cartões de acesso deixam de
     surgir entre dois frames sem qualquer continuidade visual. */
  /* O app-shell contem a sidebar position:fixed. Qualquer translate, mesmo
     terminado em zero, transforma este ancestral no bloco de contencao do
     fixed; em paginas altas a barra passava a medir a altura do documento e
     a toolbar ia parar abaixo da janela. O shell principal recebe fade puro.
     As telas sem descendentes fixos continuam com o pequeno deslocamento. */
  .app-shell {
    animation:jn-first-paint-fade var(--jn-motion-slow) var(--jn-motion-ease) both;
  }

  .auth-shell,
  body > main:not(.main-content):not(.mobile-shell),
  .login-screen .login-card {
    animation:jn-first-paint var(--jn-motion-slow) var(--jn-motion-ease) both;
  }

  @keyframes jn-first-paint-fade {
    from { opacity:0; }
    to { opacity:1; }
  }

  @keyframes jn-first-paint {
    from { opacity:0; translate:0 7px; }
    to { opacity:1; translate:0 0; }
  }

  /* Somente o conteúdo que realmente troca recebe um nome. Barra lateral,
     navegação inferior e demais elementos persistentes permanecem estáveis. */
  html[data-jn-motion="page"] .page:not(.hidden) {
    view-transition-name:jornada-page;
  }

  html[data-jn-motion="mobile-screen"] :is(.login-screen,.app-screen):not(.hidden) {
    view-transition-name:jornada-mobile-screen;
  }

  html[data-jn-motion="mobile-view"] #appScreen:not(.hidden) {
    view-transition-name:jornada-mobile-view;
  }

  html[data-jn-motion="employee"] [data-employee-panel]:not(.hidden),
  html[data-jn-motion="signature"] :is(#signatureCenterFolhaPanel,#signatureCenterReciboPanel,#signatureCenterAvulsoPanel):not(.hidden),
  html[data-jn-motion="receipts"] :is(#recibosEnviosPanel,#recibosAuditoriaPanel):not(.hidden),
  html[data-jn-motion="config"] [data-config-panel]:not(.hidden),
  html[data-jn-motion="company"] [data-company-panel]:not(.hidden),
  html[data-jn-motion="alerts"] #alertRows {
    view-transition-name:jornada-component;
  }

  /* A raiz não pisca: ela muda imediatamente, enquanto apenas a superfície
     nomeada acima conserva a imagem antiga para fazer o crossfade. */
  html[data-jn-motion]::view-transition-old(root) {
    animation:none;
    opacity:0;
    mix-blend-mode:normal;
  }

  html[data-jn-motion]::view-transition-new(root) {
    animation:none;
    mix-blend-mode:normal;
  }

  /* Nenhuma destas trocas é um MORFO — todas são crossfade. O "grupo" é a caixa
     que o navegador interpola entre a posição e o tamanho antigos e os novos, e
     ele anima por conta própria, com tempo e curva do próprio navegador.

     Como as páginas têm alturas muito diferentes (medido nesta tela: de 98px em
     Recibos a 1590px no Painel), essa interpolação virava um segundo movimento
     por cima do fade — a página aparecia e ainda se deslocava um pouco depois,
     lido como uma quebra em duas etapas. Contadas numa troca real, rodavam
     QUATRO animações onde a intenção eram duas: os dois fades desenhados aqui,
     mais o grupo da página (320ms) e o grupo da RAIZ (250ms, o padrão do
     navegador — a raiz nem constava desta regra e por isso passava batido).

     Com o grupo parado, a caixa assume o tamanho novo de uma vez e o único
     movimento é o que está descrito nos fades abaixo. */
  html[data-jn-motion]::view-transition-group(root),
  ::view-transition-group(jornada-page),
  ::view-transition-group(jornada-mobile-screen),
  ::view-transition-group(jornada-mobile-view),
  ::view-transition-group(jornada-component) {
    animation:none;
  }

  ::view-transition-old(jornada-page) {
    animation:jn-page-fade-out var(--jn-motion-fast) ease both;
    mix-blend-mode:normal;
  }

  ::view-transition-new(jornada-page) {
    animation:jn-page-fade-in var(--jn-motion-base) var(--jn-motion-ease) 45ms both;
    mix-blend-mode:normal;
  }

  html[data-jn-motion-direction="backward"]::view-transition-old(jornada-page) {
    animation-name:jn-page-fade-out-backward;
  }

  html[data-jn-motion-direction="backward"]::view-transition-new(jornada-page) {
    animation-name:jn-page-fade-in-backward;
  }

  ::view-transition-old(jornada-mobile-screen),
  ::view-transition-old(jornada-mobile-view),
  ::view-transition-old(jornada-component) {
    animation:jn-component-fade-out 140ms ease both;
    mix-blend-mode:normal;
  }

  ::view-transition-new(jornada-mobile-screen),
  ::view-transition-new(jornada-mobile-view),
  ::view-transition-new(jornada-component) {
    animation:jn-component-fade-in 220ms var(--jn-motion-ease) 35ms both;
    mix-blend-mode:normal;
  }

  @keyframes jn-page-fade-out {
    to { opacity:0; translate:0 -6px; scale:.995; }
  }

  @keyframes jn-page-fade-in {
    from { opacity:0; translate:0 8px; scale:.995; }
    to { opacity:1; translate:0 0; scale:1; }
  }

  @keyframes jn-page-fade-out-backward {
    to { opacity:0; translate:0 6px; scale:.995; }
  }

  @keyframes jn-page-fade-in-backward {
    from { opacity:0; translate:0 -8px; scale:.995; }
    to { opacity:1; translate:0 0; scale:1; }
  }

  @keyframes jn-component-fade-out {
    to { opacity:0; }
  }

  @keyframes jn-component-fade-in {
    from { opacity:0; }
    to { opacity:1; }
  }

  /* Menus, avisos e estados vazios ainda usam .hidden. display participa da
     transição para a saída terminar antes de a superfície deixar o layout. */
  :where(
    .search-results,
    .export-zip-menu-list,
    .update-pill,
    .notice,
    .empty-state,
    .company-gate-banner,
    .totals-sequence-warning,
    .people-clear-filters,
    .install-app,
    .receipt-nsr
  ) {
    opacity:1;
    translate:0 0;
    transition:
      opacity var(--jn-motion-fast) ease,
      translate var(--jn-motion-fast) var(--jn-motion-ease),
      display var(--jn-motion-fast) allow-discrete;
    transition-behavior:allow-discrete;
  }

  :where(
    .search-results,
    .export-zip-menu-list,
    .update-pill,
    .notice,
    .empty-state,
    .company-gate-banner,
    .totals-sequence-warning,
    .people-clear-filters,
    .install-app,
    .receipt-nsr
  ).hidden {
    opacity:0 !important;
    translate:0 -4px;
  }

  @starting-style {
    :where(
      .search-results,
      .export-zip-menu-list,
      .update-pill,
      .notice,
      .empty-state,
      .company-gate-banner,
      .totals-sequence-warning,
      .people-clear-filters,
      .install-app,
      .receipt-nsr
    ):not(.hidden) {
      opacity:0;
      translate:0 -4px;
    }
  }

  /* No desktop os dialogs permanecem exatamente na mesma posição durante
     toda a saída e desaparecem só por opacidade. No celular ui-dialogs.css
     continua sendo a fonte do movimento da gaveta lateral. */
  @media (min-width:721px) {
    dialog {
      /* Ao executar close(), o elemento perde :modal antes de o fade acabar.
         Sem uma posicao propria, o estilo nativo troca fixed por absolute e
         dialogos altos (como Nova jornada) sobem no primeiro quadro da saida. */
      position:fixed;
      inset:0;
      margin:auto;
      opacity:0;
      /* A escala fica em 1 aqui de propósito: este é o estado de SAÍDA, e ela
         não encolhe. Só a entrada cresce — ver o bloco `dialog[open]`. */
      scale:1;
      transition:
        opacity var(--jn-motion-base) var(--jn-motion-ease),
        overlay var(--jn-motion-base) allow-discrete,
        display var(--jn-motion-base) allow-discrete;
      transition-behavior:allow-discrete;
    }

    /* ENTRADA. Uma transição pega os tempos do estado para o qual vai, então é
       aqui — e não na regra acima — que a abertura é descrita.

       A abertura era instantânea: o card nascia opaco no primeiro quadro. Isso
       resolvia um defeito real (nascendo em opacity:0, o botão "+ Novo" do
       fundo aparecia ATRAVÉS do card enquanto ele surgia), mas ao custo de a
       janela simplesmente estar lá, sem nenhuma leitura de que algo abriu.

       A saída para os dois é separar os tempos: a OPACIDADE entra rápido
       (--jn-motion-fast), então o card fica sólido em pouco mais de dois
       quadros e nada do fundo o atravessa; a ESCALA continua acomodando por
       --jn-motion-base, e é ela que dá o sentido de "abriu".

       0.96, e não algo menor: o diálogo é grande, e uma escala mais funda vira
       zoom em vez de acomodação. Nada de escala 0 — nenhuma superfície começa
       do nada. Diálogo modal não sai de um botão, então cresce do próprio
       centro (transform-origin padrão) em vez de apontar para uma origem. */
    dialog[open] {
      opacity:1;
      scale:1;
      transition:
        opacity var(--jn-motion-fast) var(--jn-motion-ease),
        scale var(--jn-motion-base) var(--jn-motion-ease),
        overlay var(--jn-motion-base) allow-discrete,
        display var(--jn-motion-base) allow-discrete;
    }

    @starting-style {
      dialog[open] {
        opacity:0;
        scale:.96;
      }
    }

    /* Sem `@starting-style`: o escurecimento cobre o fundo já no primeiro
       quadro, e é a outra metade da proteção contra o defeito antigo — com o
       fundo apagado, não há o que atravessar o card enquanto ele chega. A
       transição daqui vale, então, só para a saída. */
    dialog::backdrop {
      opacity:0;
      transition:
        opacity var(--jn-motion-base) var(--jn-motion-ease),
        overlay var(--jn-motion-base) allow-discrete,
        display var(--jn-motion-base) allow-discrete;
      transition-behavior:allow-discrete;
    }

    dialog[open]::backdrop { opacity:1; }
  }
}

/* Um diálogo fechado não termina a saída por cima de outro que está abrindo.

   A saída dura `--jn-motion-base`, e nesse intervalo o diálogo continua na top
   layer, ainda opaco no primeiro quadro. Se outro abrir dentro dessa janela —
   fechar "Criar jornada" e clicar "+ Novo" logo em seguida, por exemplo — os
   dois aparecem juntos: os campos do antigo piscam atrás do card novo.

   `closeDialogThen` (app.js) já resolve isso no caminho do próprio "+ Novo",
   esperando o fade antes de abrir o destino. Esta regra cobre o caso geral, que
   depende do tempo do clique de quem usa e não de um caminho específico: com
   algum diálogo aberto, quem está fechando some na hora em vez de disputar a
   tela. Vale para o desktop e para a gaveta do celular.

   `!important` porque a saída é justamente uma transição de `display`. */
body:has(dialog[open]) dialog:not([open]),
body:has(dialog[open]) dialog:not([open])::backdrop {
  /* `transition:none` junto, e não só o `display`: a saída transiciona o
     próprio `display` com `allow-discrete`, então sem cortar a transição o
     `display:none` ficaria agendado para o fim do fade — exatamente o intervalo
     que se quer eliminar. */
  transition: none !important;
  display: none !important;
}

/* Seletor deslizante compartilhado. O botão ativo conserva somente conteúdo e
   cor; a superfície branca/azul/escura é uma peça única posicionada pelo
   runtime. Assim a pílula percorre opções de larguras diferentes em vez de uma
   desaparecer e outra nascer no destino. */
.jn-sliding-pill {
  --jn-pill-indicator-bg:#fff;
  --jn-pill-indicator-border:0 solid transparent;
  --jn-pill-indicator-radius:var(--radius-pill,999px);
  --jn-pill-indicator-shadow:0 2px 8px rgba(36,65,95,.11);
  isolation:isolate;
}

.jn-sliding-pill:not(.mobile-nav) { position:relative; }

.jn-sliding-pill > .jn-pill-indicator {
  position:absolute;
  z-index:0;
  top:0;
  left:0;
  box-sizing:border-box;
  width:var(--jn-pill-width,0px);
  height:var(--jn-pill-height,0px);
  border:var(--jn-pill-indicator-border);
  border-radius:var(--jn-pill-indicator-radius);
  background:var(--jn-pill-indicator-bg);
  box-shadow:var(--jn-pill-indicator-shadow);
  opacity:0;
  pointer-events:none;
  transform:translate3d(var(--jn-pill-x,0px),var(--jn-pill-y,0px),0);
  transition:
    transform var(--jn-motion-base) var(--jn-motion-ease),
    width var(--jn-motion-base) var(--jn-motion-ease),
    height var(--jn-motion-fast) ease,
    opacity var(--jn-motion-fast) ease;
  will-change:transform,width;
}

.jn-sliding-pill.jn-pill-ready > .jn-pill-indicator { opacity:1; }

.jn-sliding-pill > button {
  position:relative !important;
  z-index:1;
}

.jn-sliding-pill > button.active {
  background:transparent !important;
  box-shadow:none !important;
}

/* Variações preservam a superfície original de cada contexto. */
.alert-subtabs,
.document-category-tabs {
  --jn-pill-indicator-bg:rgba(255,255,255,.12);
  --jn-pill-indicator-shadow:none;
}

.mobile-nav {
  --jn-pill-indicator-bg:rgba(65,110,236,.16);
  --jn-pill-indicator-shadow:none;
}

/* O filtro de mes so existe no mobile (mobile.html), sobre o vidro escuro.
   Herdava a pilula do tema claro — retangulo #eaf1ff quase branco, borda azul
   1px e anel de foco — que destoava de tudo em volta. Agora usa exatamente a
   mesma pilula do menu inferior: azul translucido, raio de pilula, sem borda. */
.history-periods {
  --jn-pill-indicator-bg:rgba(65,110,236,.16);
  --jn-pill-indicator-border:0 solid transparent;
  --jn-pill-indicator-radius:var(--radius-pill,999px);
  --jn-pill-indicator-shadow:none;
}

.records-display-segment :is(.records-density,.records-order) {
  --jn-pill-indicator-bg:var(--ink,#1f2c3d);
  --jn-pill-indicator-radius:8px;
  --jn-pill-indicator-shadow:none;
}

.history-periods.jn-sliding-pill > button.active,
.records-display-segment .jn-sliding-pill > button.active {
  border-color:transparent !important;
}

@media (prefers-reduced-motion:reduce) {
  .app-shell,
  .auth-shell,
  body > main,
  .login-card,
  .jn-view-enter {
    animation:none !important;
  }

  :where(
    .search-results,
    .export-zip-menu-list,
    .update-pill,
    .notice,
    .empty-state,
    .company-gate-banner,
    .totals-sequence-warning,
    .people-clear-filters,
    .install-app,
    .receipt-nsr,
    .jn-pill-indicator,
    .jn-sliding-pill > button,
    dialog,
    dialog::backdrop
  ) {
    transition:none !important;
  }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation-duration:.01ms !important;
    animation-delay:0s !important;
  }
}


/* O seletor deslizante é estado, não enfeite — mesma razão do bloco equivalente
   em ui-refinement.css (16/09/2026, pedido do dono). A pílula existe justamente
   para mostrar de onde para onde a escolha foi; parada, ela não informa nada
   que o fundo colorido já não dissesse, e o seletor de páginas passa a "trocar"
   sem transição. Só `transition` volta: nenhuma keyframe decorativa. */
@media (prefers-reduced-motion:reduce) {
  .jn-sliding-pill > .jn-pill-indicator {
    transition:
      transform var(--jn-motion-base) var(--jn-motion-ease),
      width var(--jn-motion-base) var(--jn-motion-ease),
      height var(--jn-motion-fast) ease,
      opacity var(--jn-motion-fast) ease !important;
  }
}
