/* ============================================================================
   Motion — shared by the Lucky Cat landing and the Nock page
   ----------------------------------------------------------------------------
   Everything here is gated on `html.motion`, which motion.js only adds when
   JavaScript runs AND the system is not asking for reduced motion. Without that
   class the page is fully visible and static: no content is ever hidden behind
   an animation that might not fire.

   Only opacity and transform are animated. Easing is exponential ease-out —
   fast départ, long settle, no overshoot.
   ========================================================================= */

:root {
  --e-out:  cubic-bezier(.16, 1, .3, 1);    /* the long settle */
  --e-soft: cubic-bezier(.22, 1, .36, 1);   /* short UI moves */
  --d-rev:  .72s;
}

/* --- generic reveal -------------------------------------------------------- */
html.motion [data-reveal] { opacity: 0; transform: translateY(16px); }
html.motion [data-reveal].is-in {
  opacity: 1; transform: none;
  transition: opacity var(--d-rev) var(--e-out), transform var(--d-rev) var(--e-out);
}

/* --- staggered children ---------------------------------------------------- */
/* One entrance per item, 70ms apart, so a row reads left to right instead of
   arriving as a single block. */
html.motion [data-reveal="stagger"] { opacity: 1; transform: none; }
html.motion [data-reveal="stagger"] > * { opacity: 0; transform: translateY(14px); }
html.motion [data-reveal="stagger"].is-in > * {
  opacity: 1; transform: none;
  transition: opacity .62s var(--e-out), transform .62s var(--e-out);
}
html.motion [data-reveal="stagger"].is-in > :nth-child(1) { transition-delay: 0ms; }
html.motion [data-reveal="stagger"].is-in > :nth-child(2) { transition-delay: 70ms; }
html.motion [data-reveal="stagger"].is-in > :nth-child(3) { transition-delay: 140ms; }
html.motion [data-reveal="stagger"].is-in > :nth-child(4) { transition-delay: 210ms; }
html.motion [data-reveal="stagger"].is-in > :nth-child(5) { transition-delay: 280ms; }
html.motion [data-reveal="stagger"].is-in > :nth-child(6) { transition-delay: 350ms; }

/* --- sequencia alta demais para a tela ------------------------------------
   Num telefone a .pgrid vira uma coluna de ~1700px e a lista de degraus ~620px.
   O observer dispara com rootMargin -12% e threshold .12, ou seja quando pouco
   mais de 200px do topo do container apareceram -- e a cascata inteira roda ali,
   com os filhos 2..n animando centenas de pixels ABAIXO da dobra. A pessoa
   rola e encontra tudo ja revelado: paga-se o movimento e nao se ve nenhum.
   Quando o container e mais alto que a tela, o JS marca `data-seq="split"` e
   passa a observar cada filho; a cadencia sai, o gatilho entra por elemento. */
html.motion [data-reveal="stagger"][data-seq="split"] > .is-in,
html.motion [data-motion="steps"][data-seq="split"] li.is-in > * {
  opacity: 1; transform: none;
  transition: opacity var(--d-rev, .58s) var(--e-out), transform var(--d-rev, .58s) var(--e-out);
  transition-delay: 0ms;
}
html.motion [data-motion="steps"][data-seq="split"] li.is-in::before {
  transform: scaleX(1); transition: transform .66s var(--e-out); transition-delay: 0ms;
}

/* --- the handoff: a missed call becoming a job card ------------------------ */
/* The page's whole argument in one move. The dead card is already there, the
   arrow travels, and the job card lands after it — in that order, because that
   is the claim being made. */
html.motion [data-motion="handoff"] .dead-card { opacity: 0; transform: translateY(14px); }
html.motion [data-motion="handoff"] .tarrow    { opacity: 0; transform: translateX(-14px); }
html.motion [data-motion="handoff"] .job       { opacity: 0; transform: translateY(22px) scale(.985); }
html.motion [data-motion="handoff"].is-in .dead-card,
html.motion [data-motion="handoff"].is-in .tarrow,
html.motion [data-motion="handoff"].is-in .job {
  opacity: 1; transform: none;
  transition: opacity .7s var(--e-out), transform .7s var(--e-out);
}
html.motion [data-motion="handoff"].is-in .tarrow { transition-delay: .34s; }
html.motion [data-motion="handoff"].is-in .job    { transition-delay: .46s; }

/* --- the thread: messages arriving like messages --------------------------- */
/* Nock's replies come from its side, the customer's from theirs, at a cadence
   close to someone actually typing. */
html.motion [data-motion="thread"] .bub { opacity: 0; transform: translateY(10px); }
html.motion [data-motion="thread"] .bub-nock { transform: translate(-10px, 10px); }
html.motion [data-motion="thread"] .bub-cust { transform: translate(10px, 10px); }
html.motion [data-motion="thread"].is-in .bub {
  opacity: 1; transform: none;
  transition: opacity .5s var(--e-out), transform .5s var(--e-out);
}
html.motion [data-motion="thread"].is-in .bub:nth-child(1) { transition-delay: 0ms; }
html.motion [data-motion="thread"].is-in .bub:nth-child(2) { transition-delay: 260ms; }
html.motion [data-motion="thread"].is-in .bub:nth-child(3) { transition-delay: 620ms; }
html.motion [data-motion="thread"].is-in .bub:nth-child(4) { transition-delay: 900ms; }
html.motion [data-motion="thread"].is-in .bub:nth-child(5) { transition-delay: 1200ms; }

/* --- the fork: one first line, two different sets of questions ------------- */
/* The branches separate as they arrive, which is the point being made. */
html.motion [data-motion="fork"] > .branch { opacity: 0; }
html.motion [data-motion="fork"] > .branch:nth-child(1) { transform: translateX(-16px); }
html.motion [data-motion="fork"] > .branch:nth-child(2) { transform: translateX(16px); }
html.motion [data-motion="fork"].is-in > .branch {
  opacity: 1; transform: none;
  transition: opacity .68s var(--e-out), transform .68s var(--e-out);
}
html.motion [data-motion="fork"].is-in > .branch:nth-child(2) { transition-delay: 90ms; }

/* --- the lineup: four products, then the empty slot ------------------------ */
/* The open chip waits, so "and yours" lands as its own beat. */
html.motion [data-motion="lineup"] .chip { opacity: 0; transform: translateY(12px); }
html.motion [data-motion="lineup"].is-in .chip {
  opacity: 1; transform: none;
  transition: opacity .55s var(--e-out), transform .55s var(--e-out);
}
html.motion [data-motion="lineup"].is-in .chip:nth-child(1) { transition-delay: 0ms; }
html.motion [data-motion="lineup"].is-in .chip:nth-child(2) { transition-delay: 80ms; }
html.motion [data-motion="lineup"].is-in .chip:nth-child(3) { transition-delay: 160ms; }
html.motion [data-motion="lineup"].is-in .chip:nth-child(4) { transition-delay: 240ms; }
html.motion [data-motion="lineup"].is-in .chip-open         { transition-delay: 460ms; }

/* --- the steps: a rule drawn under each number ----------------------------- */
/* The rule grows left to right in sequence, which is the same information the
   numbers carry. The border is handed to a pseudo-element so it can scale. */
html.motion [data-motion="steps"] li { border-top-color: transparent; position: relative; }
html.motion [data-motion="steps"] li::before {
  content: ""; position: absolute; top: -2px; left: 0; width: 100%; height: 2px;
  background: var(--border); transform: scaleX(0); transform-origin: left;
}
html.motion [data-motion="steps"] li:first-child::before { background: var(--gold); }
html.motion [data-motion="steps"] li > * { opacity: 0; transform: translateY(12px); }
html.motion [data-motion="steps"].is-in li::before {
  transform: scaleX(1); transition: transform .66s var(--e-out);
}
html.motion [data-motion="steps"].is-in li > * {
  opacity: 1; transform: none;
  transition: opacity .58s var(--e-out), transform .58s var(--e-out);
}
html.motion [data-motion="steps"].is-in li:nth-child(1)::before,
html.motion [data-motion="steps"].is-in li:nth-child(1) > * { transition-delay: 0ms; }
html.motion [data-motion="steps"].is-in li:nth-child(2)::before,
html.motion [data-motion="steps"].is-in li:nth-child(2) > * { transition-delay: 110ms; }
html.motion [data-motion="steps"].is-in li:nth-child(3)::before,
html.motion [data-motion="steps"].is-in li:nth-child(3) > * { transition-delay: 220ms; }
html.motion [data-motion="steps"].is-in li:nth-child(4)::before,
html.motion [data-motion="steps"].is-in li:nth-child(4) > * { transition-delay: 330ms; }

/* --- hero stage drift ------------------------------------------------------ */
/* The devices sit at slightly different depths, so they part company a little
   as the page scrolls. Driven by a custom property motion.js writes, and only
   where there is room for it to read as depth rather than wobble. */
/* The phones carry their tilt on the separate `rotate` property, so transform
   is free for the drift and the angles stay exactly as designed. */
/* A deriva estava presa em min-width:900px, e era o efeito mais visivel da
   pagina. Consequencia no telefone: os aparelhos ficavam parados, o hover nao
   existe no toque, e depois do .rise inicial NADA mais se movia -- a pagina
   inteira virava estatica no aparelho por onde a maioria vai entrar (o QR do
   cartao de visita cai aqui). As amplitudes agora sao variaveis: no retrato os
   aparelhos se sobrepoem, e o deslocamento do desktop leria como tremor. */
html.motion .stage-tablet        { transform: translateY(calc(var(--drift, 0) * var(--dr-tab, -8px))); }
html.motion .stage-phone.is-left { transform: translateY(calc(var(--drift, 0) * var(--dr-l, 15px))); }
html.motion .stage-phone.is-right{ transform: translateY(calc(var(--drift, 0) * var(--dr-r, 20px))); }

@media (min-width: 900px) {
  html.motion .stage { --dr-tab: -14px; --dr-l: 26px; --dr-r: 34px; }
}

/* A unica coisa da pagina que se move sozinha. O .stage-glow ja carrega
   filter: blur(30px), ou seja ja e camada composta: animar opacity e scale
   custa um tique do compositor e nada mais -- sem reflow, sem repaint, sem
   disputar os 16ms com os reveals. 9s e lento o bastante para ser sentido em
   vez de assistido. Cuidado de cascata: lc.css posiciona o elemento com a
   propriedade `translate` separada, entao o keyframe so pode tocar em scale e
   opacity, senao o centramento se perde. */
html.motion .stage-glow { animation: glow-breathe 9s ease-in-out infinite; }
@keyframes glow-breathe {
  0%, 100% { opacity: .82; scale: 1; }
  50%      { opacity: 1;   scale: 1.06; }
}

/* --- chip hover ------------------------------------------------------------ */
/* Pointing at one product dims the others: the lineup responds as a set. */
html.motion .chip { transition: transform .2s var(--e-soft), opacity .2s var(--e-soft), box-shadow .2s; }
/* :hover so existe onde ha ponteiro. Num telefone estas duas regras nunca
   disparam, e o conjunto fica inerte -- por isso o realce por ponteiro fica
   atras de (hover: hover) e o toque ganha o seu proprio, no :active. */
@media (hover: hover) {
  html.motion .lineup:hover .chip:not(:hover) { opacity: .62; }
  html.motion .chip:hover { transform: translateY(-2px); }
}
@media (hover: none) {
  html.motion .chip:active { transform: scale(.97); }
}

/* --- v3: paper, the strip, the plates, the rail --------------------------- */
/* Every block below carries BOTH `data-reveal` and `data-motion="…"`. Two
   reasons, and both matter: `data-reveal` is the hook the observer has always
   watched, so the trigger cannot depend on a new name being recognised; and the
   print and reduced-motion nets at the end of this file reset
   `[data-motion] *`, which is the only selector that reaches a grandchild.
   Anything that starts at opacity 0 here is therefore guaranteed a way back
   to visible even if the JavaScript never runs. */

/* Paper settles the way a pile does: the sheets arrive as a stack and spread.
   Small amplitudes — this is a pile of dockets, not a card trick. */
html.motion [data-motion="paper"][data-reveal] .sheet { opacity: 0; translate: 6% 4%; }
html.motion [data-motion="paper"][data-reveal].is-in .sheet {
  opacity: 1; translate: 0 0;
  transition: opacity .6s var(--e-out), translate .75s var(--e-out);
}
html.motion [data-motion="paper"][data-reveal].is-in .sheet:nth-child(2) { transition-delay: .09s; }
html.motion [data-motion="paper"][data-reveal].is-in .sheet:nth-child(3) { transition-delay: .18s; }

/* The morning fills up by hand, block after block, and only then does the
   automated one land. The order is the whole point, so the delays are long
   enough to be read as sequence rather than as a single fade. */
html.motion [data-motion="strip"][data-reveal] .dchip { opacity: 0; transform: translateY(8px); }
html.motion [data-motion="strip"][data-reveal].is-in .dchip {
  opacity: 1; transform: none;
  transition: opacity .42s var(--e-out), transform .42s var(--e-out);
}
html.motion [data-motion="strip"][data-reveal].is-in .drow:first-child .dchip:nth-child(1) { transition-delay: .05s; }
html.motion [data-motion="strip"][data-reveal].is-in .drow:first-child .dchip:nth-child(2) { transition-delay: .16s; }
html.motion [data-motion="strip"][data-reveal].is-in .drow:first-child .dchip:nth-child(3) { transition-delay: .27s; }
html.motion [data-motion="strip"][data-reveal].is-in .drow:first-child .dchip:nth-child(4) { transition-delay: .38s; }
html.motion [data-motion="strip"][data-reveal].is-in .drow:first-child .dchip:nth-child(5) { transition-delay: .49s; }
html.motion [data-motion="strip"][data-reveal].is-in .drow + .drow .dchip--auto { transition-delay: .72s; }
html.motion [data-motion="strip"][data-reveal].is-in .drow + .drow .dchip--free { transition-delay: .88s; }

/* A plate: the sentence first, the artefact a beat later, coming from its own
   side of the page so the alternation is felt as well as seen. */
html.motion [data-motion="plate"][data-reveal] .plate-copy { opacity: 0; transform: translateY(14px); }
html.motion [data-motion="plate"][data-reveal] .plate-art  { opacity: 0; transform: translateY(20px) scale(.99); }
html.motion [data-motion="plate"][data-reveal].is-in .plate-copy,
html.motion [data-motion="plate"][data-reveal].is-in .plate-art {
  opacity: 1; transform: none;
  transition: opacity .7s var(--e-out), transform .7s var(--e-out);
}
html.motion [data-motion="plate"][data-reveal].is-in .plate-art { transition-delay: .2s; }

/* The thread types itself out: question, then the answer. Each bubble comes
   from the side it sits on. */
html.motion [data-motion="talk"][data-reveal] .bub { opacity: 0; }
html.motion [data-motion="talk"][data-reveal] .bub-cust { transform: translate(-10px, 8px); }
html.motion [data-motion="talk"][data-reveal] .bub-nock { transform: translate(10px, 8px); }
html.motion [data-motion="talk"][data-reveal].is-in .bub {
  opacity: 1; transform: none;
  transition: opacity .5s var(--e-out), transform .5s var(--e-out);
}
html.motion [data-motion="talk"][data-reveal].is-in .bub:nth-child(2) { transition-delay: .34s; }
html.motion [data-motion="talk"][data-reveal].is-in .bub:nth-child(3) { transition-delay: .62s; }

/* The rail. Same technique as the numbered steps — the rule is handed to a
   pseudo-element so it can scale from the left — because this is the same idea
   one section further on, and using a second technique for it would show. */
html.motion [data-motion="flow"][data-reveal] .flow-mark { border-top-color: transparent; position: relative; }
html.motion [data-motion="flow"][data-reveal] .flow-mark::before {
  content: ""; position: absolute; top: -2px; left: 0; width: 100%; height: 2px;
  background: var(--border); transform: scaleX(0); transform-origin: left;
}
html.motion [data-motion="flow"][data-reveal] .flow-stop:first-child .flow-mark::before { background: var(--gold); }
html.motion [data-motion="flow"][data-reveal] .flow-art,
html.motion [data-motion="flow"][data-reveal] .flow-mark > *,
html.motion [data-motion="flow"][data-reveal] .flow-stop > h3,
html.motion [data-motion="flow"][data-reveal] .flow-stop > p { opacity: 0; transform: translateY(12px); }
html.motion [data-motion="flow"][data-reveal].is-in .flow-mark::before {
  transform: scaleX(1); transition: transform .66s var(--e-out);
}
html.motion [data-motion="flow"][data-reveal].is-in .flow-art,
html.motion [data-motion="flow"][data-reveal].is-in .flow-mark > *,
html.motion [data-motion="flow"][data-reveal].is-in .flow-stop > h3,
html.motion [data-motion="flow"][data-reveal].is-in .flow-stop > p {
  opacity: 1; transform: none;
  transition: opacity .58s var(--e-out), transform .58s var(--e-out);
}
html.motion [data-motion="flow"][data-reveal].is-in .flow-stop:nth-child(1) * { transition-delay: 0ms; }
html.motion [data-motion="flow"][data-reveal].is-in .flow-stop:nth-child(2) * { transition-delay: 130ms; }
html.motion [data-motion="flow"][data-reveal].is-in .flow-stop:nth-child(3) * { transition-delay: 260ms; }
html.motion [data-motion="flow"][data-reveal].is-in .flow-stop:nth-child(4) * { transition-delay: 390ms; }

/* Laptop and phone are one object in two parts, so the phone arrives last and
   from underneath — the way it would be set down beside the laptop. */
html.motion .device-stack[data-reveal] .device--phone { opacity: 0; transform: translateY(26px); }
html.motion .device-stack[data-reveal].is-in .device--phone {
  opacity: 1; transform: none;
  transition: opacity .7s var(--e-out) .22s, transform .8s var(--e-out) .22s;
}

/* --- print ----------------------------------------------------------------- */
/* Printing never scrolls, so the observer never fires for anything below the
   first screen. Without this, half the page prints blank. */
@media print {
  html.motion [data-reveal],
  html.motion [data-reveal] > *,
  html.motion [data-motion] *,
  html.motion [data-motion] > * {
    /* `translate` is reset alongside `transform` because the v3 paper stack
       animates the standalone property, which `transform: none` does not touch. */
    opacity: 1 !important; transform: none !important; translate: none !important;
    transition: none !important;
  }
  html.motion [data-motion="steps"] li { border-top-color: var(--border); }
  html.motion [data-motion="steps"] li:first-child { border-top-color: var(--gold); }
  html.motion [data-motion="steps"] li::before { display: none; }
  /* Same for the v3 rail: give the stop its drawn border back and drop the
     pseudo-element that was standing in for it. */
  html.motion [data-motion="flow"] .flow-mark { border-top-color: var(--border); }
  html.motion [data-motion="flow"] .flow-stop:first-child .flow-mark { border-top-color: var(--gold); }
  html.motion [data-motion="flow"] .flow-mark::before { display: none; }
}

/* --- last resort ----------------------------------------------------------- */
/* Belt and braces: if the class is somehow present while the OS asks for
   reduced motion, everything collapses to its resting state. */
@media (prefers-reduced-motion: reduce) {
  html.motion [data-reveal],
  html.motion [data-reveal] > *,
  html.motion [data-motion] *,
  html.motion [data-motion] > * {
    /* `translate` is reset alongside `transform` because the v3 paper stack
       animates the standalone property, which `transform: none` does not touch. */
    opacity: 1 !important; transform: none !important; translate: none !important;
    transition: none !important;
  }
  html.motion [data-motion="steps"] li { border-top-color: var(--border); }
  html.motion [data-motion="steps"] li:first-child { border-top-color: var(--gold); }
  html.motion [data-motion="steps"] li::before { display: none; }
  /* Same for the v3 rail: give the stop its drawn border back and drop the
     pseudo-element that was standing in for it. */
  html.motion [data-motion="flow"] .flow-mark { border-top-color: var(--border); }
  html.motion [data-motion="flow"] .flow-stop:first-child .flow-mark { border-top-color: var(--gold); }
  html.motion [data-motion="flow"] .flow-mark::before { display: none; }
  html.motion .stage-tablet, html.motion .stage-phone { transform: none; }
}
