/* Donnie's movements (tools/illustrations/donnie.mjs - a capybara in a kilt;
   donnie-site.mjs - Donnie in his hard hat beside the digger).
   Martin, 12 October 2026: "donnie should be interative always moving
   slightly. You know like a google thing moves".

   ALWAYS, on .donnie: he breathes (.dd-all, on his feet), looks about now
   and then (.dd-head), his arm sways (.dd-arm), he blinks (.dd-eyes), and the
   digger's exhaust puffs (.ds-puff). The page moves his eye towards the
   pointer (.dd-look, home-donnie.js).
   MOODS, a class on .donnie, replace the idle movement of that part:
     .is-hello      he raises his arm and waves (on load, and on hover);
     .is-thinking   his head tilts back and forth while an answer comes;
     .is-nod        one small nod - "got it".
     .is-digging    the digger lifts its arm and scoops (a click on the digger;
                    Martin: "if you click on the excavator the arm and bucket can move").
     .is-inside     he has walked to the digger and sits in the cab (a triple click on
                    him); .is-leaving - he climbs out and walks back (a click on him
                    in the cab). Martin: "if you triple click on him i want him to go
                    inside the digger. and then if you click on him in the digger he
                    comes back out." The end states are plain rules, so under reduced
                    motion he simply is in the cab, or beside it.
     .is-loading    with Donnie in the cab, a click on the bucket: the dumper comes
                    on from the right, the digger scoops, swings round, empties into
                    the dumper, swings back, and the dumper drives off loaded. One
                    seven-second sequence; every part's keyframes share its clock.
                    Martin: "i want a dumper reverse on to the right hand side and
                    then the digger scoops up, swings round and empties into the
                    dumper" - for the real Donnie's amusement, and a surprise for
                    the website's visitors.
   Each part turns on its own pin, in the drawing's own coordinates (the
   numbers in each part's data-pin). Small movements on purpose. Under reduced
   motion nothing moves. */
.donnie .dd-all { transform-box: view-box; transform-origin: 192px 396px; animation: dd-breathe 3.4s ease-in-out infinite alternate; }
.donnie .dd-arm { transform-box: view-box; transform-origin: 178px 196px; animation: dd-sway 4.2s ease-in-out infinite alternate; }
.donnie .dd-head { transform-box: view-box; transform-origin: 210px 170px; animation: dd-look 9s ease-in-out infinite; }
.donnie .dd-eyes { transform-box: view-box; transform-origin: 184px 90px; animation: dd-blink 5s infinite 1.5s; }
.donnie .dd-look { transition: transform .25s ease-out; }
.donnie .ds-puff { transform-box: fill-box; transform-origin: center; opacity: 0; animation: ds-puff 3.6s ease-out infinite; }
.donnie .ds-puff-2 { animation-delay: 1.2s; }
.donnie .ds-puff-3 { animation-delay: 2.4s; }
.donnie .ex-arm { transform-box: view-box; transform-origin: 222px 192px; }
.donnie .ex-bucket { transform-box: view-box; transform-origin: 390px 246px; }
.donnie .ds-digger { cursor: pointer; }
.donnie.is-digging .ex-arm { animation: ex-lift 2.6s ease-in-out 1; }
.donnie.is-digging .ex-bucket { animation: ex-scoop 2.6s ease-in-out 1; }
/* in and out of the cab - in donnie-site.svg's own units: he stands at x 611 on the ground (396), the cab door is near x 395, y 296 */
.donnie .ds-walk { transform-box: view-box; transform-origin: 611px 396px; }
.donnie .ds-driver { opacity: 0; pointer-events: none; }
.donnie.is-inside .ds-walk { opacity: 0; pointer-events: none; animation: ds-walk-in 1.6s ease-in-out backwards; }
.donnie.is-inside .ds-driver { opacity: 1; pointer-events: auto; cursor: pointer; animation: ds-pop .45s ease-out 1.45s backwards; }
.donnie.is-leaving .ds-driver { animation: ds-pop .3s ease-in reverse both; }
.donnie.is-leaving .ds-walk { animation: ds-walk-in 1.6s ease-in-out .2s reverse backwards; }
/* the loading sequence */
.donnie .ds-dumper { transform: translateX(420px); }
.donnie .dm-load, .donnie .ex-dirt { opacity: 0; }
.donnie .ex-house { transform-box: view-box; transform-origin: 160px 232px; }
.donnie .ex-dipper { transform-box: view-box; transform-origin: 366px 148px; }
.donnie.is-loading .ds-dumper { animation: ds-drive 7s ease-in-out 1; }
.donnie.is-loading .dm-load { animation: dm-fill 7s linear 1; }
.donnie.is-loading .ex-house { animation: ex-slew 7s ease-in-out 1; }
.donnie.is-loading .ex-arm { animation: ex-load-arm 7s ease-in-out 1; }
.donnie.is-loading .ex-dipper { animation: ex-load-dip 7s ease-in-out 1; }
.donnie.is-loading .ex-bucket { animation: ex-load-bucket 7s ease-in-out 1; }
.donnie.is-loading .ex-dirt { animation: ex-dirt 7s linear 1; }
.donnie.is-loading .ex-logo { animation: ex-logo 7s linear 1; }
.donnie.is-loading .ds-cab { cursor: default; }
.donnie.is-hello .dd-arm { animation: dd-wave 1.8s ease-in-out 1; }
.donnie.is-thinking .dd-head { animation: dd-tilt .9s ease-in-out infinite alternate; }
.donnie.is-nod .dd-head { animation: dd-nod .6s ease-in-out 1; }
@keyframes dd-breathe { from { transform: scale(1, 1); } to { transform: scale(1.012, 1.022); } }
@keyframes dd-sway { from { transform: rotate(0); } to { transform: rotate(-7deg); } }
@keyframes dd-look { 0%, 30%, 100% { transform: rotate(0); } 40%, 52% { transform: rotate(-4deg); } 62%, 78% { transform: rotate(3deg); } }
@keyframes dd-blink { 0%, 95%, 100% { transform: scaleY(1); } 97% { transform: scaleY(.1); } }
@keyframes dd-wave { 0%, 100% { transform: rotate(0); } 20%, 60% { transform: rotate(-80deg); } 40%, 80% { transform: rotate(-60deg); } }
@keyframes dd-tilt { from { transform: rotate(0); } to { transform: rotate(-5deg); } }
@keyframes dd-nod { 0%, 100% { transform: rotate(0); } 45% { transform: rotate(6deg); } }
@keyframes ex-lift { 0%, 100% { transform: rotate(0); } 15% { transform: rotate(2deg); } 50%, 65% { transform: rotate(-16deg); } }
@keyframes ex-scoop { 0%, 100% { transform: rotate(0); } 15%, 30% { transform: rotate(30deg); } 50%, 65% { transform: rotate(18deg); } 80% { transform: rotate(-20deg); } }
@keyframes ds-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 12% { transform: translate(-22px, -5px); } 24% { transform: translate(-44px, 0); } 36% { transform: translate(-66px, -5px); } 48% { transform: translate(-88px, 0); } 75% { transform: translate(-180px, -96px) scale(.85); opacity: 1; } 100% { transform: translate(-216px, -100px) scale(.6); opacity: 0; } }
@keyframes ds-pop { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes ds-drive { 0% { transform: translateX(420px); } 22%, 80% { transform: translateX(0); } 100% { transform: translateX(440px); } }
@keyframes dm-fill { 0%, 54% { opacity: 0; } 58%, 100% { opacity: 1; } }
@keyframes ex-slew { 0%, 22% { transform: scaleX(1); } 40%, 60% { transform: scaleX(-1); } 78%, 100% { transform: scaleX(1); } }
@keyframes ex-load-arm { 0% { transform: rotate(0); } 8%, 16% { transform: rotate(4deg); } 28%, 62% { transform: rotate(-45deg); } 78%, 100% { transform: rotate(0); } }
@keyframes ex-load-dip { 0%, 16% { transform: rotate(0); } 28%, 62% { transform: rotate(25deg); } 78%, 100% { transform: rotate(0); } }
@keyframes ex-load-bucket { 0% { transform: rotate(0); } 8% { transform: rotate(-12deg); } 16%, 44% { transform: rotate(35deg); } 50%, 58% { transform: rotate(-45deg); } 70%, 100% { transform: rotate(0); } }
@keyframes ex-dirt { 0%, 14% { opacity: 0; } 17%, 47% { opacity: 1; } 51%, 100% { opacity: 0; } }
@keyframes ex-logo { 0%, 29% { opacity: 1; } 31%, 69% { opacity: 0; } 71%, 100% { opacity: 1; } }
@keyframes ds-puff { 0% { opacity: 0; transform: translate(0, 0) scale(.5); } 15% { opacity: .9; } 100% { opacity: 0; transform: translate(-10px, -42px) scale(1.7); } }
/* ---- THE OTHER SCENES (one is picked at random on each visit, home-donnie.js).
   Martin, 12 October: "can it show a different Donnie scenario each time you go
   on the website". Each works as the digger does: three clicks walk Donnie into
   the driving seat (his own walk, to his own door), a click on him brings him
   out, and with him inside a click on the vehicle (.ds-go) runs the scene's
   sequence. Standing, a click on the vehicle gives it a little bounce.
   Every number below is in that scene's own units (tools/illustrations/donnie-*.mjs). */
.donnie .ds-go { cursor: pointer; }
.donnie.is-digging .ds-go { animation: ds-bounce .7s ease-in-out 1; }
@keyframes ds-bounce { 0%, 50%, 100% { transform: translateY(0); } 25% { transform: translateY(-3px); } 75% { transform: translateY(-1.5px); } }
.donnie.is-inside .illo-donnie-taxi .ds-walk, .donnie.is-inside .illo-donnie-bins .ds-walk, .donnie.is-inside .illo-donnie-farm .ds-walk, .donnie.is-inside .illo-donnie-crane .ds-walk,
.donnie.is-leaving .illo-donnie-taxi .ds-walk, .donnie.is-leaving .illo-donnie-bins .ds-walk, .donnie.is-leaving .illo-donnie-farm .ds-walk, .donnie.is-leaving .illo-donnie-crane .ds-walk { animation-duration: 2s; }
.donnie.is-inside .illo-donnie-taxi .ds-driver, .donnie.is-inside .illo-donnie-bins .ds-driver, .donnie.is-inside .illo-donnie-farm .ds-driver, .donnie.is-inside .illo-donnie-crane .ds-driver { animation-delay: 1.85s; }
/* the chip shop and the two sales have nothing to get into: a click on the shop or
   the building (.ds-run) starts the sequence straight away */
.donnie .ds-run { cursor: pointer; }

/* the taxi rank (donnie-taxi.mjs): he stands at x 502; the driver's door is near x 200 */
.illo-donnie-taxi .ds-walk { transform-origin: 502px 396px; }
.donnie.is-inside .illo-donnie-taxi .ds-walk, .donnie.is-leaving .illo-donnie-taxi .ds-walk { animation-name: tx-walk-in; }
.donnie .tx-pass { opacity: 0; }
.illo-donnie-taxi .tx-friend { transform-box: view-box; transform-origin: 627px 396px; }
.donnie.is-loading .tx-car { animation: tx-trip 10s ease-in-out 1; }
.donnie.is-loading .tx-friend { animation: tx-fare 10s linear 1; }
.donnie.is-loading .tx-pass { animation: tx-pass 10s linear 1; }
@keyframes tx-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 12% { transform: translate(-30px, -5px); } 24% { transform: translate(-60px, 0); } 36% { transform: translate(-90px, -5px); } 48% { transform: translate(-120px, 0); } 60% { transform: translate(-160px, -4px); } 75% { transform: translate(-250px, -34px) scale(.85); opacity: 1; } 100% { transform: translate(-300px, -44px) scale(.6); opacity: 0; } }
/* off to the left, round from the right to the rank, the fare gets in, off to the left again, round from the right, home */
@keyframes tx-trip { 0%, 4% { transform: translateX(0); } 16% { transform: translateX(-470px); } 16.01% { transform: translateX(800px); } 30%, 50% { transform: translateX(310px); } 62% { transform: translateX(-470px); } 62.01% { transform: translateX(800px); } 80%, 100% { transform: translateX(0); } }
@keyframes tx-fare { 0%, 33% { transform: none; opacity: 1; } 39% { transform: translate(-8px, -6px) scale(.9); opacity: 1; } 45% { transform: translate(-14px, -30px) scale(.6); opacity: 0; } 90% { transform: none; opacity: 0; } 98%, 100% { transform: none; opacity: 1; } }
@keyframes tx-pass { 0%, 43% { opacity: 0; } 46%, 62% { opacity: 1; } 62.5%, 100% { opacity: 0; } }

/* the bin round (donnie-bins.mjs): he stands at x 542; the cab door is near x 97, y 242;
   the lift is at x 489 and the bins' left edges at 602 and 668 */
.illo-donnie-bins .ds-walk { transform-origin: 542px 396px; }
.donnie.is-inside .illo-donnie-bins .ds-walk, .donnie.is-leaving .illo-donnie-bins .ds-walk { animation-name: bn-walk-in; }
.donnie .bn-bits { opacity: 0; }
.illo-donnie-bins .bn-bin { transform-box: view-box; }
.illo-donnie-bins .bn-bin-a { transform-origin: 602px 320px; }
.illo-donnie-bins .bn-bin-b { transform-origin: 668px 320px; }
.donnie.is-loading .bn-lorry { animation: bn-round 10s ease-in-out 1; }
.donnie.is-loading .bn-bin-a { animation: bn-tip-a 10s ease-in-out 1; }
.donnie.is-loading .bn-bin-b { animation: bn-tip-b 10s ease-in-out 1; }
.donnie.is-loading .bn-bin-a .bn-bits { animation: bn-bits-a 10s linear 1; }
.donnie.is-loading .bn-bin-b .bn-bits { animation: bn-bits-b 10s linear 1; }
@keyframes bn-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-40px, -5px); } 20% { transform: translate(-80px, 0); } 30% { transform: translate(-120px, -5px); } 40% { transform: translate(-160px, 0); } 50% { transform: translate(-200px, -5px); } 60% { transform: translate(-240px, 0); } 75% { transform: translate(-380px, -90px) scale(.85); opacity: 1; } 100% { transform: translate(-445px, -110px) scale(.6); opacity: 0; } }
@keyframes bn-round { 0% { transform: translateX(0); } 14%, 42% { transform: translateX(112px); } 50%, 76% { transform: translateX(178px); } 94%, 100% { transform: translateX(0); } }
/* up, over (tipping on its top front corner), back, down */
@keyframes bn-tip-a { 0%, 16% { transform: none; } 22% { transform: translateY(-56px); } 28%, 32% { transform: translateY(-56px) rotate(-125deg); } 37% { transform: translateY(-56px); } 42%, 100% { transform: none; } }
@keyframes bn-tip-b { 0%, 52% { transform: none; } 58% { transform: translateY(-56px); } 64%, 68% { transform: translateY(-56px) rotate(-125deg); } 73% { transform: translateY(-56px); } 78%, 100% { transform: none; } }
/* the rubbish falls straight down the screen out of the upturned bin: in the bin's own turned units that is up and back */
@keyframes bn-bits-a { 0%, 28% { opacity: 0; transform: none; } 29% { opacity: 1; transform: none; } 35% { opacity: 0; transform: translate(-25px, -17px); } 100% { opacity: 0; } }
@keyframes bn-bits-b { 0%, 64% { opacity: 0; transform: none; } 65% { opacity: 1; transform: none; } 71% { opacity: 0; transform: translate(-25px, -17px); } 100% { opacity: 0; } }

/* the farm (donnie-farm.mjs): he stands at x 518; the cab door is near x 196, y 289;
   the ramp hinges at the trailer's floor, x 447, y 376 */
.illo-donnie-farm .ds-walk { transform-origin: 518px 396px; }
.donnie.is-inside .illo-donnie-farm .ds-walk, .donnie.is-leaving .illo-donnie-farm .ds-walk { animation-name: fm-walk-in; }
.donnie .fm-bull-in { opacity: 0; }
.illo-donnie-farm .fm-ramp { transform-box: view-box; transform-origin: 447px 376px; }
.donnie.is-loading .fm-rig { animation: fm-run 11s ease-in-out 1; }
.donnie.is-loading .fm-ramp { animation: fm-ramp 11s ease-in-out 1; }
.donnie.is-loading .fm-bull { animation: fm-bull 11s linear 1; }
.donnie.is-loading .fm-bull-in { animation: fm-bull-in 11s linear 1; }
@keyframes fm-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-36px, -5px); } 20% { transform: translate(-72px, 0); } 30% { transform: translate(-108px, -5px); } 40% { transform: translate(-144px, 0); } 50% { transform: translate(-180px, -5px); } 60% { transform: translate(-216px, 0); } 75% { transform: translate(-290px, -70px) scale(.85); opacity: 1; } 100% { transform: translate(-322px, -86px) scale(.6); opacity: 0; } }
/* back up to the bull, wait while he is loaded, off to the left, a moment, reverse back in */
@keyframes fm-run { 0% { transform: translateX(0); } 14%, 46% { transform: translateX(60px); } 58%, 64% { transform: translateX(-820px); } 80%, 100% { transform: translateX(0); } }
@keyframes fm-ramp { 0%, 16% { transform: rotate(0); } 22%, 39% { transform: rotate(109deg); } 45%, 100% { transform: rotate(0); } }
/* he walks up the ramp into the trailer; the moment he is in, the bull drawn inside the trailer takes over */
@keyframes fm-bull { 0%, 22% { transform: none; opacity: 1; } 26% { transform: translate(-40px, -2px); } 30% { transform: translate(-90px, -14px); } 34% { transform: translate(-150px, -20px); } 39% { transform: translate(-236px, -20px); opacity: 1; } 39.5% { opacity: 0; } 90% { transform: none; opacity: 0; } 98%, 100% { transform: none; opacity: 1; } }
@keyframes fm-bull-in { 0%, 39% { opacity: 0; } 39.5%, 58% { opacity: 1; } 59%, 100% { opacity: 0; } }

/* the mobile crane (donnie-crane.mjs): he stands at x 492 and climbs into the low cab at
   the front (near x 67, y 293). In the crane's own units: the outriggers come down 28; the
   boom turns on its pivot (380, 128), the hook's frame on the tip (80, 128), the inner
   section slides out 111.8; over the stack the boom is at 165 degrees and the hook goes
   down 197.3, over the frame at 162.85 degrees and down 61.3 (worked out in donnie-crane.mjs). */
.illo-donnie-crane .ds-walk { transform-origin: 492px 396px; }
.donnie.is-inside .illo-donnie-crane .ds-walk, .donnie.is-leaving .illo-donnie-crane .ds-walk { animation-name: cr-walk-in; }
.illo-donnie-crane .cr-boom { transform-box: view-box; transform-origin: 380px 128px; }
.illo-donnie-crane .cr-hang { transform-box: view-box; transform-origin: 80px 128px; }
.donnie .cr-load, .donnie .cr-set { opacity: 0; }
.donnie.is-loading .cr-legs { animation: cr-legs 14s ease-in-out 1; }
.donnie.is-loading .cr-boom { animation: cr-boom 14s ease-in-out 1; }
.donnie.is-loading .cr-tele { animation: cr-tele 14s ease-in-out 1; }
.donnie.is-loading .cr-hang { animation: cr-hang 14s ease-in-out 1; }
.donnie.is-loading .cr-hook { animation: cr-hook 14s ease-in-out 1; }
.donnie.is-loading .cr-load { animation: cr-load 14s linear 1; }
.donnie.is-loading .cr-top { animation: cr-top 14s linear 1; }
.donnie.is-loading .cr-set { animation: cr-set 14s linear 1; }
@keyframes cr-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-40px, -5px); } 20% { transform: translate(-80px, 0); } 30% { transform: translate(-120px, -5px); } 40% { transform: translate(-160px, 0); } 50% { transform: translate(-200px, -5px); } 60% { transform: translate(-240px, 0); } 80% { transform: translate(-380px, -40px) scale(.85); opacity: 1; } 100% { transform: translate(-425px, -62px) scale(.6); opacity: 0; } }
@keyframes cr-legs { 0% { transform: translateY(0); } 6%, 84% { transform: translateY(28px); } 90%, 100% { transform: translateY(0); } }
@keyframes cr-boom { 0%, 6% { transform: rotate(0); } 20%, 42% { transform: rotate(165deg); } 50%, 64% { transform: rotate(162.85deg); } 80%, 100% { transform: rotate(0); } }
@keyframes cr-hang { 0%, 6% { transform: rotate(0); } 20%, 42% { transform: rotate(-165deg); } 50%, 64% { transform: rotate(-162.85deg); } 80%, 100% { transform: rotate(0); } }
@keyframes cr-tele { 0%, 6% { transform: translateX(0); } 20%, 42% { transform: translateX(-111.8px); } 50%, 100% { transform: translateX(0); } }
/* down to the stack, up with the girder; down onto the frame, up empty */
@keyframes cr-hook { 0%, 20% { transform: translateY(0); } 26%, 29% { transform: translateY(197.3px); } 36%, 50% { transform: translateY(0); } 56%, 59% { transform: translateY(61.3px); } 65%, 100% { transform: translateY(0); } }
@keyframes cr-load { 0%, 27.5% { opacity: 0; } 28%, 57.5% { opacity: 1; } 58%, 100% { opacity: 0; } }
@keyframes cr-top { 0%, 27.5% { opacity: 1; } 28%, 94% { opacity: 0; } 98%, 100% { opacity: 1; } }
@keyframes cr-set { 0%, 57.5% { opacity: 0; } 58%, 92% { opacity: 1; } 96%, 100% { opacity: 0; } }

/* the chip shop (donnie-chippy.mjs): the customer's paw is at x 244; the supper is drawn at x 560-600 */
.donnie .cp-fish, .donnie .cp-bub, .donnie .cp-steam, .donnie .cp-parcel { opacity: 0; }
.illo-donnie-chippy .cp-steam { transform-box: fill-box; transform-origin: center; }
.donnie.is-loading .cp-basket { animation: cp-basket 10s ease-in-out 1; }
.donnie.is-loading .cp-fish { animation: cp-fish 10s linear 1; }
.donnie.is-loading .cp-bub { animation: cp-bub 1.2s linear .8s 3; }
.donnie.is-loading .cp-bub-2 { animation-delay: 1.2s; }
.donnie.is-loading .cp-bub-3 { animation-delay: 1.6s; }
.donnie.is-loading .cp-steam { animation: ds-puff 1.8s ease-out 1s 2; }
.donnie.is-loading .cp-steam-2 { animation-delay: 1.6s; }
.donnie.is-loading .cp-steam-3 { animation-delay: 2.2s; }
.donnie.is-loading .cp-parcel { animation: cp-parcel 10s ease-in-out 1; }
.donnie.is-loading .cp-customer { animation: dl-hop 10s ease-in-out 1; }
@keyframes cp-basket { 0% { transform: translateY(0); } 8%, 40% { transform: translateY(22px); } 48%, 100% { transform: translateY(0); } }
@keyframes cp-fish { 0%, 42% { opacity: 0; } 44%, 56% { opacity: 1; } 58%, 100% { opacity: 0; } }
@keyframes cp-bub { 0% { opacity: 0; transform: translateY(0); } 20% { opacity: 1; } 100% { opacity: 0; transform: translateY(-14px); } }
/* wrapped, along the counter, into the customer's paw, a happy hop, gone */
@keyframes cp-parcel { 0%, 54% { opacity: 0; transform: none; } 58% { opacity: 1; transform: none; } 72% { transform: translate(-230px, 0); } 78% { transform: translate(-336px, 2px); } 80% { transform: translate(-336px, 2px); } 83% { transform: translate(-336px, -8px); } 86% { transform: translate(-336px, 2px); } 89% { transform: translate(-336px, -4px); } 92% { opacity: 1; transform: translate(-336px, 2px); } 96%, 100% { opacity: 0; transform: translate(-336px, 2px); } }

/* the sales (donnie-deal.mjs - donnie-factory, donnie-tower): the handshake moves both
   front arms, each in its own capybara's units (the suit's is turned, so its arm
   mirrors Donnie's by itself); the board flips about its middle */
.donnie .dl-bag { opacity: 0; }
.donnie .dl-for, .donnie .dl-sold { transform-box: fill-box; transform-origin: center; }
.donnie .dl-sold { transform: scaleY(0); }
.donnie.is-loading .illo-donnie-factory .ds-walk .dd-arm, .donnie.is-loading .illo-donnie-tower .ds-walk .dd-arm { animation: dl-arm-d 10s ease-in-out 1; }
.donnie.is-loading .dl-suit .dd-arm { animation: dl-arm-s 10s ease-in-out 1; }
.donnie.is-loading .dl-suit { animation: dl-hop 10s ease-in-out 1; }
.donnie.is-loading .dl-for { animation: dl-for 10s ease-in-out 1; }
.donnie.is-loading .dl-sold { animation: dl-sold 10s ease-in-out 1; }
.donnie.is-loading .dl-bag { animation: dl-bag 10s ease-in-out 1; }
@keyframes dl-arm-d { 0%, 4% { transform: none; } 12% { transform: rotate(40deg) translate(-44px, 0); } 16%, 24% { transform: rotate(48deg) translate(-44px, 0); } 20%, 28% { transform: rotate(32deg) translate(-44px, 0); } 32%, 36% { transform: rotate(40deg) translate(-44px, 0); } 44%, 54% { transform: none; } 60%, 72% { transform: rotate(30deg) translate(-44px, 0); } 78%, 100% { transform: none; } }
@keyframes dl-arm-s { 0%, 4% { transform: none; } 12% { transform: rotate(40deg) translate(-44px, 0); } 16%, 24% { transform: rotate(32deg) translate(-44px, 0); } 20%, 28% { transform: rotate(48deg) translate(-44px, 0); } 32%, 36% { transform: rotate(40deg) translate(-44px, 0); } 44%, 64% { transform: none; } 70%, 88% { transform: rotate(30deg) translate(-44px, 0); } 94%, 100% { transform: none; } }
@keyframes dl-for { 0%, 44% { transform: scaleY(1); } 50%, 97% { transform: scaleY(0); } 100% { transform: scaleY(1); } }
@keyframes dl-sold { 0%, 50% { transform: scaleY(0); } 56%, 94% { transform: scaleY(1); } 97%, 100% { transform: scaleY(0); } }
@keyframes dl-hop { 0%, 80% { transform: translateY(0); } 83% { transform: translateY(-10px); } 86% { transform: translateY(0); } 89% { transform: translateY(-5px); } 92%, 100% { transform: translateY(0); } }
/* the bag appears in Donnie's paw, goes across to the other's paw, and hops with them */
@keyframes dl-bag { 0%, 58% { opacity: 0; transform: none; } 62%, 66% { opacity: 1; transform: none; } 74%, 80% { transform: translate(var(--dl-give), 0); } 83% { transform: translate(var(--dl-give), -10px); } 86% { transform: translate(var(--dl-give), 0); } 89% { transform: translate(var(--dl-give), -5px); } 92% { opacity: 1; transform: translate(var(--dl-give), 0); } 97%, 100% { opacity: 0; transform: translate(var(--dl-give), 0); } }
.donnie .dl-bag { --dl-give: -10px; }

/* the bakery (donnie-bakery.mjs): nothing to get into - a click on the oven or the sign (.ds-run)
   starts it. Donnie and his peel step forward together (.bk-push, the peel's blade from x 226 to
   the lower deck's glass); the loaf goes in (.bk-dough); he steps back; a fresh cob appears on
   the counter (.bk-fresh) and steams (.bk-steam) */
.donnie .bk-fresh, .donnie .bk-steam { opacity: 0; }
.illo-donnie-bakery .bk-steam { transform-box: fill-box; transform-origin: center; }
.donnie.is-loading .bk-push { animation: bk-bake 10s ease-in-out 1; }
.donnie.is-loading .bk-dough { animation: bk-dough 10s linear 1; }
.donnie.is-loading .bk-fresh { animation: bk-fresh 10s linear 1; }
.donnie.is-loading .bk-steam { animation: ds-puff 1.8s ease-out 6.4s 2; }
.donnie.is-loading .bk-steam-2 { animation-delay: 7s; }
.donnie.is-loading .bk-steam-3 { animation-delay: 7.6s; }
@keyframes bk-bake { 0%, 8% { transform: translateX(0); } 24%, 40% { transform: translateX(-96px); } 56%, 100% { transform: translateX(0); } }
@keyframes bk-dough { 0%, 30% { opacity: 1; } 36%, 92% { opacity: 0; } 98%, 100% { opacity: 1; } }
@keyframes bk-fresh { 0%, 60% { opacity: 0; } 64%, 94% { opacity: 1; } 98%, 100% { opacity: 0; } }

/* the helicopter (donnie-helicopter.mjs): he stands at x 716; the cockpit door is near x 470, y 340.
   The rotors turn on their hubs (the main one at 500, 282; the tail's at 668, 306 - HUB and TAIL in
   the file), seen edge-on, so they shrink and grow; the flight goes from the pad to the helideck,
   404 across and 156 up (FLY in the file), and back */
.illo-donnie-helicopter .ds-walk { transform-origin: 716px 396px; }
.donnie.is-inside .illo-donnie-helicopter .ds-walk, .donnie.is-leaving .illo-donnie-helicopter .ds-walk { animation-name: hc-walk-in; animation-duration: 2s; }
.donnie.is-inside .illo-donnie-helicopter .ds-driver { animation-delay: 1.85s; }
.illo-donnie-helicopter .hc-rotor { transform-box: view-box; transform-origin: 500px 282px; }
.illo-donnie-helicopter .hc-tail { transform-box: view-box; transform-origin: 668px 306px; }
.donnie.is-loading .hc-heli { animation: hc-flight 14s ease-in-out 1; }
.donnie.is-loading .hc-rotor { animation: hc-spin .24s linear infinite; }
.donnie.is-loading .hc-tail { animation: hc-spin-tail .2s linear infinite; }
@keyframes hc-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-40px, -5px); } 20% { transform: translate(-80px, 0); } 30% { transform: translate(-120px, -5px); } 40% { transform: translate(-160px, 0); } 50% { transform: translate(-200px, -5px); } 60% { transform: translate(-236px, 0); } 80% { transform: translate(-250px, -36px) scale(.85); opacity: 1; } 100% { transform: translate(-262px, -50px) scale(.6); opacity: 0; } }
@keyframes hc-flight { 0%, 8% { transform: translate(0, 0); } 18% { transform: translate(0, -70px); } 36% { transform: translate(-404px, -110px); } 44%, 56% { transform: translate(-404px, -156px); } 64% { transform: translate(-404px, -110px); } 82% { transform: translate(0, -70px); } 92%, 100% { transform: translate(0, 0); } }
@keyframes hc-spin { 0% { transform: scaleX(1); } 50% { transform: scaleX(.12); } 100% { transform: scaleX(1); } }
@keyframes hc-spin-tail { 0% { transform: scaleY(1); } 50% { transform: scaleY(.12); } 100% { transform: scaleY(1); } }

/* the parcel round (donnie-parcels.mjs): he stands at x 505; the cab door is near x 110, y 300;
   the parcel comes out of the back doors at x 428 and goes 252 across to the doorstep */
.illo-donnie-parcels .ds-walk { transform-origin: 505px 396px; }
.donnie.is-inside .illo-donnie-parcels .ds-walk, .donnie.is-leaving .illo-donnie-parcels .ds-walk { animation-name: pv-walk-in; animation-duration: 2s; }
.donnie.is-inside .illo-donnie-parcels .ds-driver { animation-delay: 1.85s; }
.donnie .pv-drop { opacity: 0; }
.donnie.is-loading .pv-van { animation: pv-round 10s ease-in-out 1; }
.donnie.is-loading .pv-drop { animation: pv-drop 10s ease-in-out 1; }
@keyframes pv-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-40px, -5px); } 20% { transform: translate(-80px, 0); } 30% { transform: translate(-120px, -5px); } 40% { transform: translate(-160px, 0); } 50% { transform: translate(-200px, -5px); } 60% { transform: translate(-240px, 0); } 80% { transform: translate(-340px, -40px) scale(.85); opacity: 1; } 100% { transform: translate(-385px, -60px) scale(.6); opacity: 0; } }
/* off to the left, round from the right, back to the kerb; then the parcel out and over to the step */
@keyframes pv-round { 0%, 4% { transform: translateX(0); } 20% { transform: translateX(-520px); } 20.01% { transform: translateX(800px); } 38%, 100% { transform: translateX(0); } }
@keyframes pv-drop { 0%, 42% { opacity: 0; transform: none; } 46%, 50% { opacity: 1; transform: none; } 58% { transform: translate(126px, -44px); } 66%, 94% { opacity: 1; transform: translate(252px, 0); } 98%, 100% { opacity: 0; transform: translate(252px, 0); } }

/* the forest (donnie-forestry.mjs): he stands at x 662; the cab door is near x 215, y 300.
   The tree falls on its foot (44, 396); the crane swings on its pillar (180, 232 - PIV in the
   file) by 137 degrees to put the head over the trailer, and the head turns back the same
   amount on the crane's tip (50, 288) so it hangs level; the log it holds goes out as the
   loaded log on the trailer comes in */
.illo-donnie-forestry .ds-walk { transform-origin: 662px 396px; }
.donnie.is-inside .illo-donnie-forestry .ds-walk, .donnie.is-leaving .illo-donnie-forestry .ds-walk { animation-name: fr-walk-in; animation-duration: 2s; }
.donnie.is-inside .illo-donnie-forestry .ds-driver { animation-delay: 1.85s; }
.illo-donnie-forestry .fr-tree { transform-box: view-box; transform-origin: 44px 396px; }
.illo-donnie-forestry .fr-crane { transform-box: view-box; transform-origin: 180px 232px; }
.illo-donnie-forestry .fr-head { transform-box: view-box; transform-origin: 50px 288px; }
.donnie .fr-log, .donnie .fr-loaded { opacity: 0; }
.donnie.is-loading .fr-tree { animation: fr-tree 12s ease-in 1; }
.donnie.is-loading .fr-crane { animation: fr-crane 12s ease-in-out 1; }
.donnie.is-loading .fr-head { animation: fr-head 12s ease-in-out 1; }
.donnie.is-loading .fr-log { animation: fr-log 12s linear 1; }
.donnie.is-loading .fr-loaded { animation: fr-loaded 12s linear 1; }
@keyframes fr-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-50px, -5px); } 20% { transform: translate(-100px, 0); } 30% { transform: translate(-150px, -5px); } 40% { transform: translate(-200px, 0); } 50% { transform: translate(-250px, -5px); } 60% { transform: translate(-300px, 0); } 80% { transform: translate(-400px, -40px) scale(.85); opacity: 1; } 100% { transform: translate(-445px, -60px) scale(.6); opacity: 0; } }
/* the tree goes over to the left and is gone; a tree is standing again at the end */
@keyframes fr-tree { 0%, 18% { transform: rotate(0); opacity: 1; } 34% { transform: rotate(-85deg); opacity: 1; } 40% { transform: rotate(-85deg); opacity: 0; } 94% { transform: rotate(0); opacity: 0; } 100% { transform: rotate(0); opacity: 1; } }
@keyframes fr-crane { 0%, 42% { transform: rotate(0); } 58%, 68% { transform: rotate(-137deg); } 84%, 100% { transform: rotate(0); } }
@keyframes fr-head { 0%, 42% { transform: rotate(0); } 58%, 68% { transform: rotate(137deg); } 84%, 100% { transform: rotate(0); } }
@keyframes fr-log { 0%, 36% { opacity: 0; } 40%, 66% { opacity: 1; } 68%, 100% { opacity: 0; } }
@keyframes fr-loaded { 0%, 66% { opacity: 0; } 68%, 94% { opacity: 1; } 97%, 100% { opacity: 0; } }

/* the football (donnie-football.mjs, a picture for the chat): the ball flies from his boot
   into the net and the net bulges, round and round while the picture shows; the net is pinned
   at its right post */
.illo-donnie-football .fb-net { transform-box: view-box; transform-origin: 190px 300px; animation: fb-net 5s ease-out infinite; }
.illo-donnie-football .fb-ball { animation: fb-kick 5s ease-out infinite; }
@keyframes fb-kick { 0%, 10% { transform: translate(0, 0); opacity: 1; } 26% { transform: translate(-150px, -80px); } 42% { transform: translate(-290px, -40px); opacity: 1; } 60% { transform: translate(-300px, -36px); opacity: 1; } 64% { transform: translate(-300px, -36px); opacity: 0; } 96% { transform: translate(0, 0); opacity: 0; } 100% { transform: translate(0, 0); opacity: 1; } }
@keyframes fb-net { 0%, 40% { transform: scaleX(1); } 46% { transform: scaleX(1.12); } 56%, 100% { transform: scaleX(1); } }

/* the sports car (donnie-sportscar.mjs): he stands at x 600; the driver's seat is near x 305, y 300;
   the wheels turn on their centres (150 and 400, 369) - forward is anticlockwise, facing left */
.illo-donnie-sportscar .ds-walk { transform-origin: 600px 396px; }
.donnie.is-inside .illo-donnie-sportscar .ds-walk, .donnie.is-leaving .illo-donnie-sportscar .ds-walk { animation-name: sc-walk-in; animation-duration: 2s; }
.donnie.is-inside .illo-donnie-sportscar .ds-driver { animation-delay: 1.85s; }
.illo-donnie-sportscar .sc-wheel { transform-box: view-box; }
.illo-donnie-sportscar .sc-wheel-f { transform-origin: 150px 369px; }
.illo-donnie-sportscar .sc-wheel-r { transform-origin: 400px 369px; }
.donnie.is-loading .sc-car { animation: sc-drive 8s ease-in-out 1; }
.donnie.is-loading .sc-wheel { animation: sc-spin .5s linear infinite; }
@keyframes sc-walk-in { 0% { transform: translate(0, 0); opacity: 1; } 10% { transform: translate(-40px, -5px); } 20% { transform: translate(-80px, 0); } 30% { transform: translate(-120px, -5px); } 40% { transform: translate(-160px, 0); } 50% { transform: translate(-200px, -5px); } 60% { transform: translate(-240px, 0); } 80% { transform: translate(-272px, -36px) scale(.85); opacity: 1; } 100% { transform: translate(-295px, -50px) scale(.6); opacity: 0; } }
@keyframes sc-drive { 0%, 6% { transform: translateX(0); } 40% { transform: translateX(-560px); } 40.01% { transform: translateX(800px); } 84%, 100% { transform: translateX(0); } }
@keyframes sc-spin { to { transform: rotate(-360deg); } }

@media (prefers-reduced-motion: reduce) {
  .donnie .bk-push, .donnie .bk-dough, .donnie .bk-fresh, .donnie .bk-steam, .donnie .hc-heli, .donnie .hc-rotor, .donnie .hc-tail, .donnie .pv-van, .donnie .pv-drop, .donnie .sc-car, .donnie .sc-wheel, .donnie .fr-tree, .donnie .fr-crane, .donnie .fr-head, .donnie .fr-log, .donnie .fr-loaded { animation: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .donnie .cr-legs, .donnie .cr-boom, .donnie .cr-tele, .donnie .cr-hang, .donnie .cr-hook, .donnie .cr-load, .donnie .cr-top, .donnie .cr-set, .donnie .cp-basket, .donnie .cp-fish, .donnie .cp-bub, .donnie .cp-steam, .donnie .cp-parcel, .donnie .cp-customer, .donnie .dl-suit, .donnie .dl-for, .donnie .dl-sold, .donnie .dl-bag { animation: none !important; }
  .donnie .ds-go, .donnie .tx-car, .donnie .tx-friend, .donnie .tx-pass, .donnie .bn-lorry, .donnie .bn-bin, .donnie .bn-bits, .donnie .fm-rig, .donnie .fm-ramp, .donnie .fm-bull, .donnie .fm-bull-in { animation: none !important; }
  .donnie .dd-all, .donnie .dd-arm, .donnie .dd-head, .donnie .dd-eyes, .donnie .ds-puff, .donnie .ex-arm, .donnie .ex-bucket, .donnie .ds-walk, .donnie .ds-driver, .donnie .ds-dumper, .donnie .ex-house, .donnie .ex-dipper, .donnie .dm-load, .donnie .ex-dirt, .donnie .ex-logo { animation: none !important; }
  .donnie .ds-puff { opacity: 0; }
}

/* TALKING (register S374, donnie-talk.svg): his mouth is its own part, .dd-mouth, pinned under the smile line. Shut,
   it is a sliver; the introduction (assets/donnie-intro.js) puts .m1 (half open, a consonant) or .m2 (open, a vowel)
   on .donnie in time with the voice, letter by letter. Under reduced motion it stays shut and the words carry it. */
.donnie .dd-mouth { transform-box: view-box; transform-origin: 101px 140px; transform: scaleY(.12); transition: transform 70ms linear; }
.donnie.m1 .dd-mouth { transform: scaleY(.55); }
.donnie.m2 .dd-mouth { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .donnie .dd-mouth, .donnie.m1 .dd-mouth, .donnie.m2 .dd-mouth { transform: scaleY(.12); transition: none; }
}
