/* Product stories (2026-10-14). Each product fragment plays its point once,
   like a short demo, the first time it is half on screen, then stays still.
   Scouted with find-animation-opportunities, built to emil-design-eng values.

   Gating: the hidden "before" states only apply under html.motion, which the
   inline head script sets when JavaScript runs and the visitor has not asked
   for reduced motion. Without it every fragment is simply shown, finished.
   home.js adds .play to a [data-play] element when it enters view. Easing is
   the site's --out curve; only transform, opacity and clip-path move. */

/* ---------- 1. Same sale: the sum, then the order card ---------- */

/* The sum states its terms one after another, then the total is struck. */
.motion .h-sum[data-play] > p { transition: opacity 350ms var(--out), transform 350ms var(--out); }
.motion .h-sum[data-play]:not(.play) > p { opacity: 0; transform: translateY(8px); }
.motion .h-sum[data-play] > p:nth-child(2) { transition-delay: 120ms; }
.motion .h-sum[data-play] > p:nth-child(3) { transition-delay: 240ms; }
.motion .h-sum[data-play] > p:nth-child(4) { transition-delay: 360ms; }
.motion .h-sum[data-play] > p:nth-child(5) { transition-delay: 480ms; }
.motion .h-sum[data-play] > .h-sum-truth { transition-delay: 1400ms; }

/* The strike is a drawn bar rather than text-decoration, so it can be drawn. */
.h-sum-wrong b { position: relative; text-decoration: none; }
.h-sum-wrong b::after {
  content: ""; position: absolute; left: -3px; right: -3px; top: 54%; height: 3px;
  background: var(--acc); border-radius: 2px; transform-origin: left center;
}
.motion .h-sum[data-play] .h-sum-wrong b::after { transition: transform 450ms var(--out) 900ms; }
.motion .h-sum[data-play]:not(.play) .h-sum-wrong b::after { transform: scaleX(0); }

/* The order card: Meta claims it, Google claims it, your revenue counts it once. */
.motion .order[data-play] .order-rows li { transition: opacity 350ms var(--out), transform 350ms var(--out); }
.motion .order[data-play]:not(.play) .order-rows li { opacity: 0; transform: translateY(8px); }
.motion .order[data-play] .order-rows li:nth-child(1) { transition-delay: 250ms; }
.motion .order[data-play] .order-rows li:nth-child(2) { transition-delay: 530ms; }
.motion .order[data-play] .order-rows li:nth-child(3) { transition-delay: 850ms; }

/* "Your revenue": its tint wipes in from the left, then the verdict lands. */
.order-you { position: relative; isolation: isolate; background: transparent; }
.order-you::before { content: ""; position: absolute; inset: 0; z-index: -1; background: #232327; border-radius: 6px; }
.motion .order[data-play] .order-you::before { transition: clip-path 500ms var(--out) 950ms; }
.motion .order[data-play]:not(.play) .order-you::before { clip-path: inset(0 100% 0 0); }
.motion .order[data-play] .order-you b { display: inline-block; transform-origin: right center; transition: color 250ms ease 1350ms, transform 250ms var(--out) 1350ms; }
.motion .order[data-play]:not(.play) .order-you b { color: #a1a1aa; transform: scale(0.96); }

/* ---------- 2. Chat: the question, a beat of typing, the answer ---------- */
.chat-a { position: relative; }
.chat-typing { display: none; }
.motion .chat[data-play] .chat-q { transition: opacity 300ms var(--out), transform 300ms var(--out); }
.motion .chat[data-play]:not(.play) .chat-q { opacity: 0; transform: translateY(8px); }
.motion .chat[data-play] .chat-a p { transition: opacity 300ms var(--out), transform 300ms var(--out); }
.motion .chat[data-play] .chat-a p:nth-of-type(2) { transition-delay: 120ms; }
.motion .chat[data-play] .chat-a p:nth-of-type(3) { transition-delay: 240ms; }
.motion .chat[data-play]:not(.answered) .chat-a p { opacity: 0; transform: translateY(8px); }

/* Typing sits over the first answer line, so nothing shifts when it leaves. */
.motion .chat-typing {
  display: flex; gap: 4px; position: absolute; left: 0; top: 4px;
  padding: 10px 12px; background: #1c1c20; border-radius: 12px 12px 12px 4px;
  opacity: 0; transform: translateY(6px); pointer-events: none;
  transition: opacity 150ms var(--out), transform 150ms var(--out);
}
.motion .chat.typing .chat-typing { opacity: 1; transform: none; transition-duration: 250ms; }
.chat-typing i { width: 6px; height: 6px; border-radius: 50%; background: #a1a1aa; animation: chat-dot 900ms ease-in-out infinite; }
.chat-typing i:nth-child(2) { animation-delay: 150ms; }
.chat-typing i:nth-child(3) { animation-delay: 300ms; }
.chat:not(.typing) .chat-typing i { animation-play-state: paused; }
@keyframes chat-dot { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }

/* ---------- 3. How it works: each step's card checks itself off ---------- */
/* Desktop only, where one step shows at a time; on a phone every step is
   listed, so nothing waits on a step becoming current. */
@media (min-width: 901px) {
  .motion .h-how[data-play] .h-stage-item .frag-row,
  .motion .h-how[data-play] .h-stage-item .frag-conn { transition: opacity 300ms var(--out), transform 300ms var(--out); }
  .motion .h-how[data-play] .h-stage-item:not(.is-on) :is(.frag-row, .frag-conn),
  .motion .h-how[data-play]:not(.play) :is(.frag-row, .frag-conn) { opacity: 0; transform: translateY(6px); }
  .motion .h-how[data-play] .h-stage-item.is-on :is(.frag-row, .frag-conn):nth-of-type(1) { transition-delay: 200ms; }
  .motion .h-how[data-play] .h-stage-item.is-on .frag-row + .frag-row,
  .motion .h-how[data-play] .h-stage-item.is-on .frag-conn + .frag-conn { transition-delay: 550ms; }
  .motion .h-how[data-play] .frag-ok::before { transition: transform 250ms var(--out); }
  .motion .h-how[data-play] .h-stage-item.is-on .frag-row:nth-of-type(1) .frag-ok::before { transition-delay: 300ms; }
  .motion .h-how[data-play] .h-stage-item.is-on .frag-row + .frag-row .frag-ok::before { transition-delay: 650ms; }
  .motion .h-how[data-play] .h-stage-item:not(.is-on) .frag-ok::before { transform: scale(0.6); }
}

/* ---------- 5. Hero: the source rows settle after the panel ---------- */
@keyframes story-row { from { opacity: 0; transform: translateY(6px); } }
/* backwards, not both: once played, the row's own :active press must win. */
.motion .h-hero .claims-row { animation: story-row 300ms var(--out) backwards; animation-delay: calc(500ms + var(--r, 0) * 40ms); }
.claims-row:nth-child(2) { --r: 1; }
.claims-row:nth-child(3) { --r: 2; }
.claims-row:nth-child(4) { --r: 3; }
.claims-row:nth-child(5) { --r: 4; }
.claims-row:nth-child(6) { --r: 5; }
.claims-row:nth-child(7) { --r: 6; }

/* ---------- Hero motion graphic (flow.js) ---------- */
.home .h-stage.h-flow { position: relative; height: 460px; padding: 0; border-radius: 18px; overflow: hidden; }
.flow-svg { position: absolute; inset: 0; display: block; font-family: "Geist", system-ui, sans-serif; font-variant-numeric: tabular-nums; }
/* Without script: the sources as a plain list on the same panel. */
.flow-fallback { list-style: none; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding: 32px; }
.flow-fallback li { background: #1c1c20; border-radius: 8px; padding: 9px 14px; font-size: 14px; }
.is-drawn .flow-fallback { display: none; }
@media (max-width: 900px) { .home .h-stage.h-flow { height: 440px; border-radius: 14px; } }
