/* T23: the welcome, the refracting transition, and the letter that follows it.
   Score and source provenance: work/t23/shockwave.spec.md.

   One stage, pinned for two screens of scroll. Everything on it is a function of scroll
   position (why.js writes six numbers onto the stage; the rest is arithmetic here), so it
   plays backwards on the way up and holds wherever the page stops.

   --pop    0..1   how far the crowd of competitor icons has arrived
   --ring   px     radius of the ripple's front (far negative: no ripple yet)
   --white  px     radius of the white that follows the ripple
   --q      0..1   the question, as it leaves
   --o      0..1   the orb under the answer
   --lx --ly px    the pointer, a beat behind; --lit 0|1 whether a mouse is over the stage */
/* 100svh stage + 196svh pin. The 200svh score ends at .98 as the orb settles. */
.why{position:relative;height:524svh;background:#000;color:#fff}
.why__stage{position:sticky;top:0;height:100svh;height:100lvh;   /* lvh: fills the screen even when a phone's toolbar slides away (owner, 15 Oct) */
 display:grid;place-items:center;overflow:clip;isolation:isolate;background:#000;
 --pop:0;--ring:-400;--white:-600;--q:1;--o:0;--lx:-999px;--ly:-999px}
.why__light,.why__wall,.why__halo,.why__white,.why__ripple{position:absolute;inset:0;pointer-events:none}

/* Pointer light belongs to the icon glass only. The stage layer is deliberately
   inert: a full-stage radial pool lifts the black canvas between the marks. */
.why__light{display:none}
/* T25 (owner, 15 Oct): the dark halo behind the question is back, as agreed in T22: black that fades out past the
   clear margin, so the crowd presses in without touching the words. why.js sizes it (--hw, --hh) and fades it with the question. */
.why__halo{background:radial-gradient(ellipse var(--hw,520px) var(--hh,200px) at 50% 50%,rgba(0,0,0,.97) 0,rgba(0,0,0,.95) 58%,rgba(0,0,0,.72) 80%,rgba(0,0,0,0) 100%);opacity:var(--halo,1)}

/* The crowd. Each icon is one cell of logos.webp (Sarthak's glass, drawn ahead of time), placed
   by why.js for this window. --b is when it is born, --d how far it sits from the centre. It
   arrives with a small swell, and when the leading ring reaches it, it lifts and is gone. */
.why__wall i{position:absolute;
 /* Two layers of the glass (owner, 15 Oct): between T22's one, which read too faint, and the three Sarthak had. */
 background-image:url('logos.webp'),url('logos.webp');
 background-position:var(--bp),var(--bp);background-size:var(--bs),var(--bs);background-repeat:no-repeat;
 contain:paint;}
/* The same light, caught by each icon: one spotlight centred on the pointer, shown only through
   the icon's own glass (its image is the mask, so the rims take most of it). An icon is lit on
   the side that faces the pointer and fades with distance; no two are lit alike. */
.why__wall i::after{content:'';position:absolute;inset:0;opacity:0;transition:opacity .45s ease;
 -webkit-mask:url('logos.webp') var(--bp)/var(--bs) no-repeat;
 mask:url('logos.webp') var(--bp)/var(--bs) no-repeat;
 background:radial-gradient(400px circle at var(--icon-lx,-999px) var(--icon-ly,-999px),#fff,rgba(255,255,255,.7) 20%,rgba(255,255,255,.32) 46%,rgba(255,255,255,.09) 74%,transparent 100%);
}
/* Only nearby visible marks receive local pointer coordinates. One atlas-masked
   light replaces stacked filter surfaces; black gaps remain completely untouched. */
.why__wall i.is-lit::after{opacity:var(--crowd,1)}
/* In Safari, invisible atlas masks can still become expensive surfaces beneath
   WebGL. Suspend only that hover layer during the scroll-owned glass ripple. */
.why__wall[data-refracting] i::after{display:none}
/* One bounded foreground surface replaces per-icon mask compositing. The
   original CSS treatment remains available if foreground WebGL cannot initialize. */
.why__wall[data-hover-canvas] i::after{display:none}
.why__hover-canvas{position:absolute;left:0;top:0;pointer-events:none}
.why__wall[data-refracting] .why__hover-canvas{display:none!important}

@media(prefers-reduced-motion:reduce){.why__light,.why__wall i::after{transition:none}}

/* The ripple is Sarthak's glass lens from T21 (story/vendor/shockwave.js, same options): clear
   rings drawn only by the light they catch. why.js scrubs it with scroll. White follows it out. */
/* The shader already renders monochrome; avoid a second full-stage filter pass. */
.why__ripple{filter:none;z-index:0}
.why__white{background:radial-gradient(circle at 50% 50%,#fff calc(var(--white)*1px - 64px),rgba(255,255,255,0) calc(var(--white)*1px))} /* a narrow edge: letters are unreadable only where it is mid-grey */

/* The words, set exactly as the hero title is (size, leading, tracking): the question in white
   on the black, the answer in black on the white. The answer only starts once the white holds it. */
.why__copy{position:relative;z-index:1;display:grid;place-items:center;text-align:center;padding:0 6vw;color:#fff}
.why__line{margin:0;font-family:var(--serif);font-weight:400;font-size:var(--t-display);line-height:.95;letter-spacing:-.045em;text-wrap:balance}
.why__q,.why__serious,.why__pair{grid-area:1/1}
/* T25: the line after the question stands on the white, in the answer's ink, and gives way to the answer. */
.why__serious{opacity:var(--serious,0)}
.why__pair>.why__serious{grid-area:1/1}
/* The answer and, once it is written, the orb beneath it: the hero's orb at the hero's size and
   the hero's gap. The pair is one centred block; until the orb arrives (--o) it sits lower by
   half the orb and its gap, so the line alone is centred, and it eases up as the orb fades in. */
.why__pair{--orb:clamp(160px,15vw,220px);--gap:clamp(28px,5vh,56px);display:grid;justify-items:center;gap:var(--gap);color:#000;
 translate:0 calc((1 - var(--o))*(var(--orb) + var(--gap))/2)}
.why__orb{--source-orb-size:var(--orb);opacity:var(--o);scale:calc(.9 + .1*var(--o))}
@media(max-width:600px){.why__pair{--orb:150px}}
/* Both lines write themselves in letter by letter (why.js sets each letter); the question leaves whole. */
.why__q{opacity:var(--q);translate:0 calc((1 - var(--q))*-14px)}
.why .w{display:inline-block}
.why .w,.why .w--letters>span{transition:opacity .18s linear}   /* eased like candor.inc's word reveal (owner, 15 Oct) */
/* Easter eggs (owner, 15 Oct). The caret: a thin bar after the newest letter, blinking once the line is typed.
   Shared with the story's "type into it." */
.egg-caret{position:relative}
.egg-caret::after{content:'';position:absolute;left:calc(100% + .04em);top:.12em;bottom:.04em;width:max(1.5px,.05em);background:currentColor;border-radius:1px}
.egg-caret.is-idle::after{animation:egg-caret 1.06s steps(1) infinite}
@keyframes egg-caret{50%{opacity:0}}
/* The full stop after "there": a generous invisible target, and one ring of water when the pointer reaches it. */
.why__stop{position:relative}
.why__stop::before{content:'';position:absolute;left:50%;top:78%;width:56px;height:56px;margin:-28px 0 0 -28px;border-radius:50%}
.why__drop,.why__drop::after{position:absolute;left:50%;top:78%;width:120px;height:120px;margin:-60px 0 0 -60px;border-radius:50%;border:1px solid rgba(0,0,0,.32);pointer-events:none;
 animation:why-drop 1.15s cubic-bezier(.2,.7,.2,1) forwards}
.why__drop::after{content:'';left:0;top:0;margin:0;width:100%;height:100%;box-sizing:border-box;border-color:rgba(0,0,0,.18);animation-delay:.14s;opacity:0}
@keyframes why-drop{from{transform:scale(.04);opacity:.9}to{transform:scale(1);opacity:0}}

/* ---------- The letter ----------
   Sarthak's story, as a passage you scroll through: each line has its own place on the page and
   arrives as it rises (body lines word by word, the large statements letter by letter). It opens
   the light half; white runs on from here to the end of the page. Order: the bigger picture,
   memory, privacy, free (call of 11 Oct), then the closing quote and one way onto the waitlist. */
.letter{padding:clamp(72px,14vh,160px) 0 clamp(120px,22vh,240px)}
/* The passage is set in the site's sans, regular; only the large statements are serif (owner, 13 Oct). */
.letter__col{display:grid;justify-items:center;gap:clamp(40px,7vh,72px);max-width:64rem;margin:0 auto;padding:0 6vw;text-align:center}
.letter__line{margin:0;max-width:34ch;font-family:var(--sans);font-weight:400;font-size:clamp(18px,1.53vw,24px);line-height:1.5;letter-spacing:-.011em;text-wrap:balance}
.letter__line--big{max-width:17ch;margin-block:clamp(24px,4vh,44px);font-family:var(--serif);font-size:var(--t-display);line-height:1.06;letter-spacing:-.03em}
.letter__promise{display:block;position:relative;width:max-content;margin-inline:auto}
/* "Free.* Forever.*": each asterisk arrives with its word; once both are written they fade and
   drop away, and "No asterisk." takes their place. --read is the line's travel (why.js). */
.letter__promise sup{position:absolute;left:calc(100% + .08em);top:.2em;font-size:.26em;line-height:1;
 --in:clamp(0,calc((var(--read,1) - var(--at))/.08),1);--out:clamp(0,calc((var(--read,1) - .68)/.16),1);
 opacity:calc(var(--in)*(1 - var(--out)));translate:0 calc(var(--out)*6px)}
.letter__promise:first-child sup{--at:.2}
.letter__promise:nth-child(2) sup{--at:.5}
.letter__free small{display:block;margin-top:28px;font:400 var(--t-body-sm)/24px var(--sans);letter-spacing:0;color:var(--muted);opacity:clamp(0,calc((var(--read,1) - .84)/.16),1)}
.letter .phrase{white-space:nowrap}
.letter .inline-marks{display:inline-flex;vertical-align:middle;align-items:center;height:1em;margin:0 .08em 0 .14em}
.letter .mark-disc{display:inline-flex;align-items:center;justify-content:center;width:1.05em;height:1.05em;border-radius:50%;background:#161616;border:1px solid #fff;position:relative} /* dark discs, as in T21: several of these marks are white drawings */
.letter .mark-disc+.mark-disc{margin-left:-.2em}
.letter .mark-disc:nth-child(2){z-index:1}.letter .mark-disc:nth-child(3){z-index:2}
.letter .mark-disc img{width:56%;height:56%;object-fit:contain;filter:grayscale(1);opacity:.94}
/* The quote closes the letter: the same large setting, its source beneath in the body's muted ink. */
.letter__quote{margin:clamp(40px,8vh,96px) 0 0;display:grid;justify-items:center;gap:24px}
.letter__quote[hidden]{display:none}
.letter__quote blockquote{max-width:20ch;margin:0}
.letter__quote figcaption{font:400 var(--t-body-sm)/24px var(--sans);color:var(--muted)}
/* One way onto the waitlist, under the letter's last words. It settles in as it rises (--in, why.js). */
#top .letter__cta.lg.lg--button{margin-top:clamp(8px,2vh,24px);min-height:44px!important;height:44px;padding:0 32px!important;
 opacity:var(--in,1);translate:0 calc((1 - var(--in,1))*14px)}
@media(max-width:600px){
 .letter__col{gap:clamp(32px,5vh,48px)}
 .letter__line{max-width:30ch}
}
/* A readable, linear version for reduced motion; no pin, flash, lens or text writing. */
@media(prefers-reduced-motion:reduce){
 .why{height:auto}
 .why__stage{position:relative;display:block;height:auto;min-height:0;overflow:hidden}
 .why__white,.why__ripple,.why__light,.why__halo{display:none}
 .why__wall{height:80svh;opacity:.35}
 .why__copy{display:flex;flex-direction:column;gap:40px;padding:100px 0 0;width:100%}
 .why__q,.why__serious{opacity:1;translate:none;padding:0 6vw}
 .why__pair{background:#fff;width:100%;padding:80px 6vw;translate:none;--o:1;display:flex;flex-direction:column;align-items:center;gap:40px}
 .why__orb{opacity:1;scale:1}
 .why .w>span,.letter .w,.letter .w>span{opacity:1!important}
}

/* T22 scroll reveal also owns the promise and its small final line. */
#letter .letter__free small{opacity:clamp(0,calc((var(--read,1) - .84)/.16),1)}
