/* The screenshot sequence — shared by every page on the site. ONE door: change it here.

   SHOWN SMALLER THAN NATIVE, on purpose. Every frame is 1254x533 real pixels and the frame is
   capped at 760, so the browser downsamples. Screenshots of text look sharp when they are
   downscaled and soft when they are stretched, which is why the frame is capped in CSS rather
   than the images being resized on disk. */
.seq{margin:2rem auto 0;max-width:1040px}
/* 1040, not 760. The captures are 2508px wide; a 760px frame showed the app at 53% of its
   natural size, which is why the text in them read as blurry — it was small, not soft. The
   .wrap is 1120 with 2rem padding, so 1040 is the widest that still aligns with the prose
   column above it, and it spends pixels the frame was previously discarding. */

/* THE STAGE HOLDS ITS OWN HEIGHT. Every frame is absolutely positioned, and the stage reserves
   the space from the frame ratio instead of from whichever image happens to be showing.

   It used to give the active image `position:relative` and everything else `position:absolute`,
   which meant that on every change two images swapped positioning scheme in the same frame. The
   stage lost its content for an instant, collapsed, and the whole block below it jumped. That is
   what made the transition look cheap — not the fade, the reflow under it. */
.seq-stage{position:relative;aspect-ratio:1254/533;overflow:hidden}

/* NO CROSS-DISSOLVE THROUGH THE BACKGROUND. Two images at 50% opacity show whatever is behind
   them, so a plain crossfade dips to a pale flash in the middle. Instead the outgoing frame is
   held fully opaque underneath while the incoming one fades in on top of it; when the fade
   finishes the one underneath is dropped, and nothing visible changes at that moment. */
.seq-stage img{
  position:absolute; inset:0; display:block; width:100%; height:100%;
  object-fit:cover; object-position:top center;
  opacity:0; z-index:0;
  transition:opacity .85s cubic-bezier(.4,0,.2,1);
  will-change:opacity;
}
.seq-stage img.is-on{opacity:1;z-index:2}
.seq-stage img.was-on{opacity:1;z-index:1;transition:none}

/* Reduced motion: cut instead of fade. It still advances — see seq.js. */
.seq.seq-cut .seq-stage img{transition:none}
@media (prefers-reduced-motion: reduce){
  .seq-stage img{transition:none}
}

.seq-foot{display:flex;align-items:center;gap:.9rem;margin-top:.6rem;flex-wrap:nowrap}
/* ONE LINE, always. A caption that wraps changes the block's height as it advances. It fades
   with the picture rather than switching under it, on the same curve. */
.seq-cap{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:opacity .28s ease}
.seq-cap.is-swapping{opacity:0}
.seq.seq-cut .seq-cap{transition:none}
@media (prefers-reduced-motion: reduce){ .seq-cap{transition:none} }

.seq-dots{display:flex;gap:.4rem;flex:0 0 auto;margin-inline-start:auto}
.seq-dot{width:1.5rem;height:.25rem;border:0;padding:0;border-radius:2px;cursor:pointer;
  background:currentColor;opacity:.2;transition:opacity .4s cubic-bezier(.4,0,.2,1)}
.seq-dot.is-on{opacity:.85}
.seq-dot:focus-visible{outline:2px solid currentColor;outline-offset:3px}
