/* App-screen kit: phone frames, interface components and design annotations.
   Set --ph (phone height) on a phone or its parent. Everything inside is sized in em, so the whole screen scales from that one value. */
.phone,.device{font-size:calc(var(--ph,520px) / 46)}
.phone{position:relative;flex:none;height:var(--ph,520px);width:calc(var(--ph,520px) * .4865);padding:.62em;border-radius:3.9em;background:#1f1e1b;box-shadow:inset 0 0 0 .14em #4d4b45,inset 0 0 0 .32em #12110f,0 2.8em 4.6em -1.8em rgba(48,47,43,.5),0 1em 1.8em -.8em rgba(48,47,43,.35);transition:box-shadow .8s,transform .8s cubic-bezier(.2,.8,.2,1)}
.phone-screen{position:relative;height:100%;border-radius:3.3em;overflow:hidden;background:var(--paper);color:var(--ink);display:flex;flex-direction:column;font-family:Arial,Helvetica,sans-serif;line-height:1.3;text-align:left}
.phone-screen p{line-height:1.35}
.phone-island{position:absolute;top:1.3em;left:50%;width:6.3em;height:1.95em;margin-left:-3.15em;border-radius:2em;background:#0d0d0c;z-index:5}
.device{position:relative;flex:none}

.ui-status{flex:none;height:4.3em;display:flex;align-items:center;justify-content:space-between;padding:0 2.1em 0 2.7em;font-weight:700;letter-spacing:.01em}
.ui-status-icons{display:flex;gap:.32em;align-items:center}
.ui-status svg{height:.92em;width:auto;fill:currentColor}
.ui-status .ui-wifi{fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round}

.ui-top{flex:none;display:flex;align-items:center;justify-content:space-between;gap:1em;min-height:3em;padding:.1em 1.6em .5em}
.ui-top b{font-size:1.1em}
.ui-back{font-size:2.3em;line-height:.8;font-weight:300;width:.8em}
.ui-skip{color:var(--muted)}
.ui-steps{flex:1;display:flex;gap:.35em}
.ui-steps i{flex:1;height:.32em;border-radius:.3em;background:rgba(48,47,43,.14)}
.ui-steps i.on{background:var(--ink)}
.ui-logo{font-family:Coolvetica,Arial,sans-serif;font-size:1.55em;letter-spacing:-.035em}
.ui-badge{font-size:.85em;font-weight:700;background:var(--coral);padding:.35em .75em;border-radius:1em}

.ui-body{flex:1;min-height:0;display:flex;flex-direction:column;padding:.4em 1.6em 0}
.ui-center{align-items:center;justify-content:center;text-align:center}
.ui-kicker{font-size:.85em;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin-bottom:.6em}
.ui-title{font-family:Coolvetica,Arial,sans-serif;font-weight:500;font-size:2.05em;line-height:1.02;letter-spacing:-.02em;margin:0 0 .4em}
.ui-help{font-size:1em;color:var(--muted);margin-bottom:1.1em}
.ui-footer{flex:none;display:flex;flex-direction:column;gap:.55em;padding:.8em 1.6em 2.1em}

.ui-btn{position:relative;display:flex;align-items:center;justify-content:center;height:3.6em;border-radius:2em;background:var(--ink);color:var(--paper);font-weight:700;font-size:1.02em;white-space:nowrap}
.ui-btn.coral{background:var(--coral);color:var(--ink)}
.ui-btn.ghost{background:transparent;color:var(--ink);box-shadow:inset 0 0 0 1px rgba(48,47,43,.25)}

.ui-options{display:flex;flex-direction:column;gap:.55em}
.ui-option{position:relative;display:grid;grid-template-columns:2.7em 1fr 1.5em;align-items:center;gap:.9em;padding:.8em 1em;border-radius:1.2em;background:#fff;box-shadow:0 0 0 1px rgba(48,47,43,.09);transition:background .5s,color .5s,box-shadow .5s,transform .6s cubic-bezier(.2,.8,.2,1)}
.ui-option b{display:block;font-size:1.15em;margin-bottom:.15em}
.ui-option small{display:block;font-size:.92em;line-height:1.3;color:var(--muted);transition:color .5s}
.ui-option-icon{width:2.7em;height:2.7em;border-radius:.85em;background:var(--stone);display:grid;place-items:center;transition:background .5s}
.ui-option-icon svg,.ui-inline-icon{width:1.45em;height:1.45em;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ui-radio{width:1.5em;height:1.5em;border-radius:50%;box-shadow:inset 0 0 0 .13em rgba(48,47,43,.28);transition:box-shadow .5s}
.ui-option.is-current{background:var(--ink);color:var(--paper);box-shadow:0 .9em 1.8em -.9em rgba(48,47,43,.7);transform:scale(1.025)}
.ui-option.is-current small{color:#d9d7cd}
.ui-option.is-current .ui-option-icon{background:var(--coral);color:var(--ink)}
.ui-option.is-current .ui-radio{box-shadow:inset 0 0 0 .45em var(--coral),inset 0 0 0 1em var(--paper)}

.ui-chips{display:flex;flex-wrap:wrap;gap:.45em}
.ui-chip{font-size:.98em;padding:.62em 1em;border-radius:2em;box-shadow:inset 0 0 0 1px rgba(48,47,43,.22)}
.ui-chip.on{background:var(--coral);box-shadow:none;font-weight:700}

.ui-avatar{width:2.6em;height:2.6em;border-radius:50%;object-fit:cover;object-position:50% 25%;display:block;flex:none}
.ui-duo{display:flex}
.ui-duo .ui-avatar{box-shadow:0 0 0 .2em var(--paper)}
.ui-duo .ui-avatar+.ui-avatar{margin-left:-.8em}

/* A tap: shows where the person presses on the current screen. */
.ui-tap{position:absolute;top:50%;right:22%;width:2.8em;height:2.8em;margin:-1.4em;border-radius:50%;background:rgba(255,104,64,.35);box-shadow:0 0 0 .14em rgba(255,104,64,.6);opacity:0;pointer-events:none}
.is-current .ui-tap{animation:ui-tap 1.6s cubic-bezier(.2,.7,.2,1) .45s both}
@keyframes ui-tap{0%{opacity:0;transform:scale(.5)}22%{opacity:1;transform:scale(.9)}36%{transform:scale(.72)}100%{opacity:0;transform:scale(1.7)}}

/* Design annotations: a numbered dot, a hairline leader and a short rationale. */
.ui-note{position:absolute;display:grid;grid-template-columns:28px 1fr;gap:14px;align-items:start;width:min(300px,21vw);font-size:16px}
.ui-note:before{content:'';position:absolute;top:14px;right:calc(100% + 10px);width:var(--lead,64px);height:1px;background:var(--ink);opacity:.45}
.ui-note:after{content:'';position:absolute;top:10px;right:calc(100% + 5.5px + var(--lead,64px));width:9px;height:9px;border-radius:50%;background:var(--ink);box-shadow:0 0 0 3px var(--paper)}
.ui-note-dot{width:28px;height:28px;border-radius:50%;background:var(--coral);color:var(--ink);font:700 13px Arial,sans-serif;display:grid;place-items:center}
.ui-note h4{font-family:Coolvetica,Arial,sans-serif;font-weight:500;font-size:23px;line-height:1.05;letter-spacing:-.01em;margin:2px 0 7px}
.ui-note p{font-size:15px;line-height:1.42;color:var(--muted)}

body.motion-paused .ui-tap{animation:none}

/* ---------- Motion kit ----------
   Spring easings sampled from a damped spring (soft: 2% overshoot, snap: 8%, bounce: 20%). Pair each with its settle time:
   soft .9s, snap .85s, bounce 1.25s. */
:root{
 --spring-soft:linear(0, .0126, .0463, .0954, .1552, .2218, .292, .3634, .4339, .5021, .5667, .6271, .6828, .7334, .7789, .8194, .8551, .8861, .9128, .9355, .9546, .9705, .9834, .9938, 1.002, 1.0082, 1.0129, 1.0161, 1.0182, 1.0195, 1.0199, 1.0198, 1.0192, 1.0183, 1.0171, 1.0158, 1.0145, 1.013, 1.0116, 1.0102, 1.0089, 1.0077, 1.0066, 1.0055, 1.0046, 1.0038, 1.0031, 1.0024, 1);
 --spring-snap:linear(0, .02, .0729, .1492, .2407, .3404, .4426, .5428, .6377, .7248, .8025, .8701, .9272, .9741, 1.0113, 1.0396, 1.0599, 1.0732, 1.0808, 1.0835, 1.0824, 1.0784, 1.0723, 1.0648, 1.0566, 1.048, 1.0396, 1.0316, 1.0242, 1.0176, 1.0118, 1.0068, 1.0028, .9995, .9971, .9953, .994, .9933, .993, .9931, .9934, .9939, .9945, .9952, .9959, .9966, .9972, .9979, 1);
 --spring-bounce:linear(0, .0378, .1366, .2755, .4351, .5992, .755, .8929, 1.0071, 1.0948, 1.1556, 1.1912, 1.2049, 1.2006, 1.1828, 1.1558, 1.1236, 1.0899, 1.0573, 1.028, 1.0034, .9841, .9704, .962, .9582, .9583, .9614, .9666, .9731, .98, .9868, .993, .9982, 1.0025, 1.0055, 1.0075, 1.0085, 1.0086, 1.0081, 1.0071, 1.0058, 1.0044, 1.003, 1.0017, 1.0006, .9997, .999, .9985, 1);
}
/* Browsers without linear() easing (iOS 16 and earlier, older Chrome) would drop every animation that uses these springs,
   so give them close cubic-bezier stand-ins with similar overshoot. */
@supports not (transition-timing-function: linear(0, 1)) {
 :root{--spring-soft:cubic-bezier(.22,1.06,.36,1);--spring-snap:cubic-bezier(.3,1.22,.4,1);--spring-bounce:cubic-bezier(.34,1.5,.5,1)}
}

/* A solid phone: sides and a back plate make it read as a device when it turns in 3D.
   Never fade a wrapper of a turning phone with opacity: that flattens the 3D and shows the screen mirrored.
   The same goes for any 3D container: an entrance animation that touches opacity flattens it for as long as it fills.
   Give an ancestor `perspective` and keep `transform-style:preserve-3d` on every wrapper between it and the phone. */
.phone{--t:1em;transform-style:preserve-3d}
.phone-screen{transform:translateZ(.6px)}
.phone-island{transform:translateZ(1px)}
.phone::after{content:'';position:absolute;inset:.62em;border-radius:3.3em;background:var(--paper);opacity:var(--dim,0);transform:translateZ(1.2px);pointer-events:none;transition:opacity .7s}
.phone-side,.phone-back{position:absolute;display:block;pointer-events:none}
.phone-side-l,.phone-side-r{top:4em;bottom:4em;width:var(--t)}
.phone-side-t,.phone-side-b{left:4em;right:4em;height:var(--t)}
.phone-side-l{left:0;transform-origin:left center;transform:rotateY(90deg);background:linear-gradient(90deg,#55524b,#9d988d 45%,#3a3833)}
.phone-side-r{right:0;transform-origin:right center;transform:rotateY(-90deg);background:linear-gradient(90deg,#3a3833,#9d988d 55%,#55524b)}
.phone-side-t{top:0;transform-origin:center top;transform:rotateX(-90deg);background:linear-gradient(#4d4a44,#8f8a80 50%,#3a3833)}
.phone-side-b{bottom:0;transform-origin:center bottom;transform:rotateX(90deg);background:linear-gradient(#3a3833,#8f8a80 50%,#4d4a44)}
.phone-back{inset:0;border-radius:3.9em;transform:translateZ(calc(var(--t) * -1)) rotateY(180deg);background:radial-gradient(120% 80% at 30% 15%,#5a5750,#2c2b27 60%,#1f1e1b);box-shadow:inset 0 0 0 .3em #3d3b36}
.phone-back:before{content:'';position:absolute;top:1.7em;left:1.7em;width:9em;height:9.4em;border-radius:2.4em;background:linear-gradient(145deg,#45433d,#25241f);box-shadow:inset 0 0 0 .12em #5d5a52,0 .4em 1em rgba(0,0,0,.4)}
.phone-back:after{content:'';position:absolute;top:2.6em;left:2.6em;width:3.2em;height:3.2em;border-radius:50%;background:radial-gradient(circle at 40% 35%,#3e5a6b,#0b0c0d 60%);box-shadow:0 4.2em 0 0 #0b0c0d,3.9em 2.1em 0 -.6em #0b0c0d,inset 0 0 0 .35em #2e2d29}

/* Words that rise out of a mask. Build them with DD_UI.reveal(). They play when the scene opens,
   and inside a [data-show] frame each time that frame is shown. */
.rw{display:inline-block;overflow:hidden;vertical-align:bottom;padding:0 .04em .16em;margin:0 -.04em -.16em}
.rw>span{display:inline-block;transform-origin:0 100%}
.scene.active .rw>span{animation:dd-rise .95s var(--spring-soft) calc(.15s + var(--i,0) * 55ms) both}
.scene.active [data-show]:not(.is-shown) .rw>span{animation:none}
@keyframes dd-rise{from{transform:translateY(112%) rotate(5deg)}to{transform:none}}
@keyframes dd-blur-in{from{opacity:0;filter:blur(14px);transform:translateY(14px) scale(.98)}}
@keyframes dd-pop{0%{transform:scale(.4);opacity:0}100%{transform:none;opacity:1}}
@keyframes dd-press{0%,100%{transform:none}35%{transform:scale(.94)}}
body.motion-paused .rw>span{animation:none!important}

/* Annotations draw in once a slide has settled: the dot lands on the target, the line grows out to the note, then the words. */
.scene.active .ui-note:after{animation:dd-pop .7s var(--spring-bounce) 1.25s both}
.scene.active .ui-note:before{transform-origin:left center;animation:ui-line .6s cubic-bezier(.6,0,.2,1) 1.4s both}
.scene.active .ui-note-dot{animation:dd-pop .7s var(--spring-bounce) 1.75s both}
.scene.active .ui-note>div{animation:dd-blur-in .8s ease 1.85s both}
.scene.active .ui-note+.ui-note:after{animation-delay:1.5s}
.scene.active .ui-note+.ui-note:before{animation-delay:1.65s}
.scene.active .ui-note+.ui-note .ui-note-dot{animation-delay:2s}
.scene.active .ui-note+.ui-note>div{animation-delay:2.1s}
@keyframes ui-line{from{transform:scaleX(0)}}

/* Paused or reduced motion: skip entrances so everything simply shows in its final place. */
body.motion-paused .ui-note,body.motion-paused .ui-note:before,body.motion-paused .ui-note:after,body.motion-paused .ui-note-dot,body.motion-paused .ui-note>div{animation:none!important}

/* Chat bubbles and a typing indicator, sized in phone em. */
.ui-msg{width:fit-content;max-width:80%;padding:.62em .95em;border-radius:1.25em;font-size:1.02em;line-height:1.3}
.ui-msg.in{background:#fff;box-shadow:0 0 0 1px rgba(48,47,43,.08);border-bottom-left-radius:.4em}
.ui-msg.out{margin-left:auto;background:var(--ink);color:var(--paper);border-bottom-right-radius:.4em}
.ui-typing{display:inline-flex;width:fit-content;gap:.28em;padding:.8em .95em;border-radius:1.25em;border-bottom-left-radius:.4em;background:#fff;box-shadow:0 0 0 1px rgba(48,47,43,.08)}
.ui-typing i{width:.45em;height:.45em;border-radius:50%;background:var(--muted);animation:ui-dot 1s ease-in-out infinite}
.ui-typing i:nth-child(2){animation-delay:.15s}.ui-typing i:nth-child(3){animation-delay:.3s}
@keyframes ui-dot{0%,60%,100%{transform:none;opacity:.35}30%{transform:translateY(-.32em);opacity:1}}

/* Slide headings: one short line, one supporting line. */
.hd h2{font-size:clamp(44px,4.6vw,78px);line-height:.95;letter-spacing:-.035em}
.hd p{font-family:Coolvetica,Arial,sans-serif;font-size:clamp(19px,1.6vw,25px);line-height:1.15;color:var(--muted);margin-top:clamp(10px,1.8vh,18px);max-width:520px}

/* Beat helpers: put data-show="<beats>" on an element and add one of these. --dl delays the entrance.
   They use the individual translate/scale properties, so the element's own transform stays free. */
.on-pop{opacity:0;scale:.55;transition:opacity .35s ease,scale .85s var(--spring-bounce)}
.on-rise{opacity:0;translate:0 28px;filter:blur(8px);transition:opacity .45s ease,translate .9s var(--spring-snap),filter .5s ease}
.on-fade{opacity:0;transition:opacity .6s ease}
:is(.on-pop,.on-rise,.on-fade).is-shown{opacity:1;scale:1;translate:0 0;filter:none;transition-delay:var(--dl,0s)}
.on-type{clip-path:inset(0 100% 0 0)}
.on-type.is-shown{animation:type-in var(--td,1.2s) steps(var(--n,24)) var(--dl,0s) both}
@keyframes type-in{to{clip-path:inset(0 0 0 0)}}
body.motion-paused .on-type.is-shown{animation:none;clip-path:none}

/* Scene stage: children with .el sit at the centre and move by --x/--y (percent of the stage), --s scale,
   --r rotation, --o opacity, --b blur and --d delay. Change those per [data-step] and the springs do the rest. */
.cq{position:relative;container-type:size}
.el{--x:0;--y:0;--s:1;--o:1;--b:0px;--r:0deg;--d:0s;position:absolute;left:50%;top:50%;margin:0;opacity:var(--o);filter:blur(var(--b));transform:translate(-50%,-50%) translate(calc(var(--x) * 1cqw),calc(var(--y) * 1cqh)) rotate(var(--r)) scale(var(--s));transition:transform 1.1s var(--spring-soft) var(--d),opacity .55s ease var(--d),filter .6s ease var(--d),background .5s,color .5s,box-shadow .5s}
.el.snap{transition-timing-function:var(--spring-snap),ease,ease,ease,ease,ease}
.el.bouncy{transition-timing-function:var(--spring-bounce),ease,ease,ease,ease,ease}

/* Step list beside a scene: the current step is bold and its bar fills while it plays. */
.stp{list-style:none;margin:clamp(26px,5vh,50px) 0 0;padding:0;display:flex;flex-direction:column;gap:clamp(10px,1.9vh,20px)}
.stp li{position:relative;display:grid;grid-template-columns:42px 1fr;opacity:.28;transition:opacity .5s,transform .8s var(--spring-snap)}
.stp li b{font:700 12px/1.9 Arial,sans-serif;letter-spacing:.04em;color:#bd4127}
.stp li strong{display:block;font-family:Coolvetica,Arial,sans-serif;font-weight:500;font-size:clamp(22px,1.9vw,30px);line-height:1.05}
.stp li span{display:block;font-size:clamp(14px,1.1vw,17px);line-height:1.35;color:var(--muted);max-height:0;overflow:hidden;opacity:0;transition:max-height .7s var(--spring-soft),opacity .5s,margin .5s}
.stp li.is-current{opacity:1;transform:translateX(8px)}
.stp li.is-current span{max-height:4em;opacity:1;margin-top:6px}
.stp li:before{content:'';position:absolute;left:-14px;top:4px;bottom:4px;width:2px;background:var(--line)}
.stp li.is-current:after{content:'';position:absolute;left:-14px;top:4px;width:2px;height:calc(100% - 8px);background:var(--coral);transform-origin:top;animation:stp-fill 3.8s linear both}
@keyframes stp-fill{from{transform:scaleY(0)}}
body.motion-paused .stp li:after{animation:none}

/* ---------- Live scenes: the café and mini golf drawings with moving people ----------
   Built by DD_UI.live.cafe() / .golf(). 1cqw = 1% of the scene width, so every motion scales with it. */
.live{position:relative;width:100%;aspect-ratio:1536/1024;container-type:inline-size}
.live>*,.lv-hop>*{position:absolute}
.live>.lv-plate{inset:0;width:100%;height:100%}
.live .lv{height:auto;display:block}
.lv-hop{inset:0}

/* Café, 6.4 s: Mina tells a story while Alex listens and nods; then he laughs and she leans in. */
.lv-ca{transform-origin:37.5% 97.6%;animation:lv-ca 6.4s ease-in-out infinite}
.lv-cm{transform-origin:52.9% 97.4%;animation:lv-cm 6.4s ease-in-out infinite}
@keyframes lv-ca{0%{transform:none}8%{transform:rotate(.6deg)}12%{transform:rotate(2.1deg)}16%{transform:rotate(1.1deg)}20%{transform:rotate(2.7deg)}24%{transform:rotate(1.8deg)}40%,46%{transform:rotate(3.2deg)}50%{transform:rotate(1.3deg) translateY(-2.2%)}54%{transform:rotate(2.7deg)}58%{transform:rotate(1.1deg) translateY(-2.2%)}62%{transform:rotate(2.2deg)}66%{transform:rotate(1deg) translateY(-1.4%)}70%{transform:rotate(1.8deg)}100%{transform:none}}
@keyframes lv-cm{0%{transform:none}6%{transform:rotate(-2.2deg) translateY(-1%)}12%{transform:rotate(1deg)}18%{transform:rotate(-2.8deg) translateY(-1.2%)}24%{transform:rotate(.5deg)}30%{transform:rotate(-2deg) translateY(-.8%)}36%{transform:rotate(.8deg)}44%{transform:rotate(-.6deg)}54%{transform:rotate(-3.4deg)}70%{transform:rotate(-4deg) translateY(-.6%)}100%{transform:none}}
.lv-glow{left:65.1%;top:27.8%;width:16cqw;height:16cqw;margin:-8cqw 0 0 -8cqw;border-radius:50%;background:radial-gradient(circle,rgba(255,238,205,.8),rgba(255,222,175,0) 62%);mix-blend-mode:screen;animation:lv-glow 3.2s ease-in-out infinite alternate}
@keyframes lv-glow{from{opacity:.3;transform:scale(.88)}to{opacity:.8;transform:scale(1.08)}}

/* Speech bubbles and the heart. */
.lv-bub{z-index:3;display:flex;align-items:center;gap:.22em;white-space:nowrap;font-family:Coolvetica,Arial,sans-serif;font-size:2cqw;line-height:1;padding:.5em .75em;border-radius:1em;background:#fff;color:var(--ink);box-shadow:0 .6cqw 1.4cqw -.6cqw rgba(48,47,43,.45);transform-origin:30% 100%;opacity:0}
.lv-bub:after{content:'';position:absolute;left:28%;bottom:-.32em;width:.7em;height:.7em;background:#fff;border-radius:.12em;transform:rotate(45deg)}
.lv-bub i{position:relative;z-index:1;width:.42em;height:.42em;border-radius:50%;background:var(--ink);animation:ui-dot 1s ease-in-out infinite}
.lv-bub i:nth-child(2){animation-delay:.15s}.lv-bub i:nth-child(3){animation-delay:.3s}
.lv-bub-m{left:50.5%;top:19.5%;transform-origin:70% 100%;animation:lv-bub-m 6.4s infinite}
.lv-bub-m:after{left:auto;right:28%}
.lv-bub-a{left:33%;top:16%;animation:lv-bub-a 6.4s infinite}
@keyframes lv-bub-m{0%,3%{opacity:0;transform:scale(.3)}8%{opacity:1;transform:scale(1.08)}11%,38%{opacity:1;transform:none}43%,100%{opacity:0;transform:scale(.7) translateY(.6cqw)}}
@keyframes lv-bub-a{0%,47%{opacity:0;transform:scale(.3)}52%{opacity:1;transform:scale(1.08) rotate(-4deg)}55%,76%{opacity:1;transform:rotate(-4deg)}81%,100%{opacity:0;transform:scale(.7) rotate(-4deg)}}
.lv-heart{z-index:3;left:48.6%;top:34%;font-size:3cqw;line-height:1;color:var(--coral);text-shadow:0 .3cqw .8cqw rgba(255,104,64,.45);opacity:0;animation:lv-heart 6.4s ease-out infinite}
@keyframes lv-heart{0%,60%{opacity:0;transform:translateY(0) scale(.2)}66%{opacity:1;transform:translateY(-1cqw) scale(1.15)}72%{transform:translateY(-2cqw) scale(1) rotate(-6deg)}90%{opacity:0;transform:translateY(-6cqw) scale(.9) rotate(8deg)}100%{opacity:0}}

/* Mini golf, 5.2 s: Mina lines up and putts, the ball curls into the hole, they both jump, Alex cheers. */
.lv-ga{transform-origin:41.7% 90.5%;animation:lv-ga 5.2s ease-in-out infinite}
.lv-gm{transform-origin:52.5% 96.3%;animation:lv-gm 5.2s ease-in-out infinite}
.lv-club{transform-origin:83.6% 4.9%;animation:lv-club 5.2s infinite}
.lv-ball{z-index:2;animation:lv-ball 5.2s infinite}
.lv-hop-m{animation:lv-hop 5.2s infinite}
.lv-hop-a{animation:lv-hop 5.2s .12s infinite}
@keyframes lv-ga{0%{transform:none}16%{transform:rotate(-1deg)}36%{transform:rotate(1.6deg)}54%{transform:rotate(3.6deg)}61%,100%{transform:none}}
@keyframes lv-gm{0%{transform:none}22%,29%{transform:rotate(1.1deg)}35%{transform:rotate(-1.2deg)}46%,100%{transform:none}}
@keyframes lv-club{0%{transform:none;animation-timing-function:ease-in-out}22%{transform:rotate(17deg)}29%{transform:rotate(17deg);animation-timing-function:cubic-bezier(.55,0,.9,.4)}34%{transform:rotate(-7deg);animation-timing-function:ease-out}44%{transform:rotate(2deg)}52%,100%{transform:none}}
@keyframes lv-ball{0%,33%{transform:none;opacity:1;animation-timing-function:ease-out}40%{transform:translate(.75cqw,.85cqw);animation-timing-function:linear}48%{transform:translate(-.45cqw,1.95cqw);animation-timing-function:ease-out}55%{transform:translate(-2.3cqw,1.86cqw)}58%{transform:translate(-2.54cqw,1.88cqw) scale(.55);opacity:.7}60%,90%{transform:translate(-2.54cqw,1.88cqw) scale(.15);opacity:0}91%{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.3,1.6,.5,1)}97%,100%{transform:none;opacity:1}}
@keyframes lv-hop{0%,59%{transform:none;animation-timing-function:cubic-bezier(.2,.7,.3,1)}64%{transform:translateY(-1.6cqw);animation-timing-function:cubic-bezier(.6,0,.85,.4)}68%{transform:none;animation-timing-function:cubic-bezier(.2,.7,.3,1)}71%{transform:translateY(-.7cqw);animation-timing-function:cubic-bezier(.6,0,.85,.4)}74%,100%{transform:none}}
.lv-shadow{width:5.4cqw;height:1.2cqw;margin:-.6cqw 0 0 -2.7cqw;border-radius:50%;background:radial-gradient(closest-side,rgba(28,48,30,.32),rgba(28,48,30,0));animation:lv-sh 5.2s infinite}
.lv-sa{left:39.4%;top:53.6%;animation-delay:.12s}.lv-sm{left:51.8%;top:54%}
@keyframes lv-sh{0%,59%,68%,74%,100%{transform:none;opacity:1}64%{transform:scale(.7);opacity:.45}71%{transform:scale(.85);opacity:.7}}
.lv-ring{z-index:2;left:46.1%;top:58.9%;width:3.4cqw;height:1.7cqw;margin:-.85cqw 0 0 -1.7cqw;border-radius:50%;box-shadow:0 0 0 .22cqw var(--coral);opacity:0;animation:lv-ring 5.2s ease-out infinite}
@keyframes lv-ring{0%,57%{opacity:0;transform:scale(.4)}60%{opacity:1;transform:scale(.9)}74%,100%{opacity:0;transform:scale(2.4)}}
.lv-bub-g{left:34.5%;top:12%;animation:lv-bub-g 5.2s infinite}
@keyframes lv-bub-g{0%,60%{opacity:0;transform:scale(.3)}64%{opacity:1;transform:scale(1.1) rotate(-5deg)}67%,86%{opacity:1;transform:rotate(-5deg)}91%,100%{opacity:0;transform:scale(.7) rotate(-5deg)}}

/* Phones enter by rising from below the bottom edge of the screen into place, turning to face the audience as they land.
   Uses the individual translate/rotate properties so it stacks on any tilt the phone already has. No opacity: the phone
   starts off-screen, and fading a 3D object would flatten it. */
@keyframes dd-phone-in{from{translate:0 108vh;rotate:1 -.7 0 34deg}}
body.motion-paused :is(.phone,.o-aud-fly,.j-ring){animation:none!important}

/* Pinned notes: position per step (set by DD_UI.pin) and a three-part leader that bends when a note had to move
   to avoid another. --dy is the target's offset from the note's own line: 0 means a straight line. */
.ui-note[data-pin]{top:var(--ny0);--dy:var(--dy0,0px);transition:top .8s var(--spring-snap)}
.scene[data-step="1"] .ui-note[data-pin]{top:var(--ny1,var(--ny0));--dy:var(--dy1,var(--dy0,0px))}
.scene[data-step="2"] .ui-note[data-pin]{top:var(--ny2,var(--ny0));--dy:var(--dy2,var(--dy0,0px))}
.scene[data-step="3"] .ui-note[data-pin]{top:var(--ny3,var(--ny0));--dy:var(--dy3,var(--dy0,0px))}
.ui-note[data-pin]:before{display:none}
.ui-note[data-pin]:after{top:calc(10px + var(--dy));transition:top .8s var(--spring-snap)}
.ui-note-lead{position:absolute;right:calc(100% + 10px);width:var(--lead,64px);top:calc(14px + min(var(--dy), 0px));height:calc(max(var(--dy), var(--dy) * -1) + 1px);pointer-events:none;transition:top .8s var(--spring-snap),height .8s var(--spring-snap)}
.ui-note-lead i{position:absolute;display:block;background:var(--ink);opacity:.45;transition:top .8s var(--spring-snap)}
.ui-note-lead i:nth-child(1){left:0;width:50%;height:1px;top:max(var(--dy), 0px)}
.ui-note-lead i:nth-child(2){left:50%;width:1px;top:0;bottom:0}
.ui-note-lead i:nth-child(3){left:50%;width:50%;height:1px;top:max(calc(var(--dy) * -1), 0px)}
.scene.active .ui-note-lead{animation:ui-lead .6s cubic-bezier(.6,0,.2,1) 1.4s both}
.scene.active .ui-note+.ui-note .ui-note-lead{animation-delay:1.65s}
@keyframes ui-lead{from{clip-path:inset(-4px 100% -4px 0)}to{clip-path:inset(-4px 0 -4px 0)}}
body.motion-paused .ui-note-lead{animation:none!important}

