/* The opening exchange (intro.js): one post tags @GroktoBot, Grokto thinks, the receipt flips in, then the receipt lands in the hero's composer.
   The cards are §3's thread (.sc-thread .x-post, story.css) so they look like the thread further down; only the stage and the motion live here.
   The hand-off is a same-document view transition: while the layer is up only the receipt is named "composer", so the browser morphs it into the real one. */
.intro { --h: clamp(660px, 100svh, 1040px); --apex: calc(var(--h) * .22); position: fixed; inset: 0; z-index: 70; display: grid; place-items: center; padding: 16px 16px 20svh; overflow: hidden; /* the thread floats above the horizon; under the grain (80), over the toast (60) */
  background: radial-gradient(70% 48% at 50% 36%, rgba(153 69 255 / .14), transparent 70%), radial-gradient(44% 38% at 66% 66%, rgba(20 241 149 / .09), transparent 70%), var(--bg); }
@media (min-width: 981px) { .intro { --h: clamp(900px, 100svh, 1040px); } } /* --h and --apex are the hero's (grokto.css .hero): the planet edge is already where the hero's will be, so the cut never moves it */
.intro::before { content: ""; position: absolute; inset: 0 0 auto; height: var(--h); /* the hero's edge, verbatim */
  background: radial-gradient(160% 64% at 50% calc(100% + 64% - var(--apex) * 1.02), #000 calc(100% - 2px), #e8fff4 100%, rgba(var(--accent-rgb) / .55) calc(100% + 6px), rgba(var(--accent-rgb) / .14) calc(100% + 60px), transparent calc(100% + 240px)); }
.intro::after { content: ""; position: absolute; left: -60%; right: -60%; top: calc(var(--h) - var(--apex)); height: 120%; transform-origin: 50% 0; transform: perspective(600px) rotateX(70deg); /* the story's floor grid, running to that horizon */
  background: linear-gradient(rgba(20 241 149 / .2) 1px, transparent 1px) 0 0 / 80px 80px, linear-gradient(90deg, rgba(20 241 149 / .2) 1px, transparent 1px) 0 0 / 80px 80px;
  -webkit-mask-image: linear-gradient(transparent, #000 22%, #000 55%, transparent 88%), linear-gradient(90deg, transparent 30%, #000 50%, transparent 70%); -webkit-mask-composite: source-in;
  mask-image: linear-gradient(transparent, #000 22%, #000 55%, transparent 88%), linear-gradient(90deg, transparent 30%, #000 50%, transparent 70%); mask-composite: intersect; }
.intro.play::after { animation: in-floor 2.4s linear infinite; }
.intro.out { opacity: 0; transition: opacity .4s; } /* browsers without view transitions: a plain fade */

.intro .sc-thread { width: min(100%, 460px); animation: none; } /* story.css ties .sc-thread to the trade's scroll timeline; not here */
@media (min-width: 981px) { .intro .sc-thread { zoom: 1.3; } } /* on a desktop stage the exchange is the whole picture; at 1x it sat small in the dark */
.intro:not(.play) .x-post { opacity: 0; } /* nothing shows until the fonts are in and the tab is visible */
.in-reply { display: grid; perspective: 1200px; }
.in-reply > * { grid-area: 1 / 1; } /* the typing row and the receipt share one cell: the receipt lands over the dots */
.in-dots { display: flex; gap: 5px; padding: 9px 0 3px; }
.in-dots i { width: 7px; height: 7px; border-radius: 50%; background: var(--dim); }
.in-bot { transform-origin: 0 50%; view-transition-name: composer; }
.in-bot .sample { position: absolute; top: 13px; right: 14px; }

.intro.play .in-you { animation: in-pop .5s cubic-bezier(.22, 1, .36, 1) .15s both; }
.intro.play .in-typing { animation: in-wait .95s linear .62s both; }
.intro.play .in-dots i { animation: in-bob .9s ease-in-out infinite; }
.intro.play .in-dots i:nth-child(2) { animation-delay: .15s; } .intro.play .in-dots i:nth-child(3) { animation-delay: .3s; }
.intro.play .in-bot { animation: in-flip .55s cubic-bezier(.2, .8, .2, 1) 1.55s both; }
.intro.play .in-bot::after { animation: in-shine .8s linear 2.05s both; } /* the light that runs across a receipt as it lands (the pseudo-element is §3's) */
@keyframes in-pop { from { opacity: 0; transform: translateY(24px) scale(.92); filter: blur(8px); } }
@keyframes in-wait { 0% { opacity: 0; translate: 0 8px; } 20%, 80% { opacity: 1; translate: 0 0; } 100% { opacity: 0; } }
@keyframes in-bob { 50% { translate: 0 -4px; background: var(--text); } }
@keyframes in-flip { from { opacity: 0; transform: rotateY(-90deg) translateZ(50px); } 55% { opacity: 1; } }
@keyframes in-shine { from { translate: -110% 0; } to { translate: 110% 0; } }
@keyframes in-floor { to { background-position: 0 80px, 0 0; } }

/* the hand-off: the receipt morphs into the composer while the hero rises in under it and the header follows */
html.intro-on :is(.top, .composer) { view-transition-name: none; }
html:active-view-transition-type(intro)::view-transition-group(composer) { animation-duration: .7s; animation-timing-function: cubic-bezier(.3, .8, .2, 1); }
html:is(:active-view-transition-type(intro), :active-view-transition-type(intro-skip))::view-transition-old(composer),
html:is(:active-view-transition-type(intro), :active-view-transition-type(intro-skip))::view-transition-new(composer) { block-size: 100%; object-fit: contain; } /* both keep their shape while the box flattens: the receipt compresses into the pill, not a blown-up ghost */
html:active-view-transition-type(intro)::view-transition-old(composer) { animation: in-fade-out .3s ease-in both; }
html:active-view-transition-type(intro)::view-transition-new(composer) { animation: in-fade-in .4s ease-out .25s both; }
html:active-view-transition-type(intro)::view-transition-old(root) { animation-duration: .45s; }
html:active-view-transition-type(intro)::view-transition-new(root) { animation: in-rise .7s cubic-bezier(.2, .8, .2, 1) both; }
html:active-view-transition-type(intro)::view-transition-new(top) { animation: in-fade-in .5s ease-out .2s both; }
@keyframes in-fade-in { from { opacity: 0; } }
@keyframes in-fade-out { to { opacity: 0; } }
@keyframes in-rise { from { opacity: 0; transform: translateY(22px); } }

@media (prefers-reduced-motion: reduce) { .intro { display: none; } } /* intro.js never mounts it; this holds if the preference flips mid-way */
