/* Material weapons, bounded particle bursts and a shared anticipation/contact/recovery timeline. */
.combat-scene[data-combat-animation]{--fx-time:900ms;--fx-color:#c5edff;--fx-lift:14px;--fx-hit-angle:8deg}
.combat-scene[data-fx-speed=fast]{--fx-time:450ms}
.combat-scene[data-combat-animation] .combat-pair,.combat-scene[data-combat-animation] .combat-single{position:relative;isolation:isolate}
.combat-scene[data-combat-animation] .combat-portrait{position:relative;isolation:isolate}
.combat-scene .combat-fx-origin,.combat-scene .combat-fx-impact,.combat-scene .combat-fx-travel{pointer-events:none;color:var(--fx-color);position:absolute;display:block;z-index:3}
.combat-scene .fx-svg{display:block;width:100%;height:100%;overflow:visible}
.combat-scene .combat-fx-origin{width:74px;height:74px;left:50%;top:50%;transform:translate(-50%,-50%);filter:drop-shadow(0 3px 3px #07141bc9);animation:fx-prepare var(--fx-time) ease-out both}
.combat-scene .combat-fx-impact{width:clamp(66px,86%,126px);aspect-ratio:1;left:50%;top:50%;transform:translate(-50%,-50%);animation:fx-arrival var(--fx-time) linear both}
.combat-scene[data-fx-melee=true] .combat-fx-impact{animation-name:fx-melee-arrival}
.combat-scene .fx-strike,.combat-scene .fx-armor,.combat-scene .fx-contact,.combat-scene .fx-impact-aura,.combat-scene .fx-particles{position:absolute;inset:0;display:block}
.combat-scene .fx-strike{filter:drop-shadow(0 2px 2px #0618239c);animation:fx-strike var(--fx-time) ease-out both}
.combat-scene[data-fx-melee=true] .fx-strike{animation:none}
.combat-scene .fx-impact-aura{inset:17%;border-radius:50%;background:radial-gradient(ellipse,white 0%,var(--fx-color) 18%,transparent 66%);mix-blend-mode:screen;animation:fx-contact-glow var(--fx-time) ease-out both}
.combat-scene .fx-armor{inset:-2%;color:#a8dcff;animation:fx-armor var(--fx-time) ease-out both}
.combat-scene .fx-armor>.fx-svg{position:absolute;inset:0}
.combat-scene .fx-armor .fx-shield-panel{animation:none}
.combat-scene .fx-armor-break{animation-name:fx-shield-break}
.combat-scene .fx-contact{inset:20%;animation:fx-contact var(--fx-time) ease-out both}
.combat-scene .fx-shock-ring{display:block;position:absolute;inset:0;border:1px solid var(--fx-color);border-radius:50%;box-shadow:0 0 6px color-mix(in srgb,var(--fx-color) 45%,transparent)}
.combat-scene .combat-fx-travel{left:23%;top:35%;width:54%;height:0;transform-origin:0 0;z-index:5}
.combat-scene .fx-projectile{position:absolute;left:0;top:0;width:48px;height:48px;transform:translate(-50%,-50%);filter:drop-shadow(0 2px 2px #071a29);animation:fx-flight var(--fx-time) cubic-bezier(.25,.65,.35,1) both}
.combat-scene [data-fx-projectile=arrow] .fx-projectile,.combat-scene [data-fx-projectile=bolt] .fx-projectile{width:80px;height:32px;animation-name:fx-arrow-flight}
.combat-scene [data-fx-projectile=bolt]{--fx-lift:3px}
.combat-scene .fx-projectile-tail{display:block;position:absolute;left:-55%;top:calc(50% - 1px);height:2px;width:90%;background:linear-gradient(90deg,transparent,var(--fx-color));opacity:.65;border-radius:100%;filter:blur(.5px);z-index:-1}
.combat-scene .fx-projectile-halo{position:absolute;inset:15%;display:block;border-radius:50%;background:radial-gradient(circle,var(--fx-color),transparent 72%);opacity:.6;filter:blur(4px);z-index:-1}
.combat-scene [data-fx-projectile=arrow] .fx-projectile-halo,.combat-scene [data-fx-projectile=bolt] .fx-projectile-halo{display:none}
.combat-scene [data-fx-projectile=arrow] .fx-projectile-tail,.combat-scene [data-fx-projectile=bolt] .fx-projectile-tail{width:75%;left:-40%;height:1px;opacity:.4}
.combat-scene[data-combat-animation=arrow] .fx-strike,.combat-scene[data-combat-animation=bolt] .fx-strike{transform:rotate(var(--fx-hit-angle));animation-name:fx-embed}
.combat-scene .fx-weapon-swing{transform-origin:50px 68px;animation:fx-swing var(--fx-time) cubic-bezier(.25,.85,.25,1) both}
.combat-scene .fx-weapon-thrust{transform-origin:50px 75px;animation:fx-thrust var(--fx-time) ease-out both}
.combat-scene .fx-blade-a,.combat-scene .fx-blade-b{transform-origin:50px 68px;animation:fx-cross-a var(--fx-time) ease-out both}
.combat-scene .fx-blade-b{animation-name:fx-cross-b}
.combat-scene .fx-hammer-drop{transform-origin:50px 90px;animation:fx-hammer var(--fx-time) cubic-bezier(.5,0,.8,.4) both}
.combat-scene .fx-cut{transform-origin:50px 50px;mix-blend-mode:screen;animation:fx-cut var(--fx-time) ease-out both}
.combat-scene .fx-cut-second{animation-name:fx-cut-second}
.combat-scene .fx-ground-crack{animation:fx-crack var(--fx-time) ease-out both}
.combat-scene .fx-root{stroke-dasharray:1;stroke-dashoffset:1;animation:fx-grow var(--fx-time) ease-out both}
.combat-scene .fx-leaves{transform-origin:50px 65px;animation:fx-leaves var(--fx-time) ease-out both}
.combat-scene .fx-orbit,.combat-scene .fx-vortex,.combat-scene .fx-rune{transform-origin:50px 50px;animation:fx-orbit var(--fx-time) linear both}
.combat-scene .fx-orbit-second{animation-direction:reverse}
.combat-scene .fx-electric{animation:fx-electric var(--fx-time) ease-out both;filter:drop-shadow(0 0 3px #75cdff)}
.combat-scene .fx-wisps{animation:fx-wisps var(--fx-time) ease-out both}
.combat-scene .fx-ripple,.combat-scene .fx-sonic{transform-origin:50px 60px;animation:fx-ripple var(--fx-time) ease-out both}
.combat-scene .fx-rise-rune{animation:fx-rise var(--fx-time) ease-out both}
.combat-scene .fx-shield-panel{animation:fx-shield-build var(--fx-time) ease-out both;transform-origin:50px 70px}
.combat-scene .fx-shield-shine,.combat-scene .fx-light-rays{animation:fx-sheen var(--fx-time) ease-out both}
.combat-scene .fx-pact-weave{transform-origin:50px 50px;animation:fx-weave var(--fx-time) ease-out both}
.combat-scene .fx-particle{position:absolute;display:block;left:50%;top:50%;width:var(--size);height:2px;background:var(--fx-color);border-radius:1px;box-shadow:0 0 3px var(--fx-color);animation:fx-spark var(--fx-time) ease-out both}
.combat-scene .fx-gain-particles .fx-particle{height:var(--size);border-radius:50%;animation-name:fx-mote;opacity:.75}
.combat-scene .fx-shards .fx-particle{height:calc(var(--size) * 1.7);background:linear-gradient(135deg,#e9fbff,#72b9e4a0);clip-path:polygon(0 0,100% 15%,45% 100%);box-shadow:none}
.combat-scene[data-combat-animation] .effect-numbers{z-index:6;animation:fx-numbers var(--fx-time) ease-out both}
.combat-scene[data-combat-animation] .event-arrow{opacity:.3}
.combat-scene[data-combat-animation] .combat-effect-name{font-size:.85em;color:var(--fx-color);font-weight:400;margin-left:5px}
/* Keep legacy reactions from firing before the new contact point. */
.arena44 #app .battle-panel .combat-scene[data-combat-animation] .combat-card.actor,
.arena44 #app .battle-panel .combat-scene[data-combat-animation] .combat-card.recipient{animation:none}
.combat-scene[data-combat-animation] .combat-card.actor .portrait{animation:fx-source-pulse var(--fx-time) ease-out both}
.combat-scene[data-fx-melee=true] .combat-card.actor .portrait{animation-name:fx-lunge;transform-origin:50% 80%}
.combat-scene[data-combat-animation=hammer] .combat-card.actor .portrait,.combat-scene[data-combat-animation=axe] .combat-card.actor .portrait{animation-name:fx-heavy-lunge}
.combat-scene.action-damage[data-combat-animation] .combat-card.recipient .portrait{animation:fx-hit var(--fx-time) ease-out both;transform-origin:50% 80%}
.combat-scene[data-combat-animation=hammer] .combat-card.recipient .portrait{animation-name:fx-heavy-hit}
.combat-scene[data-fx-damage=false] .combat-card.recipient .portrait{animation:fx-receive var(--fx-time) ease-out both}
.combat-scene .fx-bow-string{transform-origin:30px 50px;animation:fx-bow-string var(--fx-time) ease-out both}
@keyframes fx-prepare{0%{opacity:0;scale:.82}10%,23%{opacity:1;scale:1}27%{opacity:1;scale:1.04}35%,100%{opacity:0;scale:.98}}
@keyframes fx-bow-string{0%{transform:scaleX(.9)}23%{transform:scaleX(1.2)}30%,100%{transform:scaleX(.7)}}
@keyframes fx-flight{0%,26%{opacity:0;left:0;transform:translate(-50%,-50%) scale(.75)}29%{opacity:1;left:0;transform:translate(-50%,-50%) scale(1)}43%{opacity:1;left:55%;transform:translate(-50%,calc(-50% - var(--fx-lift))) scale(1)}58%{opacity:1;left:100%;transform:translate(-50%,-50%) scale(.85)}63%,100%{opacity:0;left:100%;transform:translate(-50%,-50%) scale(.5)}}
@keyframes fx-arrow-flight{0%,26%{opacity:0;left:0;transform:translate(-50%,-50%) rotate(-7deg)}29%{opacity:1;left:0;transform:translate(-50%,-50%) rotate(-7deg)}43%{opacity:1;left:55%;transform:translate(-50%,calc(-50% - var(--fx-lift))) rotate(0deg)}58%{opacity:1;left:100%;transform:translate(-50%,-50%) rotate(8deg)}61%,100%{opacity:0;left:100%;transform:translate(-50%,-50%) rotate(8deg)}}
@keyframes fx-arrival{0%,56%{opacity:0}58%,76%{opacity:1}100%{opacity:0}}
@keyframes fx-melee-arrival{0%,38%{opacity:0}44%,76%{opacity:1}100%{opacity:0}}
@keyframes fx-strike{0%,56%{scale:.8}63%{scale:1.04}85%,100%{scale:1}}
@keyframes fx-embed{0%,56%{opacity:0;translate:-12px 0}59%{opacity:1;translate:4px 0}63%{translate:-2px 0}72%,100%{translate:0 0}}
@keyframes fx-contact-glow{0%,56%{opacity:0;scale:.35}59%{opacity:.65;scale:.65}74%,100%{opacity:0;scale:1.3}}
@keyframes fx-contact{0%,56%{scale:.3;opacity:0}59%{scale:.45;opacity:.85}83%,100%{scale:1.5;opacity:0}}
@keyframes fx-armor{0%,56%{opacity:0;scale:.9}58%,68%{opacity:.85;scale:1}100%{opacity:0;scale:1.05}}
@keyframes fx-shield-break{0%,56%{opacity:0;scale:.9}58%,61%{opacity:1;scale:1}91%,100%{opacity:0;scale:1.15}}
@keyframes fx-swing{0%,38%{transform:rotate(-80deg) translate(-7px,-4px)}46%{transform:rotate(-65deg)}58%{transform:rotate(29deg)}69%{transform:rotate(44deg)}82%,100%{transform:rotate(35deg)}}
@keyframes fx-thrust{0%,40%{transform:translate(-25px,23px) rotate(-15deg)}57%{transform:translate(8px,-8px) rotate(5deg)}69%,100%{transform:translate(0,0)}}
@keyframes fx-cross-a{0%,40%{transform:translate(-24px,-3px) rotate(-30deg)}58%{transform:translate(2px,0) rotate(4deg)}73%,100%{transform:translate(0,0)}}
@keyframes fx-cross-b{0%,43%{transform:translate(24px,-3px) rotate(30deg)}60%{transform:translate(-2px,0) rotate(-4deg)}75%,100%{transform:translate(0,0)}}
@keyframes fx-hammer{0%,41%{transform:translateY(-32px) rotate(-15deg)}58%{transform:translateY(9px) rotate(3deg)}66%{transform:translateY(-3px)}76%,100%{transform:translateY(0)}}
@keyframes fx-cut{0%,47%{opacity:0;scale:.55}57%{opacity:.9;scale:1}73%,100%{opacity:0;scale:1.07}}
@keyframes fx-cut-second{0%,50%{opacity:0;scale:.55}60%{opacity:.9;scale:1}76%,100%{opacity:0;scale:1.07}}
@keyframes fx-crack{0%,56%{opacity:0}59%,68%{opacity:.8}92%,100%{opacity:0}}
@keyframes fx-grow{0%,40%{stroke-dashoffset:1}68%,100%{stroke-dashoffset:0}}
@keyframes fx-leaves{0%,49%{opacity:0;scale:.3}69%,100%{opacity:1;scale:1}}
@keyframes fx-orbit{from{transform:rotate(-35deg)}to{transform:rotate(155deg)}}
@keyframes fx-electric{0%,56%{opacity:.4}58%{opacity:1}74%,100%{opacity:.7}}
@keyframes fx-wisps{0%{transform:translate(-12px,6px);opacity:.2}60%{transform:translate(0,0);opacity:.85}100%{transform:translate(10px,-5px);opacity:.3}}
@keyframes fx-ripple{0%,52%{scale:.55;opacity:0}60%{scale:.75;opacity:1}100%{scale:1.15;opacity:.2}}
@keyframes fx-rise{0%{transform:translateY(12px)}100%{transform:translateY(-7px)}}
@keyframes fx-shield-build{0%,50%{scale:.6;opacity:.4}66%{scale:1.03;opacity:1}100%{scale:1;opacity:.85}}
@keyframes fx-sheen{0%,56%{opacity:.3}62%{opacity:1}100%{opacity:.35}}
@keyframes fx-weave{0%{transform:rotate(-12deg);scale:.7}70%,100%{transform:rotate(0);scale:1}}
@keyframes fx-spark{0%,56%{opacity:0;transform:translate(0,0) rotate(0)}60%{opacity:1;transform:translate(calc(var(--dx) * .2),calc(var(--dy) * .2)) rotate(calc(var(--spin) * .3))}95%,100%{opacity:0;transform:translate(var(--dx),var(--dy)) rotate(var(--spin))}}
@keyframes fx-mote{0%,56%{opacity:0;transform:translate(calc(var(--dx) * .5),15px) scale(.5)}67%{opacity:.9}100%{opacity:0;transform:translate(var(--dx),var(--dy)) scale(1.1)}}
@keyframes fx-numbers{0%,57%{opacity:0;transform:translateY(7px) scale(.97)}68%,100%{opacity:1;transform:translateY(0) scale(1)}}
@keyframes fx-source-pulse{0%{filter:brightness(1)}23%{filter:brightness(1.12)}34%,100%{filter:brightness(1)}}
@keyframes fx-lunge{0%{transform:translateX(0) rotate(0)}22%{transform:translateX(-3px) rotate(-1deg)}46%{transform:translateX(9px) rotate(1.5deg)}63%,100%{transform:translateX(0) rotate(0)}}
@keyframes fx-heavy-lunge{0%{transform:translateX(0) rotate(0)}28%{transform:translateX(-3px) rotate(-2deg)}52%{transform:translateX(7px) rotate(2deg)}76%,100%{transform:translateX(0) rotate(0)}}
@keyframes fx-hit{0%,56%{transform:translateX(0) rotate(0)}61%{transform:translateX(5px) rotate(1.5deg)}68%{transform:translateX(-2px) rotate(-.5deg)}79%,100%{transform:translateX(0) rotate(0)}}
@keyframes fx-heavy-hit{0%,56%{transform:translate(0,0) rotate(0)}62%{transform:translate(4px,3px) rotate(2deg)}70%{transform:translate(-1px,-1px)}85%,100%{transform:translate(0,0) rotate(0)}}
@keyframes fx-receive{0%,56%{filter:brightness(1)}66%{filter:brightness(1.13)}100%{filter:brightness(1)}}
/* Local healing starts at once and keeps its gains readable. */
.combat-scene[data-fx-local=true] .combat-fx-impact{animation-name:fx-local}
.combat-scene[data-fx-local=true] .effect-numbers{animation:effect-arrive .25s ease-out both}
.combat-scene[data-fx-local=true] .fx-strike,.combat-scene[data-fx-local=true] .fx-impact-aura{animation:none}
.combat-scene[data-fx-local=true] .fx-gain-particles .fx-particle{animation-name:fx-local-mote}
.combat-scene[data-fx-local=true] .fx-leaves,.combat-scene[data-fx-local=true] .fx-shield-panel,.combat-scene[data-fx-local=true] .fx-ripple{animation:none}
@keyframes fx-local{0%{opacity:0;scale:.85}16%,65%{opacity:1;scale:1}100%{opacity:0;scale:1.05}}
@keyframes fx-local-mote{0%{opacity:0;transform:translate(calc(var(--dx) * .5),15px) scale(.5)}20%{opacity:.9}100%{opacity:0;transform:translate(var(--dx),var(--dy)) scale(1.1)}}
/* A direct effect gallery uses the same renderer and no playback timers. */
dialog[data-surface=combat-effects]{width:min(94vw,600px);padding:16px}
.effect-gallery-intro{font-size:.875rem;line-height:1.4;color:var(--muted)}
.effect-gallery-groups,.effect-gallery-choices{display:flex;flex-wrap:wrap;gap:5px;margin:12px 0}
.effect-gallery-groups button{flex:1;padding:8px 4px;min-height:40px;font-size:.8rem}
.effect-gallery-choices button{padding:7px 10px;min-height:36px;font-size:.8rem}
.effect-gallery-groups button[aria-pressed=true],.effect-gallery-choices button[aria-pressed=true]{border-color:var(--gold);color:var(--gold);background:#263c44}
.effect-gallery-stage{border:1px solid #38565f;border-radius:14px;padding:14px 10px;background:radial-gradient(ellipse at 50% 40%,#263f4d,#10232b 75%);overflow:hidden;min-height:270px}
.effect-gallery-stage .combat-pair{grid-template-columns:minmax(0,1fr) 24px minmax(0,1fr);gap:10px;align-items:center}
.effect-gallery-stage .combat-card{padding:8px;border:1px solid #537483;border-radius:10px;background:#10242be8}
.effect-gallery-stage .combat-card .portrait{max-height:none!important;height:160px;aspect-ratio:auto;width:100%}
.effect-gallery-stage .combat-card .portrait img{object-fit:cover;object-position:center 25%}
.effect-gallery-stage .combat-side{font-size:11px;line-height:1.2;margin:0 0 6px;color:#b5c9d3}
.effect-gallery-stage .combat-card>strong{font-size:13px!important;margin:7px 0 0;min-height:32px;line-height:1.2}
.effect-gallery-stage .combat-action-title{background:none;margin:0 0 8px;padding:0;justify-content:center;color:var(--fx-color)}
.effect-gallery-stage .combat-action-title strong{font-size:15px}
.effect-gallery-actions{display:flex;gap:8px;margin-top:12px}
.effect-gallery-actions button{flex:1;min-height:44px}
@media(max-width:390px){.effect-gallery-stage{padding:10px 7px}.effect-gallery-stage .combat-card{padding:5px}.effect-gallery-stage .combat-card .portrait{height:140px}.effect-gallery-groups button{font-size:.72rem}}
@media(prefers-reduced-motion:reduce){
 .combat-scene[data-combat-animation] .combat-fx-origin,.combat-scene[data-combat-animation] .combat-fx-travel,.combat-scene .fx-contact,.combat-scene .fx-armor,.combat-scene .fx-impact-aura,.combat-scene .fx-particles,.combat-scene .fx-cut{display:none}
 .combat-scene[data-combat-animation] .combat-fx-impact{animation:none!important;filter:none;transform:none;scale:1;opacity:1;width:34px;height:34px;aspect-ratio:1;left:auto;right:5px;top:5px;background:#10242bdd;border-radius:6px;padding:3px}
 .combat-scene[data-combat-animation] .combat-fx-impact *{animation:none!important;scale:1;opacity:1;filter:none;translate:0 0}
 .combat-scene[data-combat-animation] .effect-numbers,.combat-scene[data-combat-animation] .combat-card,.combat-scene[data-combat-animation] .portrait{animation:none!important;transform:none;scale:1;opacity:1;filter:none}
 .combat-scene .fx-root{stroke-dashoffset:0}
 .combat-scene[data-combat-animation=arrow] .fx-strike,.combat-scene[data-combat-animation=bolt] .fx-strike{transform:none}
}
