/* opnF.sh terminal mascot. Every rule is scoped to .opnf-m, every animation named opnfm-*. */
.opnf-m{overflow:visible}
/* ── Mascot rig ───────────────────────────────────────────── */
.opnf-m .v{display:none}
.opnf-m[data-eyes="rect"] .e-rect,.opnf-m[data-eyes="wide"] .e-wide,.opnf-m[data-eyes="txt"] .e-txt,
.opnf-m[data-mouth="prompt"] .m-prompt,.opnf-m[data-mouth="txt"] .m-txt{display:inline}
.opnf-m text{font-family:"DM Mono", ui-monospace, SFMono-Regular, Menlo, monospace;font-weight:500}
/* Character faces are drawn as strokes, same weight and round caps as the >_ prompt. */
.opnf-m .glyph{fill:none;stroke:#e8e8e8;stroke-width:4.5;stroke-linecap:round;stroke-linejoin:round}
.opnf-m .mouth{fill:none;stroke:var(--opnf-m-accent,#ff6b1a);stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round}
.opnf-m.orange-eyes .glyph{stroke:var(--opnf-m-accent,#ff6b1a)}
.opnf-m .fxs{fill:none;stroke-linecap:round;stroke-linejoin:round}

.opnf-m .rig,.opnf-m .bob,.opnf-m .body,.opnf-m .shadow{transform-box:fill-box;transform-origin:50% 100%}
.opnf-m .shadow{transform-origin:50% 50%}
.opnf-m .face{transform-box:view-box;transform-origin:48px 46px}
.opnf-m .arm{transform-box:fill-box;transition:transform .22s ease}
.opnf-m .arm-l{transform-origin:100% 0}
.opnf-m .arm-r{transform-origin:0 0}
.opnf-m .look{transition:transform .12s ease-out}
.opnf-m .blink{transform-box:fill-box;transform-origin:50% 50%;animation:opnfm-blink 5s infinite}
.opnf-m .cur{animation:opnfm-cur 1s steps(1) infinite}
.opnf-m .rig{transform:rotate(var(--lean,0deg));transition:transform .3s ease}
.opnf-m .bob{animation:opnfm-bob 3.2s ease-in-out infinite}
.opnf-m .dim,.opnf-m .flash,.opnf-m .scan{opacity:0}
.opnf-m .fx > g{opacity:0}
.opnf-m .fx text,.opnf-m .fx path{transform-box:fill-box;transform-origin:50% 50%}
.opnf-m .say{font-size:15px;fill:var(--opnf-m-accent,#ff6b1a);white-space:pre}

@keyframes opnfm-bob{50%{transform:translateY(-3px)}}
@keyframes opnfm-blink{0%,46%,50%,100%{transform:scaleY(1)}48%{transform:scaleY(.1)}}
@keyframes opnfm-cur{50%{opacity:0}}
@keyframes opnfm-spin{to{transform:rotate(360deg)}}
/* Terminal effects: a glitchy jump, a scanline sweep, a CRT switching on and off. */
@keyframes opnfm-glitch{0%{transform:none}20%{transform:translate(-3px,0) skewX(10deg)}40%{transform:translate(2px,1px)}60%{transform:translate(-1px,-1px) skewX(-8deg)}80%{transform:translate(2px,0)}100%{transform:none}}
@keyframes opnfm-scan{0%{opacity:.5;transform:translateY(0)}100%{opacity:.5;transform:translateY(56px)}}
@keyframes opnfm-crtOn{0%{transform:scale(.2,.03)}35%{transform:scale(1.05,.06)}70%{transform:scale(1,1.06)}100%{transform:none}}
@keyframes opnfm-crtOff{0%{transform:none}30%{transform:scale(1.05,.05)}45%{transform:scale(.05,.04)}55%{transform:scale(.05,.04)}100%{transform:none}}
@keyframes opnfm-flash{0%{opacity:.55}100%{opacity:0}}
.opnf-m .scan{transform-box:view-box}

/* Giggle: the doughboy poke. Squash, stretch, a few little shakes, arms flapping. */
@keyframes opnfm-squish{0%{transform:scale(1)}12%{transform:scale(1.14,.82)}28%{transform:scale(.9,1.12)}44%{transform:scale(1.07,.94)}60%{transform:scale(.97,1.04)}76%{transform:scale(1.02,.98)}100%{transform:scale(1)}}
@keyframes opnfm-jitter{0%,100%{transform:rotate(0)}25%{transform:rotate(-4deg)}75%{transform:rotate(4deg)}}
@keyframes opnfm-flapL{to{transform:rotate(30deg)}}
@keyframes opnfm-flapR{to{transform:rotate(-30deg)}}
.opnf-m.a-giggle .body{animation:opnfm-squish .9s cubic-bezier(.3,.7,.4,1)}
.opnf-m.a-giggle .rig{animation:opnfm-jitter .22s .45s 4}
.opnf-m.a-giggle .arm-l{animation:opnfm-flapL .18s .3s 6 alternate}
.opnf-m.a-giggle .arm-r{animation:opnfm-flapR .18s .3s 6 alternate}

/* Dizzy: wobble, spinning @ eyes, glitching screen, asterisks circling. */
@keyframes opnfm-wobble{0%,100%{transform:rotate(0)}25%{transform:rotate(-9deg)}75%{transform:rotate(9deg)}}
.opnf-m.a-dizzy .rig{animation:opnfm-wobble 1.1s ease-in-out infinite}
.opnf-m.a-dizzy .face{animation:opnfm-glitch .28s steps(1) 3}
.opnf-m.a-dizzy .glyph{stroke-width:3.5;transform-box:fill-box;transform-origin:50% 50%;animation:opnfm-spin .8s linear infinite}
.opnf-m[data-fx="orbit"] .fx-orbit{opacity:1}
.opnf-m .fx-orbit .orb{animation:opnfm-spin 1.5s linear infinite}

/* Huff: >_< with a shake and a glitch. */
@keyframes opnfm-shake{from{transform:translateX(-2px)}to{transform:translateX(2px)}}
.opnf-m.a-grumpy .rig{animation:opnfm-shake .07s linear 10 alternate}
.opnf-m.a-grumpy .face{animation:opnfm-glitch .3s steps(1) 2}
.opnf-m.a-grumpy .arm-l{transform:rotate(20deg)}
.opnf-m.a-grumpy .arm-r{transform:rotate(-20deg)}

/* Startled: the screen snaps on like an old CRT. */
@keyframes opnfm-hop{0%{transform:none}30%{transform:translateY(-10px) scale(.94,1.1)}60%{transform:translateY(0) scale(1.06,.95)}100%{transform:none}}
.opnf-m.a-startle .rig{animation:opnfm-hop .5s ease-out}
.opnf-m.a-startle .face{animation:opnfm-crtOn .45s ease-out}
.opnf-m.a-startle .flash{animation:opnfm-flash .5s ease-out}
.opnf-m.a-startle .scan{animation:opnfm-scan .5s linear}
.opnf-m.a-startle .arm-l{transform:rotate(100deg)}
.opnf-m.a-startle .arm-r{transform:rotate(-100deg)}
.opnf-m[data-fx="bang"] .fx-bang{opacity:1}

.opnf-m .fx-bang path{animation:opnfm-cur .25s steps(1) 3}

/* Sleepy: the screen powers down, then dims. */
@keyframes opnfm-breathe{50%{transform:translateY(1px) scale(1.025,.975)}}
@keyframes opnfm-zz{0%{opacity:0;transform:translate(0,4px)}30%{opacity:1}100%{opacity:0;transform:translate(6px,-12px)}}
.opnf-m.a-sleepy .bob{animation:opnfm-breathe 3.6s ease-in-out infinite}
.opnf-m.a-sleepy .rig{transform:rotate(-4deg)}
.opnf-m.a-sleepy .face{animation:opnfm-crtOff .9s ease-in-out}
.opnf-m.a-sleepy .dim{opacity:.45;transition:opacity .6s .6s}
.opnf-m[data-fx="zzz"] .fx-zzz{opacity:1}
.opnf-m .fx-zzz path{animation:opnfm-zz 2.4s ease-out infinite;opacity:0}
.opnf-m .fx-zzz path:nth-child(2){animation-delay:.8s}
.opnf-m .fx-zzz path:nth-child(3){animation-delay:1.6s}

/* Wave hello. Raised arms swap to an "up" drawing and pivot at the shoulder. */
.opnf-m .arm .up{display:none}
.opnf-m.a-wave .arm-r .up,.opnf-m.a-think .arm-r .up,.opnf-m.a-celebrate .arm .up{display:inline}
.opnf-m.a-wave .arm-r .dn,.opnf-m.a-think .arm-r .dn,.opnf-m.a-celebrate .arm .dn{display:none}
.opnf-m.a-wave .arm-r,.opnf-m.a-think .arm-r,.opnf-m.a-celebrate .arm-r{transform-origin:0 100%}
.opnf-m.a-celebrate .arm-l{transform-origin:100% 100%}
@keyframes opnfm-wave{from{transform:rotate(-12deg)}to{transform:rotate(22deg)}}
.opnf-m.a-wave .arm-r{animation:opnfm-wave .38s ease-in-out infinite alternate}

/* Thinking: scratches his head while a spinner turns. */
@keyframes opnfm-scratch{from{transform:rotate(-4deg)}to{transform:rotate(-14deg)}}
.opnf-m.a-think .arm-r{animation:opnfm-scratch .3s ease-in-out infinite alternate}
.opnf-m.a-think .rig{transform:rotate(-4deg)}

/* Celebrate: jumps for joy, asterisks twinkle around him. */
@keyframes opnfm-jump{0%{transform:none}18%{transform:translateY(3px) scale(1.1,.88)}45%{transform:translateY(-18px) scale(.95,1.06)}70%{transform:translateY(0) scale(1.08,.92)}85%{transform:scale(.98,1.02)}100%{transform:none}}
@keyframes opnfm-shadowJ{0%,100%{transform:scale(1);opacity:1}45%{transform:scale(.6);opacity:.5}}
@keyframes opnfm-armsUpL{from{transform:rotate(-8deg)}to{transform:rotate(10deg)}}
@keyframes opnfm-armsUpR{from{transform:rotate(8deg)}to{transform:rotate(-10deg)}}
@keyframes opnfm-twinkle{0%,100%{opacity:0;transform:scale(.4)}50%{opacity:1;transform:scale(1)}}
.opnf-m.a-celebrate .rig{animation:opnfm-jump .8s ease-in-out 2}
.opnf-m.a-celebrate .shadow{animation:opnfm-shadowJ .8s ease-in-out 2}
.opnf-m.a-celebrate .arm-l{animation:opnfm-armsUpL .2s ease-in-out infinite alternate}
.opnf-m.a-celebrate .arm-r{animation:opnfm-armsUpR .2s ease-in-out infinite alternate}
.opnf-m[data-fx="spark"] .fx-spark{opacity:1}
.opnf-m .fx-spark path{animation:opnfm-twinkle 1.1s ease-in-out infinite;opacity:0}
.opnf-m .fx-spark path:nth-child(2){animation-delay:.3s}
.opnf-m .fx-spark path:nth-child(3){animation-delay:.6s}
.opnf-m .fx-spark path:nth-child(4){animation-delay:.85s}

/* Wrong answer: flinches, the screen glitches red, he types "oops". */
.opnf-m.red-face .glyph,.opnf-m.red-face .mouth{stroke:#ef4444}
.opnf-m.red-face .say{fill:#ef4444}
/* Right answer: a happy green ^ ^ and a little hop. */
.opnf-m.green-face .glyph,.opnf-m.green-face .mouth{stroke:#5ac46a}
.opnf-m.green-face .say{fill:#5ac46a}
.opnf-m.a-correct .rig{animation:opnfm-hop .5s ease-out}
.opnf-m.a-correct .arm-l{transform:rotate(40deg)}
.opnf-m.a-correct .arm-r{transform:rotate(-40deg)}
.opnf-m .rflash{opacity:0}
@keyframes opnfm-flinch{0%{transform:none}15%{transform:translate(-5px,0) rotate(-6deg)}30%{transform:translate(4px,0) rotate(4deg)}45%{transform:translate(-2px,0)}60%,100%{transform:none}}
.opnf-m.a-wrong .rig{animation:opnfm-flinch .6s ease-out}
.opnf-m.a-wrong .face{animation:opnfm-glitch .25s steps(1) 2}
.opnf-m.a-wrong .rflash{animation:opnfm-flash .45s ease-out}
.opnf-m.a-wrong .arm-l{transform:rotate(-14deg)}
.opnf-m.a-wrong .arm-r{transform:rotate(14deg)}

/* Failed round: crashes. Glitches, slumps, the screen dies, smoke curls up. Then he reboots. */
@keyframes opnfm-crtDie{0%{transform:none;opacity:1}40%{transform:scale(1.05,.05)}70%{transform:scale(.05,.04);opacity:1}100%{transform:scale(.05,.04);opacity:0}}
@keyframes opnfm-slump{to{transform:translateY(5px) rotate(-9deg)}}
@keyframes opnfm-sag{to{transform:scale(1.04,.93)}}
@keyframes opnfm-smoke{0%{opacity:0;transform:translateY(6px) scale(.6)}30%{opacity:.8}100%{opacity:0;transform:translateY(-16px) scale(1.2)}}
.opnf-m.a-fail .face{animation:opnfm-glitch .2s steps(1) 4,opnfm-crtDie .6s 1.2s ease-in forwards}
.opnf-m.a-fail .rflash{animation:opnfm-flash .5s ease-out}
.opnf-m.a-fail .rig{animation:opnfm-slump .7s .5s ease-in forwards}
.opnf-m.a-fail .body{animation:opnfm-sag .7s .5s ease-in forwards}
.opnf-m.a-fail .arm{transition-delay:.5s}
.opnf-m.a-fail .arm-l{transform:rotate(-28deg)}
.opnf-m.a-fail .arm-r{transform:rotate(28deg)}
.opnf-m.a-fail .dim{opacity:.6;transition:opacity .4s 1.6s}
.opnf-m[data-fx="smoke"] .fx-smoke{opacity:1}
.opnf-m .fx-smoke path{opacity:0;animation:opnfm-smoke 1.6s 1.3s ease-out infinite}
.opnf-m .fx-smoke path:nth-child(2){animation-delay:1.8s}
.opnf-m.a-reboot .face{animation:opnfm-crtOn .5s ease-out}
.opnf-m.a-reboot .flash{animation:opnfm-flash .5s ease-out}
.opnf-m.a-reboot .scan{animation:opnfm-scan .5s linear}

@media (prefers-reduced-motion:reduce){
  .opnf-m *,.opnf-m{animation:none!important;transition:none!important}
  .opnf-m .fx-zzz path,.opnf-m .fx-spark path{opacity:1}
}