/* v0.77 mechanic effects (js/fx.js). Reference: Honkai: Star Rail (break shatter + element emblem, crystal shield, lock-on,
   telegraphs), drawn in our pixel style. Painted strips (img/fx/fx_*.png, black background) play with a screen blend. */
.fx { position: absolute; pointer-events: none; z-index: 1200; --d: 700ms; --c: #fff; }
.fx-layer { position: absolute; inset: 0; pointer-events: none; z-index: 38; overflow: hidden; }

/* painted 4-frame strips */
.fx.strip { width: var(--sz, 360px); height: var(--sz, 360px); margin: calc(var(--sz, 360px) / -2) 0 0 calc(var(--sz, 360px) / -2);
  background-repeat: no-repeat; background-size: 400% 100%; image-rendering: pixelated; mix-blend-mode: screen;
  animation: fx-strip var(--d) steps(4) forwards; }
@keyframes fx-strip { from { background-position: 0 0; } to { background-position: 133.333% 0; } }

/* shards (procedural, always available) */
.fx.shard { width: var(--w, 34px); height: var(--h, 52px); margin: -26px 0 0 -17px; filter: drop-shadow(0 0 6px var(--c)); background: linear-gradient(135deg, #fff 0 18%, var(--c) 40%, var(--c2, var(--c)) 100%);
  clip-path: polygon(50% 0, 100% 38%, 70% 100%, 0 70%); box-shadow: 0 0 8px var(--c); image-rendering: pixelated;
  animation: fx-shard var(--d) cubic-bezier(.12,.75,.35,1) forwards; }
@keyframes fx-shard { 0% { transform: translate(0,0) rotate(0) scale(.4); opacity: 1; }
  70% { opacity: 1; } 100% { transform: translate(var(--dx), var(--dy)) rotate(var(--rot)) scale(1); opacity: 0; } }
.fx.core { width: 70px; height: 70px; margin: -35px 0 0 -35px; border-radius: 50%; background: radial-gradient(#fff 0 30%, var(--c) 60%, transparent 70%);
  animation: fx-core var(--d) ease-out forwards; mix-blend-mode: screen; }
@keyframes fx-core { 0% { transform: scale(.3); opacity: 1; } 35% { transform: scale(4.5); opacity: 1; } 100% { transform: scale(7); opacity: 0; } }

/* rings */
.fx.ring { width: 60px; height: 60px; margin: -30px 0 0 -30px; border-radius: 50%; border: 14px solid var(--c); box-shadow: 0 0 18px var(--c), inset 0 0 18px var(--c);
  animation: fx-ring var(--d) ease-out forwards; }
@keyframes fx-ring { from { transform: scale(.4); opacity: 1; } to { transform: scale(var(--to, 14)); opacity: 0; border-width: 1px; } }
.fx.ground { width: 420px; height: 110px; margin: -55px 0 0 -210px; border-radius: 50%; border: 8px solid var(--c); box-shadow: 0 0 24px var(--c), inset 0 0 24px var(--c);
  animation: fx-ground 900ms ease-in-out infinite alternate; z-index: 2 !important; }
@keyframes fx-ground { from { transform: scale(.85); opacity: .55; } to { transform: scale(1.12); opacity: 1; } }

/* full-stage flashes */
.fx.flash { inset: 0; position: absolute; background: var(--c); mix-blend-mode: screen; animation: fx-flash var(--d) ease-out forwards; z-index: 1250; }
@keyframes fx-flash { 0% { opacity: .85; } 100% { opacity: 0; } }
.fx.dim { inset: 0; position: absolute; background: radial-gradient(ellipse at var(--x,50%) var(--y,50%), transparent 0 18%, rgba(0,0,8,.72) 55%);
  animation: fx-dim var(--d) ease-in-out forwards; z-index: 20 !important; }
@keyframes fx-dim { 0% { opacity: 0; } 20%, 75% { opacity: 1; } 100% { opacity: 0; } }
.fx.vign { inset: 0; position: absolute; box-shadow: inset 0 0 160px 40px var(--c); animation: fx-vign 1400ms ease-in-out infinite alternate; z-index: 1190; }
@keyframes fx-vign { from { opacity: .35; } to { opacity: .9; } }

/* HSR-style slanted banner */
.fx.banner { left: 0; right: 0; top: 7%; height: 104px; display: flex; flex-direction: column; justify-content: center; align-items: center;
  background: linear-gradient(90deg, transparent, rgba(5,10,20,.88) 14%, rgba(5,10,20,.88) 86%, transparent); border-top: 3px solid var(--c); border-bottom: 3px solid var(--c);
  transform: skewY(-4deg); animation: fx-banner var(--d) cubic-bezier(.2,.9,.3,1) forwards; z-index: 1300; }
.fx.banner b { font: 700 54px/1 'Barlow Condensed', 'DotGothic16', sans-serif; letter-spacing: 6px; color: #fff; text-shadow: 0 0 18px var(--c), 3px 3px 0 #000; }
.fx.banner small { margin-top: 6px; font: 600 22px/1 'DotGothic16', sans-serif; letter-spacing: 2px; color: var(--c); text-shadow: 2px 2px 0 #000; }
@keyframes fx-banner { 0% { clip-path: inset(0 100% 0 0); } 14% { clip-path: inset(0 0 0 0); } 80% { clip-path: inset(0 0 0 0); opacity: 1; } 100% { clip-path: inset(0 0 0 100%); opacity: 0; } }

/* element emblem (Star Rail's break badge) */
.fx.emblem { width: 190px; height: 190px; margin: -95px 0 0 -95px; border-radius: 50%; border: 5px solid var(--c); background: radial-gradient(rgba(5,10,20,.85) 55%, transparent 70%);
  box-shadow: 0 0 26px var(--c), inset 0 0 18px var(--c); display: grid; place-items: center; animation: fx-emblem var(--d) cubic-bezier(.2,1.4,.4,1) forwards; z-index: 1280; }
.fx.emblem svg { width: 104px; height: 104px; filter: drop-shadow(0 0 6px var(--c)); }
.fx.emblem i { position: absolute; bottom: -62px; font: 800 58px/1 'Barlow Condensed', sans-serif; letter-spacing: 4px; color: #fff; text-shadow: 0 0 10px var(--c), 2px 2px 0 #000; font-style: normal; }
@keyframes fx-emblem { 0% { transform: scale(2.4) rotate(-20deg); opacity: 0; } 18% { transform: scale(1) rotate(0); opacity: 1; } 82% { opacity: 1; } 100% { transform: scale(.9); opacity: 0; } }

/* lock-on reticle */
.fx.reticle { width: 220px; height: 220px; margin: -110px 0 0 -110px; border: 7px dashed var(--c); border-radius: 50%; animation: fx-reticle var(--d) cubic-bezier(.3,.8,.3,1) forwards; z-index: 44; }
.fx.reticle::before, .fx.reticle::after { content: ''; position: absolute; background: var(--c); box-shadow: 0 0 10px var(--c); }
.fx.reticle::before { left: 50%; top: -24px; bottom: -24px; width: 4px; margin-left: -2px; }
.fx.reticle::after { top: 50%; left: -24px; right: -24px; height: 4px; margin-top: -2px; }
@keyframes fx-reticle { 0% { transform: scale(2.6) rotate(90deg); opacity: 0; } 55% { transform: scale(1) rotate(0); opacity: 1; } 70% { transform: scale(.82); } 100% { transform: scale(.9); opacity: .0; } }

/* streak from attacker to target */
.fx.streak { height: 10px; margin-top: -5px; transform-origin: 0 50%; background: linear-gradient(90deg, transparent, var(--c) 30%, #fff 80%, var(--c));
  box-shadow: 0 0 14px var(--c); animation: fx-streak var(--d) ease-out forwards; z-index: 43; }
@keyframes fx-streak { 0% { clip-path: inset(0 100% 0 0); } 40% { clip-path: inset(0 0 0 0); opacity: 1; } 100% { clip-path: inset(0 0 0 85%); opacity: 0; } }

/* dome over a unit (Guard / barrier) */
.fx.dome { width: var(--sz, 300px); height: var(--sz, 300px); margin: calc(var(--sz, 300px) / -2) 0 0 calc(var(--sz, 300px) / -2); border-radius: 50% 50% 46% 46%;
  background: repeating-conic-gradient(from 30deg, rgba(120,220,255,.16) 0 60deg, rgba(120,220,255,.04) 60deg 120deg), radial-gradient(transparent 55%, rgba(120,220,255,.5) 72%, transparent 74%);
  border: 3px solid rgba(160,235,255,.9); box-shadow: 0 0 30px rgba(90,200,255,.8), inset 0 0 30px rgba(90,200,255,.5); animation: fx-dome var(--d) ease-out forwards; z-index: 42; }
@keyframes fx-dome { 0% { transform: scale(.3); opacity: 0; } 20% { transform: scale(1.05); opacity: 1; } 75% { opacity: .9; } 100% { transform: scale(1.12); opacity: 0; } }

/* stamp on a unit (status) */
.fx.stamp { padding: 4px 18px 9px; margin-left: 0; font: italic 900 44px/1 'Barlow Condensed', sans-serif; letter-spacing: .05em; color: var(--c); background: transparent;
  border: 0; border-bottom: 4px solid currentColor; border-radius: 0; box-shadow: none; -webkit-text-stroke: 6px #081721; paint-order: stroke fill; text-shadow: 2px 4px #07131f; animation: nbStamp var(--d) both; z-index: 1260; }
@keyframes fx-stamp { 0% { transform: rotate(-8deg) scale(2.2); opacity: 0; } 20% { transform: rotate(-8deg) scale(1); opacity: 1; } 80% { opacity: 1; } 100% { transform: rotate(-8deg) translateY(-30px); opacity: 0; } }

/* rising motes (heal / regen / cleanse) */
.fx.mote { width: 10px; height: 10px; margin: -5px 0 0 -5px; background: var(--c); box-shadow: 0 0 10px var(--c); clip-path: polygon(35% 0,65% 0,65% 35%,100% 35%,100% 65%,65% 65%,65% 100%,35% 100%,35% 65%,0 65%,0 35%,35% 35%);
  animation: fx-mote var(--d) ease-out forwards; }
@keyframes fx-mote { 0% { transform: translate(0,0) scale(.6); opacity: 0; } 20% { opacity: 1; } 100% { transform: translate(var(--dx), -150px) scale(1.2); opacity: 0; } }

/* persistent states on a unit (class on .u) */
.u.fx-enraged .mon { filter: drop-shadow(0 0 8px #ff2a2a) drop-shadow(0 0 18px #ff2a2a) saturate(1.3); animation: fx-throb 900ms ease-in-out infinite; }
@keyframes fx-throb { 50% { filter: drop-shadow(0 0 16px #ff4a2a) drop-shadow(0 0 34px #ff0000) saturate(1.6); } }
.u.fx-barrier .mon::after { content: ''; position: absolute; inset: -8% -10%; border-radius: 45%; border: 3px solid rgba(255,90,110,.9);
  background: repeating-linear-gradient(60deg, rgba(255,80,110,.14) 0 14px, transparent 14px 28px), repeating-linear-gradient(-60deg, rgba(255,80,110,.14) 0 14px, transparent 14px 28px);
  box-shadow: 0 0 22px rgba(255,60,90,.8), inset 0 0 26px rgba(255,60,90,.5); animation: fx-shell 1600ms ease-in-out infinite alternate; pointer-events: none; }
@keyframes fx-shell { from { opacity: .65; } to { opacity: 1; } }
.u.fx-sealed .mon { filter: grayscale(.9) brightness(.7) drop-shadow(0 0 8px #a050ff); }
.u.fx-sealed .mon::before { content: ''; position: absolute; inset: 20% -6%; background: repeating-linear-gradient(28deg, transparent 0 18px, rgba(190,110,255,.95) 18px 24px, transparent 24px 40px),
  repeating-linear-gradient(-28deg, transparent 0 18px, rgba(190,110,255,.95) 18px 24px, transparent 24px 40px); filter: drop-shadow(0 0 6px #a050ff); z-index: 2; pointer-events: none; }
.u.fx-weak .mon::before { content: ''; position: absolute; left: 50%; top: 42%; width: 54px; height: 54px; margin: -27px; border-radius: 50%; border: 4px solid #ffe04a;
  box-shadow: 0 0 18px #ffb000, inset 0 0 12px #ffb000; animation: fx-weak 600ms ease-in-out infinite alternate; z-index: 3; pointer-events: none; }
@keyframes fx-weak { from { transform: scale(.8); } to { transform: scale(1.15); } }
.u.fx-regen .mon { filter: drop-shadow(0 0 10px rgba(80,255,140,.75)); }
.u.fx-mute .mon { filter: saturate(.4) brightness(.85); }
.u.fx-provoke .ring { box-shadow: 0 0 22px #ffb000, inset 0 0 14px #ffb000; border-color: #ffd04a !important; }

/* storm across the stage */
.fx-storm { position: absolute; inset: -20% -20%; pointer-events: none; z-index: 1150; opacity: .55; mix-blend-mode: screen;
  background-image: repeating-linear-gradient(105deg, transparent 0 28px, var(--c) 28px 30px, transparent 30px 62px), repeating-linear-gradient(105deg, transparent 0 47px, rgba(255,255,255,.55) 47px 48px, transparent 48px 91px);
  animation: fx-rain 600ms linear infinite; }
@keyframes fx-rain { from { transform: translate(0,0); } to { transform: translate(-60px,180px); } }

/* team blast */
.fx.lines { inset: 0; position: absolute; z-index: 44; background: repeating-conic-gradient(from 0deg at var(--x,60%) var(--y,50%), rgba(255,255,255,.0) 0 4deg, rgba(255,240,180,.45) 4deg 5deg);
  animation: fx-lines var(--d) ease-out forwards; mix-blend-mode: screen; }
@keyframes fx-lines { 0% { opacity: 0; transform: scale(1.4); } 25% { opacity: 1; } 100% { opacity: 0; transform: scale(1); } }

/* light rays bursting from a point (break, team blast, team hit) */
.fx.rays { width: 900px; height: 900px; margin: -450px 0 0 -450px; border-radius: 50%; mix-blend-mode: screen;
  background: repeating-conic-gradient(from var(--a, 0deg), transparent 0 7deg, var(--c) 7deg 9deg, transparent 9deg 22deg, rgba(255,255,255,.85) 22deg 23deg, transparent 23deg 31deg);
  -webkit-mask: radial-gradient(transparent 6%, #000 14%, #000 34%, transparent 62%); mask: radial-gradient(transparent 6%, #000 14%, #000 34%, transparent 62%);
  animation: fx-rays var(--d) cubic-bezier(.1,.8,.3,1) forwards; z-index: 41; }
@keyframes fx-rays { 0% { transform: scale(.2) rotate(-25deg); opacity: 0; } 15% { opacity: 1; } 100% { transform: scale(1.25) rotate(10deg); opacity: 0; } }
/* a red pulsing tint on a boss that has announced a strike */
.u.fx-warned .mon { animation: fx-warned 700ms ease-in-out infinite alternate; }
@keyframes fx-warned { from { filter: drop-shadow(0 0 6px #ff2020); } to { filter: drop-shadow(0 0 22px #ff2020) brightness(1.15) saturate(1.3); } }
.fx.bang { font: 900 120px/1 'Barlow Condensed', sans-serif; color: #ff3a3a; -webkit-text-stroke: 5px #000; text-shadow: 0 0 24px #ff0000; margin: -60px 0 0 -25px;
  animation: fx-bang var(--d) cubic-bezier(.2,1.6,.4,1) infinite alternate; z-index: 46; }
@keyframes fx-bang { from { transform: scale(.85) translateY(0); } to { transform: scale(1.1) translateY(-14px); } }
/* a unit struck by a team-wide hit */
.fx.hitx { width: 160px; height: 160px; margin: -80px 0 0 -80px; background: linear-gradient(45deg, transparent 44%, var(--c) 46% 54%, transparent 56%), linear-gradient(-45deg, transparent 44%, var(--c) 46% 54%, transparent 56%);
  filter: drop-shadow(0 0 10px var(--c)); animation: fx-hitx var(--d) ease-out forwards; z-index: 44; }
@keyframes fx-hitx { 0% { transform: scale(.3); opacity: 1; } 40% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(1.3); opacity: 0; } }

/* a unit's own hit spark (team hits): smaller than the boss flash */
.fx.pcore { width: 90px; height: 90px; margin: -45px 0 0 -45px; border-radius: 50%; background: radial-gradient(#fff 0 20%, var(--c) 45%, transparent 68%);
  mix-blend-mode: screen; animation: fx-pcore var(--d) ease-out forwards; }
@keyframes fx-pcore { 0% { transform: scale(.4); opacity: 1; } 40% { transform: scale(1.4); opacity: 1; } 100% { transform: scale(1.8); opacity: 0; } }
/* an execution: two blades crossing on the target */
.fx.cross { width: 420px; height: 420px; margin: -210px 0 0 -210px; z-index: 1240;
  background: linear-gradient(35deg, transparent 47%, #fff 49%, var(--c) 50%, #fff 51%, transparent 53%), linear-gradient(-35deg, transparent 47%, #fff 49%, var(--c) 50%, #fff 51%, transparent 53%);
  filter: drop-shadow(0 0 12px var(--c)) drop-shadow(0 0 24px var(--c)); animation: fx-cross var(--d) cubic-bezier(.1,.9,.3,1) forwards; }
@keyframes fx-cross { 0% { clip-path: inset(50% 50% 50% 50%); transform: scale(1.4) rotate(-15deg); } 30% { clip-path: inset(0 0 0 0); transform: scale(1) rotate(0); opacity: 1; } 100% { opacity: 0; transform: scale(1.05); } }
/* seal chains: bands closing around the target and a lock */
.fx.chainring { width: 260px; height: 260px; margin: -130px 0 0 -130px; border-radius: 50%; border: 10px dotted #c47aff; box-shadow: 0 0 18px #a050ff, inset 0 0 18px #a050ff;
  animation: fx-chain var(--d) cubic-bezier(.2,.9,.3,1) forwards; z-index: 1230; }
@keyframes fx-chain { 0% { transform: scale(2.2) rotate(0); opacity: 0; } 45% { transform: scale(1) rotate(160deg); opacity: 1; } 85% { opacity: 1; } 100% { transform: scale(.95) rotate(200deg); opacity: 0; } }
.fx.lock { font: 900 90px/1 'Barlow Condensed', sans-serif; margin: -45px 0 0 -30px; color: #e6c2ff; text-shadow: 0 0 18px #a050ff, 4px 4px 0 #000; animation: fx-stamp var(--d) cubic-bezier(.2,1.6,.4,1) forwards; z-index: 1260; }
.fx.mote { width: 18px; height: 18px; margin: -9px 0 0 -9px; }

/* Team Blast meter on the field: ready = gold ring, Overdrive = red-gold ring with heat */
/* Overdrive gauge badge */
.fx.gauge { width: 240px; height: 34px; margin-left: -120px; border: 3px solid var(--c); background: rgba(5,10,20,.85); box-shadow: 0 0 18px var(--c); z-index: 1290;
  transform: skewX(-12deg); animation: fx-stamp var(--d) cubic-bezier(.2,1.6,.4,1) forwards; }
.fx.gauge i { position: absolute; left: 0; top: 0; bottom: 0; width: var(--p); background: linear-gradient(90deg, #ffd84a, #ff4a2a); }
.fx.gauge b { position: absolute; inset: 0; display: grid; place-items: center; font: 800 26px/1 'Barlow Condensed', sans-serif; color: #fff; text-shadow: 2px 2px 0 #000; letter-spacing: 2px; }
