/* ────────────────────────────────────────────────────────────────────────────
   Homepage icons: little hover animations (like the laptop's lid).
   Each icon PNG gets two effect layers from index.html:
     .ifx       painted above the icon (notes, hearts, flash…)
     .ifx-back  painted behind it, so things can rise "out of" the icon
                (papers from the folder, a map from the backpack, a photo
                from the camera)
   Effects run while script.js puts .hover on the button, or while
   icon-hover-fx.js puts .fx-on on it (touch screens, when on screen).
   Positions use the icon's own drawing coordinates (320 × 180, same as
   icon-outlines.js): --x / --y. Sizes use the icon box (cqw / cqh).
   ──────────────────────────────────────────────────────────────────────── */
.has-fx>img{position:relative;z-index:1}
.ifx,.ifx-back{position:absolute;inset:0;pointer-events:none;container-type:size;z-index:2;transition:transform .4s var(--spring),filter .3s ease}
.ifx-back{z-index:0}
.icon-btn.hover>:is(.ifx,.ifx-back){transform:translateY(-7px) scale(1.1)}
.icon-btn.active>:is(.ifx,.ifx-back){transform:translateY(-4px) scale(1.04)}
.icon-btn.is-lifted>:is(.ifx,.ifx-back){visibility:hidden}
.ifx>*,.ifx-back>*{position:absolute;display:block;left:calc(var(--x,160) * 100% / 320);top:calc(21.875% + var(--y,90) * 56.25% / 180);translate:-50% -50%;font-style:normal}
.ifx>*{opacity:0}

/* Shapes drawn with masks so they take any colour */
.fx-note,.fx-heart,.fx-spark,.fx-flower{width:var(--w,14cqw);aspect-ratio:1;background:var(--c,#b95f74);-webkit-mask:var(--m) center/contain no-repeat;mask:var(--m) center/contain no-repeat}
.fx-note{--m:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11 2h2.2c.3 2.6 4.8 3.4 4.8 7.6-1-1.8-2.9-2.6-4.8-2.7v8.6a3.3 2.8 0 1 1-2.2-2.6z'/%3E%3C/svg%3E")}
.fx-note.two{--m:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8.5 5.3 19.5 2v12.6a3.1 2.7 0 1 1-2-2.5V6.4l-7 2.1v8.4a3.1 2.7 0 1 1-2-2.5z'/%3E%3C/svg%3E")}
.fx-heart{--m:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 21s-7.5-4.6-9.6-9.2C.9 8.4 3 4.5 6.8 4.5c2.2 0 3.7 1.3 4.2 2.4.5-1.1 2-2.4 4.2-2.4 3.8 0 5.9 3.9 4.4 7.3C19.5 16.4 12 21 12 21z'/%3E%3C/svg%3E")}
.fx-spark{--m:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1c.7 5.6 4.4 9.3 10 10-5.6.7-9.3 4.4-10 10-.7-5.6-4.4-9.3-10-10 5.6-.7 9.3-4.4 10-10z'/%3E%3C/svg%3E")}
.fx-flower{--m:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2a4 4 0 0 1 3.5 6 4 4 0 1 1 1.2 6.7A4 4 0 1 1 7.3 14.7 4 4 0 1 1 8.5 8 4 4 0 0 1 12 2zm0 8a2 2 0 1 0 0 4 2 2 0 0 0 0-4z'/%3E%3C/svg%3E")}

/* Shared motion */
@keyframes fxRise{
  0%{opacity:0;transform:translate(0,0) scale(.5) rotate(-12deg)}
  15%,65%{opacity:1}
  100%{opacity:0;transform:translate(var(--dx,8cqw),var(--dy,-34cqh)) scale(1) rotate(var(--r,16deg))}
}
@keyframes fxPing{0%{opacity:0;transform:scale(.3)}25%{opacity:1}100%{opacity:0;transform:scale(1.5)}}
.has-fx:is(.hover,.fx-on) .ifx>:is(.fx-note,.fx-heart,.fx-spark,.fx-flower){animation:fxRise var(--t,2.4s) ease-out var(--d,0s) infinite}

/* ── dance: the ballerina twirls and the box plays ── */
.ifx>.fx-dance{inset:0;left:0;top:0;translate:none;perspective:600px}
.fx-dance>span{position:absolute;inset:0;background-position:center;background-size:contain;background-repeat:no-repeat}
.fx-box{background-image:url("assets/clickable icons/dance-parts/music-box.png")}
.fx-ballerina{background-image:url("assets/clickable icons/dance-parts/ballerina.png");transform-origin:52.3% 50%}
@keyframes fxTwirl{from{transform:rotateY(0)}to{transform:rotateY(360deg)}}
.has-fx.fx-dance-host:is(.hover,.fx-on)>img{opacity:0}
.fx-dance-host:is(.hover,.fx-on) .fx-dance{opacity:1}
.fx-dance-host:is(.hover,.fx-on) .fx-ballerina{animation:fxTwirl 2.2s linear infinite}
.fx-dance-host.hover>.ifx{filter:drop-shadow(0 18px 32px rgba(17,17,17,.18))}

/* ── spotify: the iPod bops, sound ripples out of the earbuds ── */
@keyframes fxBop{0%,100%{rotate:0deg}25%{rotate:-5deg}75%{rotate:5deg}}
.has-fx[data-key="spotify.png"]:is(.hover,.fx-on)>img{animation:fxBop .9s ease-in-out infinite}
.fx-wave{width:14cqw;aspect-ratio:1;border-radius:50%;border:.9cqw solid transparent;border-right-color:#e0708a;rotate:var(--rot,0deg)}
.has-fx:is(.hover,.fx-on) .fx-wave{animation:fxPing 1.2s ease-out var(--d,0s) infinite}

/* ── socials: heartbeat and floating hearts ── */
@keyframes fxBeat{0%,50%,100%{scale:1}12%{scale:1.08}24%{scale:1}36%{scale:1.05}}
.has-fx[data-key="socials.png"]:is(.hover,.fx-on)>img{animation:fxBeat 1.3s ease-in-out infinite}

/* ── more about me (camera art): shutter snap, flash, and a photo pops out the top ── */
@keyframes fxSnap{0%,14%,100%{scale:1}4%{scale:1.05 .93}}
@keyframes fxFlash{0%{opacity:0;transform:scale(.2)}6%{opacity:1;transform:scale(1)}30%,100%{opacity:0;transform:scale(1.35)}}
.has-fx[data-key="more about my life.png"]:is(.hover,.fx-on)>img{animation:fxSnap 1.8s ease-out infinite}
.fx-flash{width:46cqw;aspect-ratio:1;background:radial-gradient(circle,#fff 0 10%,rgba(255,246,205,.9) 22%,rgba(255,246,205,0) 62%)}
.fx-flash .fx-spark{position:absolute;inset:22%;width:auto;height:auto;--c:#fff}
.has-fx:is(.hover,.fx-on) .fx-flash{animation:fxFlash 1.8s ease-out infinite}
.fx-print{width:22cqw;aspect-ratio:.82;padding:1.6cqw 1.6cqw 5cqw;box-sizing:border-box;border-radius:1cqw;background:#fffdf7;box-shadow:0 .6cqw 1.6cqw rgba(58,36,23,.25);rotate:4deg;transition:transform .8s cubic-bezier(.3,1.3,.5,1)}
.fx-print::before{content:'';display:block;height:100%;border-radius:.5cqw;background:radial-gradient(circle at 70% 30%,#f7d774 0 9%,transparent 10%),radial-gradient(ellipse at 30% 115%,#7fb08a 0 45%,transparent 46%),linear-gradient(#bfe0e6,#f6d7d9)}
.has-fx:is(.hover,.fx-on) .fx-print{transform:translateY(-22cqh);transition-delay:.25s}

/* ── my projects: papers rise out of the folder ── */
.fx-paper{width:28cqw;aspect-ratio:.78;border-radius:1.2cqw;background:#fffdf7 repeating-linear-gradient(#0000 0 4cqw,#e4ddd4 4cqw 4.6cqw) 0 7cqw/100% calc(100% - 11cqw) no-repeat;box-shadow:0 .6cqw 1.6cqw rgba(58,36,23,.2);transition:transform .7s cubic-bezier(.3,1.35,.5,1)}
.fx-paper.chart{background:#fffdf7 linear-gradient(#8fb3d9,#8fb3d9) 22% 80%/12% 30% no-repeat;background-image:linear-gradient(#8fb3d9,#8fb3d9),linear-gradient(#f2a7b4,#f2a7b4),linear-gradient(#f4d35e,#f4d35e);background-position:22% 82%,50% 82%,78% 82%;background-size:14% 30%,14% 55%,14% 42%;background-repeat:no-repeat}
.fx-paper.note::after{content:'';position:absolute;right:12%;top:10%;width:34%;aspect-ratio:1;background:#f9e7a3;rotate:8deg;box-shadow:0 .3cqw .8cqw rgba(0,0,0,.12)}
.has-fx:is(.hover,.fx-on) .fx-paper{transform:translate(var(--dx),-21cqh) rotate(var(--r));transition-delay:var(--d)}

/* ── side quests: the backpack bounces, a map and compass peek out,
      a paper plane takes off ── */
@keyframes fxHop{0%,100%{translate:0 0;rotate:0deg}25%{translate:0 -5%;rotate:-5deg}50%{translate:0 0;rotate:0deg}75%{translate:0 -3%;rotate:4deg}}
.has-fx[data-key="side quests.png"]:is(.hover,.fx-on)>img{animation:fxHop 1.1s ease-in-out infinite}
.fx-map{width:17cqw;aspect-ratio:1.15;border-radius:.6cqw;rotate:-14deg;background:linear-gradient(90deg,#f6e7c1 33%,#e8d39e 33% 66%,#f6e7c1 66%);box-shadow:0 .5cqw 1.2cqw rgba(58,36,23,.2);transition:transform .7s cubic-bezier(.3,1.35,.5,1)}
.fx-map::after{content:'';position:absolute;inset:18% 14%;border:.7cqw dashed #e0708a;border-color:#e0708a transparent transparent #e0708a;border-radius:60% 0 0 0}
.fx-compass{width:13cqw;aspect-ratio:1;border-radius:50%;background:#fffdf7;border:1.3cqw solid #c79a3a;box-sizing:border-box;box-shadow:0 .5cqw 1.2cqw rgba(58,36,23,.2);transition:transform .7s cubic-bezier(.3,1.35,.5,1)}
.fx-compass::before{content:'';position:absolute;left:50%;top:14%;bottom:14%;width:22%;margin-left:-11%;background:linear-gradient(#ef6f6c 50%,#8a8f98 50%);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
@keyframes fxSpin{0%{rotate:-40deg}50%{rotate:50deg}100%{rotate:-40deg}}
.has-fx:is(.hover,.fx-on) .fx-compass::before{animation:fxSpin 1.6s ease-in-out infinite}
.has-fx:is(.hover,.fx-on) .fx-map{transform:translate(-4cqw,-22cqh);transition-delay:.1s}
.has-fx:is(.hover,.fx-on) .fx-compass{transform:translate(3cqw,-20cqh);transition-delay:.25s}
.fx-plane{width:19cqw;aspect-ratio:1}
.fx-plane svg{display:block;width:100%;height:100%;overflow:visible}
@keyframes fxFly{
  0%{opacity:0;transform:translate(0,0) rotate(-6deg) scale(.5)}
  15%{opacity:1}
  55%{transform:translate(22cqw,-22cqh) rotate(-18deg) scale(.95)}
  80%{opacity:1}
  100%{opacity:0;transform:translate(40cqw,-26cqh) rotate(6deg) scale(1)}
}
.has-fx:is(.hover,.fx-on) .fx-plane{animation:fxFly 2.6s ease-in-out .3s infinite}

/* ── favourites: the TV flips through channels (books, podcasts,
      youtube, shows), the antennas pick up signal, the mug steams ── */
.fx-screen{width:22.2cqw;height:18.1cqh;border-radius:2.7cqw;overflow:hidden;background:#7fb6b3}
.fx-ch{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.4cqw;opacity:0;background:var(--bg)}
.fx-ch:nth-child(1){--bg:#7fb6b3}
.fx-ch:nth-child(2){--bg:#e58fa0}
.fx-ch:nth-child(3){--bg:#fbf1e3}
.fx-ch:nth-child(4){--bg:#4f5d80}
.fx-ch svg{width:48%;height:auto;display:block}
.fx-ch small{font:700 3.6cqw/1 'Caveat',cursive;color:#fffaf1}
.fx-ch:nth-child(3) small{color:#8a5a3b}
.fx-static{position:absolute;inset:-20%;opacity:0;background:repeating-linear-gradient(0deg,rgba(255,255,255,.55) 0 .5cqw,rgba(90,70,60,.35) .5cqw 1cqw,rgba(255,255,255,.2) 1cqw 1.6cqw),#b9aaa0}
/* The set is OFF until you hover it. .fx-off is the only effect layer that
   starts visible: it covers the teal picture baked into the PNG with dark
   glass. On hover it lifts, .fx-crt plays a CRT power-on snap, and the
   standby LED goes red -> green. */
.ifx>.fx-off{opacity:1}
.fx-off{width:22.2cqw;height:18.1cqh;border-radius:2.7cqw;overflow:hidden;background:linear-gradient(152deg,#544b45 0%,#322c28 48%,#443c37 100%);box-shadow:inset 0 0 1.4cqw rgba(0,0,0,.55);transition:opacity .26s ease .06s}
.fx-off::before{content:'';position:absolute;left:-34%;top:-70%;width:64%;height:240%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.13) 45%,transparent);rotate:20deg}
.has-fx:is(.hover,.fx-on) .ifx>.fx-off{opacity:0;transition-delay:0s}
.fx-crt{z-index:2;width:22.2cqw;height:18.1cqh;border-radius:2.7cqw;background:linear-gradient(#fffdf6,#e8f3f1);opacity:0}
@keyframes fxCrt{0%{opacity:0;transform:scale(1,.035)}8%{opacity:1;transform:scale(1,.035)}42%{opacity:.95;transform:scale(1,1)}100%{opacity:0;transform:scale(1,1)}}
.has-fx:is(.hover,.fx-on) .fx-crt{animation:fxCrt .44s ease-out}
.fx-led{width:2.1cqw;aspect-ratio:1;border-radius:50%;background:#c4554d;box-shadow:0 0 .8cqw rgba(196,85,77,.7);opacity:1;transition:background .2s ease,box-shadow .2s ease}
.ifx>.fx-led{opacity:1}
.has-fx:is(.hover,.fx-on) .fx-led{background:#7fc47a;box-shadow:0 0 1.4cqw rgba(127,196,122,.9)}
@keyframes fxCh{0%,24%{opacity:1}25%,100%{opacity:0}}
@keyframes fxStatic{0%,7%{opacity:1;transform:translateY(0)}3%{transform:translateY(6%)}9%,100%{opacity:0}}
.has-fx:is(.hover,.fx-on) .fx-ch{animation:fxCh 5.6s steps(1,end) calc(var(--i) * 1.4s) infinite}
.has-fx:is(.hover,.fx-on) .fx-screen{opacity:1}
.has-fx:is(.hover,.fx-on) .fx-static{animation:fxStatic 1.4s linear infinite}
.fx-steam{width:3cqw;height:9cqw}
.fx-steam svg{display:block;width:100%;height:100%}
@keyframes fxSteam{0%{opacity:0;transform:translateY(0) scaleX(.6)}30%{opacity:.9}100%{opacity:0;transform:translateY(-10cqh) scaleX(1.2)}}
.has-fx:is(.hover,.fx-on) .fx-steam{animation:fxSteam 2.1s ease-out var(--d,0s) infinite}

/* ── swap icons: on hover the PNG is hidden and rebuilt from full-frame
      part PNGs (.fx-part), so pieces can move ── */
.ifx>.fx-parts{inset:0;left:0;top:0;translate:none;opacity:0}
.fx-part{position:absolute;inset:0;background:var(--img) center/contain no-repeat}
.has-fx.fx-swap-host:is(.hover,.fx-on)>img{opacity:0}
.fx-swap-host:is(.hover,.fx-on) .fx-parts{opacity:1}
.fx-swap-host.hover>.ifx{filter:drop-shadow(0 18px 32px rgba(17,17,17,.18))}
@keyframes fxSwing{0%,100%{transform:rotate(0)}30%{transform:rotate(var(--a,5deg))}65%{transform:rotate(calc(var(--a,5deg) * -.6))}}
@keyframes fxFlutter{0%,100%{transform:rotate(0) skewX(0)}40%{transform:rotate(4deg) skewX(-3deg)}70%{transform:rotate(-2deg) skewX(2deg)}}
.fx-swap-host:is(.hover,.fx-on) .fx-swing{animation:fxSwing 1.9s ease-in-out var(--d,0s) infinite}
.fx-swap-host:is(.hover,.fx-on) .fx-flutter{animation:fxFlutter 1.3s ease-in-out infinite}
.fx-glow{width:7cqw;aspect-ratio:1;border-radius:50%;background:radial-gradient(circle,#fff 0 12%,var(--c) 30%,transparent 70%);mix-blend-mode:screen}
@keyframes fxTwinkle{0%,100%{opacity:.15}50%{opacity:1}}
.has-fx:is(.hover,.fx-on) .fx-glow{animation:fxTwinkle 1.1s ease-in-out var(--d,0s) infinite}

/* ── videos: the film reel spins and the strip feeds out ── */
.fx-reel{transform-origin:42.56% 44.5%}
@keyframes fxReel{to{transform:rotate(360deg)}}
@keyframes fxFeed{0%,100%{translate:0 0}50%{translate:2.2cqw 1cqw}}
.fx-film-host:is(.hover,.fx-on) .fx-reel{animation:fxReel 1.6s linear infinite}
.fx-film-host:is(.hover,.fx-on) .fx-strip{animation:fxFeed .8s ease-in-out infinite}

/* ── scrapbook: the book wiggles, stickers pop off the cover and a
      photo slides up out of the pages ── */
@keyframes fxWiggle{0%,100%{rotate:0deg}20%{rotate:-4deg}40%{rotate:3deg}60%{rotate:-2deg}80%{rotate:1deg}}
.has-fx[data-key="scrapbook.png"]:is(.hover,.fx-on)>img{animation:fxWiggle 1.1s ease-in-out}
.fx-snap{width:18cqw;aspect-ratio:.86;padding:1.3cqw 1.3cqw 4cqw;box-sizing:border-box;border-radius:.8cqw;background:#fffdf7;box-shadow:0 .6cqw 1.6cqw rgba(58,36,23,.25);rotate:-10deg;transition:transform .8s cubic-bezier(.3,1.3,.5,1)}
.fx-snap::before{content:'';display:block;height:100%;border-radius:.4cqw;background:radial-gradient(circle at 30% 35%,#fff3b0 0 10%,transparent 11%),linear-gradient(160deg,#f6c9cf,#f2a7b4 55%,#e58fa0)}
.has-fx:is(.hover,.fx-on) .fx-snap{transform:translate(-3cqw,-17cqh) rotate(-6deg);transition-delay:.15s}

@media (prefers-reduced-motion:reduce){
  .ifx,.ifx-back{display:none}
  .has-fx>img{animation:none!important;opacity:1!important}
}
