/* Sinchi: motion (owner: motion). Linked by the head part after site.css; site.js does the rest.
   Values are the motion tokens in tokens.css (local-business-studio/reference/motion.md). The signature
   is the circle: things open with clip-path: circle() from their centre or from data-origem, and the
   seal's ring turns with the scroll. Only transform (translate, rotate), opacity and clip-path move.

   The guard. An element starts hidden only under html.js, outside reduced motion and outside
   html.reduced; site.js adds html.movimento when it runs and reveals each element once. html.reduced
   (reduced motion, or no IntersectionObserver / Web Animations) matches none of the hiding rules, so
   everything shows still. If site.js never runs, a CSS safety net shows everything at 3 s.

   What moves, where and why (find-animation-opportunities, 8 October 2026):
   1. Page change, every navigation: a short crossfade, the old page up 6 px, the new one from 12 px
      below (back: the other way). The header (cabecalho) stays put; the seal (selo) travels between
      two pages that both show it, and opens as a circle on a page that has it alone.
   2. Arrival: the poster title rises line by line through its mask, then the lead and the actions.
   3. data-circulo / data-rv="circulo": the brand reveal, a circle opening from the centre or data-origem.
   4. data-rv="sobe" (lift), "lado" (from the nearer side), "mascara" (lines through their mask, or a
      curtain for a block); data-rv-kids: children in turn, 55 ms apart, capped at 440 ms (a group whose
      only child is a list staggers the list's items). What is on screen when the page opens starts
      after the poster title.
   5. data-selo-gira: the ring turns as the seal crosses the screen (scroll-driven, compositor only).
   6. Shell components with no hook of their own: the hours (days in turn, the «now» marker slides to
      the hour), the rating discs (open as circles), the pattern bands (unroll from the left).
   7. Press: the arrow of a .ligacao nudges forward under the finger (.btn and .btn-circ: site.css). */

/* 1. Page change ------------------------------------------------------------------------------- */

@view-transition { navigation: auto; types: pagina; }

:root:active-view-transition-type(pagina)::view-transition-old(root) {
  animation: pag-sai var(--d-page-out) var(--e-out) both;
}
:root:active-view-transition-type(pagina)::view-transition-new(root) {
  animation: pag-entra var(--d-page-in) var(--e-out) both;
}
:root:active-view-transition-type(volta)::view-transition-old(root) { animation-name: pag-sai-volta; }
:root:active-view-transition-type(volta)::view-transition-new(root) { animation-name: pag-entra-volta; }
@keyframes pag-sai { to { opacity: 0; transform: translateY(-6px); } }
@keyframes pag-entra { from { opacity: 0; transform: translateY(12px); } }
@keyframes pag-sai-volta { to { opacity: 0; transform: translateY(6px); } }
@keyframes pag-entra-volta { from { opacity: 0; transform: translateY(-12px); } }

/* The header is the same on every page: it holds still above the crossfade. */
::view-transition-group(cabecalho) {
  z-index: 2;
  animation-duration: var(--d-page-in);
  animation-timing-function: var(--e-out);
}
::view-transition-old(cabecalho), ::view-transition-new(cabecalho) { animation-duration: var(--d-micro); }

/* The seal: one per page carries the name. The seal in the first block of <main> has it from the first
   frame, because a new page can be drawn, and its picture taken, before the deferred site.js runs;
   site.js then gives it to the seal on screen and writes none on the others. On both pages the seal
   travels to its new place; the ring may sit at another angle there, so the new picture shows at once
   instead of crossfading two rings. Alone on the new page it opens as a circle; alone on the old page
   it fades. */
@media (prefers-reduced-motion: no-preference) {
  main > :first-child [data-selo-gira], main > [data-selo-gira]:first-child { view-transition-name: selo; }
}
::view-transition-group(selo) {
  z-index: 1;
  animation-duration: 420ms;
  animation-timing-function: var(--e-in-out);
}
::view-transition-old(selo):not(:only-child) { animation: none; opacity: 0; }
::view-transition-new(selo):not(:only-child) { animation: none; }
::view-transition-new(selo):only-child { animation: selo-abre var(--d-circle) var(--e-in-out) both; }
::view-transition-old(selo):only-child { animation: pag-esmaece-sai var(--d-page-out) var(--e-out) both; }
@keyframes selo-abre {
  from { clip-path: circle(6% at 50% 50%); }
  to { clip-path: circle(71% at 50% 50%); }
}
@keyframes pag-esmaece-sai { to { opacity: 0; } }
@keyframes pag-esmaece-entra { from { opacity: 0; } }

/* 2 to 6. Arrival and reveals: hidden states, only with JavaScript and full motion ------------- */

@media (prefers-reduced-motion: no-preference) {
  /* The poster title: CSS keyframes, so it plays from the first frame and needs no script. Wrapped in
     :where() so a page that animates its own title (the booking confirmation) wins. */
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv])) .ln > span {
    animation: ln-sobe var(--d-title-line) var(--e-out) 60ms both;
  }
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) .ln:nth-child(2 of .ln)) > span { animation-delay: calc(60ms + var(--d-title-stagger)); }
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) .ln:nth-child(3 of .ln)) > span { animation-delay: calc(60ms + 2 * var(--d-title-stagger)); }
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) .ln:nth-child(4 of .ln)) > span { animation-delay: calc(60ms + 3 * var(--d-title-stagger)); }
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) .ln:nth-child(n + 5 of .ln)) > span { animation-delay: calc(60ms + 4 * var(--d-title-stagger)); }
  /* Then the lead, the actions and any short line after the title, unless they carry a hook of their
     own (site.js then starts them after the title). */
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) ~ .lead):not([data-rv]) { animation: chega 300ms var(--e-out) 320ms both; }
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) ~ .acoes):not([data-rv]) { animation: chega 300ms var(--e-out) 380ms both; }
  :where(html.js:not(.reduced) .titulo-cartaz:not([data-rv]) ~ p:not(.lead)):not([data-rv]) { animation: chega 300ms var(--e-out) 440ms both; }

  /* Reveals waiting for site.js. Opacity only: the movement comes from the animation itself. */
  html.js:not(.reduced) [data-rv]:not([data-rv="circulo"], [data-rv="mascara"], .is-in),
  html.js:not(.reduced) [data-rv="mascara"]:not(:has(.ln), .is-in),
  html.js:not(.reduced) [data-rv-kids] > :not(.is-in, :only-child:is(ul, ol, dl)),
  html.js:not(.reduced) [data-rv-kids] > :only-child:is(ul, ol, dl) > :not(.is-in) { opacity: 0; }
  html.js:not(.reduced) [data-rv="mascara"]:not(.is-in) .ln > span { translate: 0 105%; }
  /* The circle keeps a small disc of the picture visible: it never starts from nothing, and the
     first-screen photo (the LCP) is painted from the first frame. */
  html.js:not(.reduced) :is([data-circulo], [data-rv="circulo"]):not(.is-in) {
    clip-path: circle(6% at var(--origem, 50% 50%));
  }

  /* Shell components, unless a page hook already moves them or what holds them. */
  html.js:not(.reduced) .horario__semana:not(:is([data-rv], [data-rv-kids], [data-circulo]) *) > .horario__dia:not(.is-in) { opacity: 0; }
  html.js:not(.reduced) .avaliacao__nota:not(:is([data-rv], [data-rv-kids], [data-circulo]) *, .is-in) { clip-path: circle(6% at 50% 50%); }
  html.js:not(.reduced) .faixa:not(:is([data-rv], [data-rv-kids], [data-circulo]) *, [data-rv], [data-circulo], .is-in) { clip-path: inset(0 100% 0 0); }

  /* Safety net: if site.js never adds html.movimento, everything shows at 3 s. */
  html.js:not(.movimento, .reduced) :is(
    [data-rv], [data-rv-kids] > *, [data-rv-kids] > :only-child > *, [data-circulo], [data-rv="mascara"] .ln > span,
    .horario__dia, .avaliacao__nota, .faixa
  ) { animation: rv-rede 1ms 3s both; }
}

@keyframes ln-sobe { from { translate: 0 105%; } }
@keyframes chega { from { opacity: 0; translate: 0 8px; } }
@keyframes rv-rede { to { opacity: 1; translate: none; clip-path: none; } }

/* 5. The seal's ring turns as the seal crosses the screen: about a third of a turn from entering at
   the bottom to leaving at the top. site.js sets --selo-zero so a seal reads upright where it rests
   when the page opens. Scroll-driven, so it runs on the compositor and stops when the seal is off
   screen; where scroll timelines are missing (Firefox today) the ring stays still. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    html:not(.reduced) :is([data-selo-gira] .selo__anel, .selo__anel[data-selo-gira]) {
      animation: selo-gira linear both;
      animation-timeline: view();
      animation-range: cover;
    }
  }
}
@keyframes selo-gira {
  from { rotate: calc(var(--selo-zero, 0deg) - 60deg); }
  to { rotate: calc(var(--selo-zero, 0deg) + 60deg); }
}

/* 7. Press: the arrow moves the way the link goes, under the finger as under the mouse. */
@media (prefers-reduced-motion: no-preference) {
  .ligacao:active .ico { transform: translateX(3px); }
}

/* Reduced motion: page changes become a plain crossfade; nothing travels, nothing is hidden. */
@media (prefers-reduced-motion: reduce) {
  :root:active-view-transition-type(pagina)::view-transition-old(root) { animation: pag-esmaece-sai var(--d-press) ease both; }
  :root:active-view-transition-type(pagina)::view-transition-new(root) { animation: pag-esmaece-entra var(--d-fade) ease both; }
  ::view-transition-group(cabecalho), ::view-transition-group(selo) { animation: none; }
  ::view-transition-new(selo):only-child { animation: pag-esmaece-entra var(--d-fade) ease both; }
}

@media print {
  html.js :is([data-rv], [data-rv-kids] > *, [data-rv-kids] > :only-child > *, [data-circulo], .horario__dia, .avaliacao__nota, .faixa),
  html.js :is([data-rv], .titulo-cartaz) .ln > span {
    opacity: 1 !important; translate: none !important; clip-path: none !important; animation: none !important;
  }
}
