/* Dungeon Duel — Pokémon-style battle arena (design §8). Mobile-portrait first,
   scales through tablet to desktop. Type tints follow the existing class palette.

   Layout: a grounded diorama — both combatants planted on a shared perspective
   floor along a depth diagonal (boss far upper-right, hero near lower-left),
   HP frames floating over the field, the stage line docked above the commands.

   FX: every anim id gets its own choreography (see FX_PLAYBOOK in play-duel.js).
   All FX durations multiply by --fx-speed so fast-forward shortens the visuals
   in lockstep with the JS sleeps. */

:root {
	--duel-magic: #c77dff;
	--duel-thrill: #ff9e57;
	--duel-wayfinder: #5ec8a8;
	--duel-neutral: #cdbf9a;
	--duel-panel: rgba(16, 14, 24, 0.92);
	--duel-line: rgba(243, 234, 210, 0.22);
	--duel-text: #f3ead2;
}

body.duel-open {
	overflow: hidden;
}

/* ── Complete-tap chooser ─────────────────────────────────────────────────── */
.duel-chooser-backdrop {
	position: fixed;
	inset: 0;
	z-index: 1200;
	background: rgba(8, 6, 14, 0.72);
	backdrop-filter: blur(3px);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
}
.duel-chooser {
	width: min(420px, 100%);
	background: var(--duel-panel);
	border: 1px solid var(--duel-line);
	border-radius: 16px;
	padding: 18px 16px 14px;
	color: var(--duel-text);
	box-shadow: 0 18px 60px rgba(0, 0, 0, 0.6);
}
.duel-chooser-kicker {
	margin: 0 0 2px;
	font-size: 0.72rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	opacity: 0.65;
}
.duel-chooser-title {
	margin: 0 0 4px;
	font-size: 1.15rem;
}
.duel-chooser-sub {
	margin: 0 0 12px;
	font-size: 0.85rem;
	opacity: 0.75;
}
.duel-choice {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	text-align: left;
	background: rgba(255, 255, 255, 0.05);
	border: 1px solid var(--duel-line);
	border-radius: 12px;
	color: var(--duel-text);
	padding: 12px;
	margin-bottom: 8px;
	cursor: pointer;
	transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.duel-choice:hover {
	transform: translateY(-1px);
	background: rgba(255, 255, 255, 0.09);
}
.duel-choice--fight {
	border-color: rgba(255, 158, 87, 0.55);
	background: linear-gradient(160deg, rgba(255, 158, 87, 0.16), rgba(255, 255, 255, 0.04));
}
.duel-choice-icon {
	font-size: 1.6rem;
	flex: 0 0 auto;
}
.duel-choice b {
	display: block;
	font-size: 0.95rem;
}
.duel-choice small {
	display: block;
	font-size: 0.75rem;
	opacity: 0.7;
	line-height: 1.35;
}
.duel-chooser-cancel {
	display: block;
	margin: 6px auto 0;
	background: none;
	border: none;
	color: var(--duel-text);
	opacity: 0.6;
	font-size: 0.8rem;
	cursor: pointer;
	text-decoration: underline;
}

/* ── Stage shell ──────────────────────────────────────────────────────────── */
.duel-stage {
	position: fixed;
	inset: 0;
	z-index: 1100;
	display: flex;
	flex-direction: column;
	background: #0c0a14;
	color: var(--duel-text);
	height: var(--play-app-height, 100dvh);
}
.duel-chrome {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	padding: calc(env(safe-area-inset-top, 0px) + 8px) 12px 8px;
	font-size: 0.74rem;
	letter-spacing: 0.05em;
	background: rgba(0, 0, 0, 0.45);
	border-bottom: 1px solid var(--duel-line);
}
.duel-chrome-loc {
	opacity: 0.7;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.duel-chrome-actions {
	display: flex;
	gap: 6px;
	flex: 0 0 auto;
}
.duel-chrome-btn {
	background: rgba(255, 255, 255, 0.07);
	border: 1px solid var(--duel-line);
	border-radius: 8px;
	color: var(--duel-text);
	font-size: 0.74rem;
	padding: 4px 9px;
	cursor: pointer;
}
.duel-chrome-btn.is-on {
	background: rgba(255, 158, 87, 0.3);
	border-color: rgba(255, 158, 87, 0.6);
}

/* ── Arena ────────────────────────────────────────────────────────────────── */
.duel-arena {
	position: relative;
	flex: 1;
	overflow: hidden;

	/* The diorama anchors (combatant feet, % from arena bottom/left). */
	--duel-boss-x: 66%;
	--duel-boss-feet: 43%;
	--duel-hero-x: 30%;
	--duel-hero-feet: 9%;
	--duel-ground-h: 46%;
}
.duel-arena-bg {
	position: absolute;
	inset: 0;
	/* Layered top→bottom: per-boss backdrop → per-park arena → mood gradients. A missing
	   image layer 404s to nothing and reveals the layer beneath, so bosses without their
	   own backdrop fall back to the park arena, and parks without art fall back to gradient. */
	background:
		var(--duel-boss-img, none) center/cover no-repeat,
		var(--duel-arena-img, none) center/cover no-repeat,
		radial-gradient(120% 70% at 75% 18%, rgba(125, 95, 255, 0.25), transparent 55%),
		radial-gradient(120% 80% at 20% 95%, rgba(70, 180, 150, 0.18), transparent 60%),
		linear-gradient(180deg, #181228 0%, #0e0b18 55%, #141022 100%);
	image-rendering: pixelated;
	opacity: 0.95;
	z-index: 0;
	/* Soft vignette pulls the eye to the center of the diorama. */
	box-shadow: inset 0 0 90px 24px rgba(8, 6, 14, 0.5);
}
.duel-arena--pulse .duel-arena-bg {
	animation: duelBgPulse calc(var(--fx-speed, 1) * 0.7s) ease-in-out 1;
}
@keyframes duelBgPulse {
	0%, 100% { filter: brightness(1); }
	45% { filter: brightness(1.28) saturate(1.15); }
}

/* ── Field: the grounded diorama ─────────────────────────────────────────── */
.duel-field {
	position: absolute;
	inset: 0;
	z-index: 1;
	overflow: hidden;
}
.duel-ground {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: var(--duel-ground-h, 46%);
	/* A receding floor: horizon glow line at the top edge, then a GENTLE darken
	   only toward the very bottom (where the HP frames + stage-log sit) — kept
	   transparent at the horizon so there's no harsh top/bottom color switch
	   over the now-bright backdrop art. */
	background:
		linear-gradient(180deg, rgba(243, 234, 210, 0.1), transparent 9%),
		radial-gradient(150% 110% at 50% 115%, rgba(20, 16, 34, 0) 45%, rgba(8, 6, 14, 0.28) 100%),
		linear-gradient(180deg, transparent 0%, rgba(10, 8, 16, 0.12) 45%, rgba(8, 6, 14, 0.4) 100%);
}
.duel-ground::before {
	/* Haze hanging just above the horizon — separates floor from backdrop. */
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: -28px;
	height: 28px;
	background: linear-gradient(180deg, transparent, rgba(150, 130, 200, 0.12));
}

/* Combatants: planted by their FEET on the floor (consistent grounding at any
   sprite size), centered on their anchor with translateX only — the inner
   .duel-sprite owns ALL motion transforms so anchors never fight animations. */
.duel-combatant {
	position: absolute;
	transform: translateX(-50%);
	z-index: 2;
}
.duel-combatant--boss {
	left: var(--duel-boss-x);
	bottom: var(--duel-boss-feet);
}
.duel-combatant--hero {
	left: var(--duel-hero-x);
	bottom: var(--duel-hero-feet);
}
.duel-sprite {
	position: relative;
	display: block;
	z-index: 2;
}
.duel-sprite--boss {
	width: 116px;
	height: 116px;
}
.duel-sprite--hero {
	/* The hero stands nearer the camera, so slightly larger than the boss. */
	width: 126px;
	height: 126px;
}
.duel-sprite img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	image-rendering: pixelated;
	filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.55));
	user-select: none;
	-webkit-user-drag: none;
}
.duel-sprite-emoji {
	font-size: 76px;
	line-height: 116px;
	text-align: center;
	display: block;
	width: 100%;
	filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.55));
}
.duel-sprite--hero .duel-sprite-emoji {
	transform: scaleX(-1); /* back-view fallback emoji faces the boss */
	font-size: 84px;
	line-height: 126px;
}
.duel-platform {
	position: absolute;
	left: 50%;
	bottom: -12px;
	transform: translateX(-50%);
	width: 150%;
	height: 30px;
	border-radius: 50%;
	z-index: 1;
	background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.2) 55%, transparent 72%);
	box-shadow: 0 0 24px 2px rgba(243, 234, 210, 0.05);
}

/* Idle bob + states */
@keyframes duelBob {
	0%, 100% { transform: translateY(0); }
	50% { transform: translateY(-4px); }
}
.duel-sprite--boss {
	animation: duelBob 3.2s ease-in-out infinite;
}
.duel-sprite--hero {
	animation: duelBob 3.8s ease-in-out 1.1s infinite;
}
.duel-winding .duel-sprite {
	animation: duelWind 0.5s ease-in-out infinite !important;
	filter: drop-shadow(0 0 14px rgba(255, 120, 60, 0.65));
}
@keyframes duelWind {
	0%, 100% { transform: translateY(0) scale(1); }
	50% { transform: translateY(-2px) scale(1.06); }
}
.duel-hitflash .duel-sprite {
	animation: duelHit 0.32s steps(2) 2 !important;
}
@keyframes duelHit {
	0%, 100% { filter: none; }
	50% { filter: brightness(2.4) saturate(0.2); }
}
.duel-defeated .duel-sprite {
	animation: none !important;
	transition: transform 0.9s ease, opacity 0.9s ease;
	transform: translateY(26px) scale(0.8);
	opacity: 0;
}

/* ── Attacker action keyframes (wind-ups / lunges) ────────────────────────────
   One-shot round trips on .duel-sprite: each ends back at rest, so removing the
   class never snaps. !important beats the idle-bob animation while playing.
   ne = attacking the boss (up-right), sw = attacking the hero (down-left). */
.duel-sprite.duel-act--lunge-ne { animation: duelLungeNE calc(var(--fx-speed, 1) * 620ms) ease-in-out 1 both !important; }
.duel-sprite.duel-act--lunge-sw { animation: duelLungeSW calc(var(--fx-speed, 1) * 620ms) ease-in-out 1 both !important; }
.duel-sprite.duel-act--charge-ne { animation: duelChargeNE calc(var(--fx-speed, 1) * 800ms) ease-in-out 1 both !important; }
.duel-sprite.duel-act--charge-sw { animation: duelChargeSW calc(var(--fx-speed, 1) * 800ms) ease-in-out 1 both !important; }
.duel-sprite.duel-act--smash-ne { animation: duelSmashNE calc(var(--fx-speed, 1) * 700ms) ease-in 1 both !important; }
.duel-sprite.duel-act--smash-sw { animation: duelSmashSW calc(var(--fx-speed, 1) * 700ms) ease-in 1 both !important; }
.duel-sprite.duel-act--stomp { animation: duelStomp calc(var(--fx-speed, 1) * 300ms) ease-out 1 both !important; }
.duel-sprite.duel-act--gather { animation: duelGather calc(var(--fx-speed, 1) * 360ms) ease-in-out 1 both !important; }
.duel-sprite.duel-act--rise { animation: duelRiseUp calc(var(--fx-speed, 1) * 340ms) ease-in-out 1 both !important; }

@keyframes duelLungeNE {
	0%, 100% { transform: translate(0, 0); }
	35%, 60% { transform: translate(38px, -34px); }
}
@keyframes duelLungeSW {
	0%, 100% { transform: translate(0, 0); }
	35%, 60% { transform: translate(-38px, 34px); }
}
@keyframes duelChargeNE {
	0%, 100% { transform: translate(0, 0); }
	22%, 42% { transform: translate(-20px, 16px) scale(0.96); } /* crouch back… */
	62%, 78% { transform: translate(48px, -42px); }            /* …then tackle */
}
@keyframes duelChargeSW {
	0%, 100% { transform: translate(0, 0); }
	22%, 42% { transform: translate(20px, -16px) scale(0.96); }
	62%, 78% { transform: translate(-48px, 42px); }
}
@keyframes duelSmashNE {
	0%, 100% { transform: translate(0, 0); }
	30%, 46% { transform: translate(-6px, -24px) scale(1.07); } /* heave up… */
	58%, 72% { transform: translate(36px, -26px) scale(1); }    /* …slam in */
}
@keyframes duelSmashSW {
	0%, 100% { transform: translate(0, 0); }
	30%, 46% { transform: translate(6px, -24px) scale(1.07); }
	58%, 72% { transform: translate(-36px, 30px) scale(1); }
}
@keyframes duelStomp {
	0%, 100% { transform: translateY(0); }
	35% { transform: translateY(-14px); }
	62% { transform: translateY(5px) scaleY(0.94); }
}
@keyframes duelGather {
	0%, 100% { transform: scale(1); filter: none; }
	50% { transform: scale(1.1); filter: drop-shadow(0 0 16px rgba(255, 255, 255, 0.75)); }
}
@keyframes duelRiseUp {
	0%, 100% { transform: translateY(0); }
	40%, 70% { transform: translateY(-14px); filter: drop-shadow(0 0 14px rgba(255, 255, 255, 0.6)); }
}

/* ── Target reaction keyframes ──────────────────────────────────────────────── */
.duel-sprite.duel-react--recoil-ne { animation: duelRecoilNE calc(var(--fx-speed, 1) * 480ms) ease-out 1 both !important; }
.duel-sprite.duel-react--recoil-sw { animation: duelRecoilSW calc(var(--fx-speed, 1) * 480ms) ease-out 1 both !important; }
.duel-sprite.duel-react--compress { animation: duelCompress calc(var(--fx-speed, 1) * 520ms) ease-out 1 both !important; }
.duel-sprite.duel-react--jitter { animation: duelJitter calc(var(--fx-speed, 1) * 550ms) linear 1 both !important; }
.duel-sprite.duel-react--pinch { animation: duelPinch calc(var(--fx-speed, 1) * 550ms) ease-in-out 1 both !important; }
.duel-sprite.duel-react--sway { animation: duelSway calc(var(--fx-speed, 1) * 700ms) ease-in-out 1 both !important; }
.duel-sprite.duel-react--freeze { animation: duelFreezeTint calc(var(--fx-speed, 1) * 800ms) ease-in-out 1 both !important; }
.duel-sprite.duel-react--scorch { animation: duelScorchTint calc(var(--fx-speed, 1) * 800ms) ease-in-out 1 both !important; }
.duel-sprite.duel-react--dread { animation: duelDreadTint calc(var(--fx-speed, 1) * 800ms) ease-in-out 1 both !important; }

@keyframes duelRecoilNE {
	0%, 100% { transform: translate(0, 0) rotate(0); }
	30% { transform: translate(20px, -14px) rotate(5deg); }
	60% { transform: translate(9px, -6px) rotate(2deg); }
}
@keyframes duelRecoilSW {
	0%, 100% { transform: translate(0, 0) rotate(0); }
	30% { transform: translate(-20px, 14px) rotate(-5deg); }
	60% { transform: translate(-9px, 6px) rotate(-2deg); }
}
@keyframes duelCompress {
	0%, 100% { transform: scale(1, 1) translateY(0); }
	30% { transform: translateY(9px) scale(1.1, 0.76); }
	62% { transform: translateY(2px) scale(0.97, 1.05); }
}
@keyframes duelJitter {
	0%, 100% { transform: translate(0, 0); }
	12%, 50%, 88% { transform: translate(-4px, 1px); }
	30%, 70% { transform: translate(4px, -1px); }
}
@keyframes duelPinch {
	0%, 100% { transform: scale(1, 1); }
	35% { transform: scale(0.8, 1.1); }
	70% { transform: scale(1.07, 0.96); }
}
@keyframes duelSway {
	0%, 100% { transform: rotate(0); }
	25% { transform: rotate(7deg); }
	62% { transform: rotate(-6deg); }
}
@keyframes duelFreezeTint {
	0%, 100% { filter: none; }
	25%, 75% { filter: saturate(0.45) brightness(1.45) drop-shadow(0 0 14px #9fdcff); }
}
@keyframes duelScorchTint {
	0%, 100% { filter: none; }
	25%, 75% { filter: brightness(1.2) drop-shadow(0 0 14px #ff7a30); }
}
@keyframes duelDreadTint {
	0%, 100% { filter: none; }
	30%, 75% { filter: grayscale(0.85) brightness(0.65) drop-shadow(0 0 16px #7d3fd1); }
}

/* Screen shake + hitstop freeze-frame */
@keyframes duelShake {
	10%, 90% { transform: translate(-2px, 0); }
	20%, 80% { transform: translate(3px, 1px); }
	30%, 70% { transform: translate(-4px, -1px); }
	50% { transform: translate(4px, 1px); }
}
.duel-shake { animation: duelShake 0.35s linear 1; }
.duel-shake--big { animation: duelShake 0.55s linear 2; }
.duel-freeze,
.duel-freeze * {
	animation-play-state: paused !important;
}

/* ── HP boxes: floating overlay frames (enemy top-left, you bottom-right) ──── */
.duel-hpbox {
	position: absolute;
	z-index: 3;
	background: var(--duel-panel);
	border: 1px solid var(--duel-line);
	border-radius: 12px;
	padding: 8px 10px;
	width: min(62%, 250px);
	box-shadow: 0 8px 22px rgba(0, 0, 0, 0.4);
}
.duel-hpbox--boss {
	top: 10px;
	left: 10px;
	border-top-left-radius: 4px;
}
.duel-hpbox--player {
	right: 10px;
	bottom: 58px;
	border-bottom-right-radius: 4px;
}
.duel-hpbox-row {
	display: flex;
	align-items: baseline;
	gap: 6px;
	min-width: 0;
}
.duel-hpbox-name {
	font-weight: 700;
	font-size: 0.86rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.duel-hpbox-lv {
	font-size: 0.68rem;
	opacity: 0.7;
	flex: 0 0 auto;
}
.duel-type-badge {
	font-size: 0.62rem;
	padding: 1px 6px;
	border-radius: 999px;
	border: 1px solid var(--duel-line);
	flex: 0 0 auto;
	white-space: nowrap;
}
.duel-type--magic { color: var(--duel-magic); border-color: var(--duel-magic); }
.duel-type--thrill { color: var(--duel-thrill); border-color: var(--duel-thrill); }
.duel-type--wayfinder { color: var(--duel-wayfinder); border-color: var(--duel-wayfinder); }

.duel-bar {
	height: 10px;
	margin: 6px 0 4px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.1);
	overflow: hidden;
	border: 1px solid rgba(0, 0, 0, 0.4);
}
.duel-bar-fill {
	height: 100%;
	width: 100%;
	border-radius: 999px;
	background: linear-gradient(90deg, #58d68d, #2ecc71);
	transition: width 0.5s cubic-bezier(0.25, 0.8, 0.4, 1);
}
.duel-bar-fill.is-mid { background: linear-gradient(90deg, #f5d76e, #f4b350); }
.duel-bar-fill.is-low { background: linear-gradient(90deg, #ff7d6b, #e74c3c); }
.duel-hpbox-row--sub {
	justify-content: space-between;
	font-size: 0.66rem;
	opacity: 0.8;
}
.duel-status:empty { display: none; }

/* Party pool (shared boss) */
.duel-pool { margin-top: 6px; }
.duel-pool-label {
	font-size: 0.62rem;
	opacity: 0.75;
	margin-bottom: 2px;
}
.duel-bar--pool { height: 6px; margin: 2px 0; }
.duel-bar-fill--pool { background: linear-gradient(90deg, #b393ff, #7d5fff); }
.duel-pool-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 3px;
	margin-top: 3px;
}
.duel-pool-chip {
	font-size: 0.58rem;
	padding: 0 5px;
	border-radius: 999px;
	background: rgba(125, 95, 255, 0.2);
	border: 1px solid rgba(125, 95, 255, 0.4);
	white-space: nowrap;
}
.duel-pool-chip.is-won { background: rgba(46, 204, 113, 0.2); border-color: rgba(46, 204, 113, 0.45); }

/* ── Stage line: a battle-log ribbon docked above the command box ──────────── */
.duel-stageline {
	position: absolute;
	z-index: 4;
	left: 50%;
	bottom: 10px;
	transform: translateX(-50%);
	width: max-content;
	max-width: min(94%, 520px);
	text-align: center;
	font-size: 0.86rem;
	line-height: 1.35;
	padding: 6px 14px;
	border-radius: 10px;
	background: rgba(0, 0, 0, 0.55);
	border: 1px solid var(--duel-line);
	min-height: 2.1em;
}
.duel-stageline:empty { opacity: 0; }
.duel-stageline--super { border-color: #f5d76e; color: #ffe9a8; }
.duel-stageline--weak { opacity: 0.85; }
.duel-stageline--telegraph {
	border-color: var(--duel-thrill);
	color: #ffd9b8;
	animation: duelPulse 0.8s ease-in-out infinite;
}
.duel-stageline--heavy { border-color: #e74c3c; color: #ffc4ba; }
@keyframes duelPulse {
	0%, 100% { box-shadow: 0 0 0 rgba(255, 158, 87, 0); }
	50% { box-shadow: 0 0 18px rgba(255, 158, 87, 0.45); }
}

/* ── Floating combat numbers ──────────────────────────────────────────────── */
.duel-float {
	position: absolute;
	top: 18%;
	font-weight: 800;
	font-size: 1.05rem;
	pointer-events: none;
	z-index: 5;
	text-shadow: 0 2px 4px rgba(0, 0, 0, 0.8);
	animation: duelFloat 1.3s ease-out forwards;
	white-space: nowrap;
}
.duel-float--dmg { color: #ff8a7a; }
.duel-float--crit { color: #ffd166; font-size: 1.35rem; }
.duel-float--heal { color: #7dd87d; }
.duel-float--shield { color: #8ecbff; }
.duel-float--ghost { color: #b393ff; font-size: 0.8rem; opacity: 0.9; }
@keyframes duelFloat {
	0% { transform: translateY(6px); opacity: 0; }
	15% { opacity: 1; }
	100% { transform: translateY(-44px); opacity: 0; }
}

/* ── Impact particles (glyph bursts on a combatant) ───────────────────────── */
.duel-fx-p {
	position: absolute;
	font-size: 1.1rem;
	pointer-events: none;
	z-index: 4;
	animation: duelFxBurst calc(var(--fx-speed, 1) * 0.8s) ease-out var(--fx-d, 0s) forwards;
	opacity: 0;
}
.duel-fx-p--slash { animation-name: duelFxSlash; font-size: 1.5rem; }
.duel-fx-p--rise { animation-name: duelFxRise; }
.duel-fx--magic { color: var(--duel-magic); text-shadow: 0 0 10px var(--duel-magic); }
.duel-fx--thrill { color: var(--duel-thrill); text-shadow: 0 0 10px var(--duel-thrill); }
.duel-fx--wayfinder { color: var(--duel-wayfinder); text-shadow: 0 0 10px var(--duel-wayfinder); }
.duel-fx--neutral { color: var(--duel-neutral); text-shadow: 0 0 8px rgba(255, 255, 255, 0.5); }
@keyframes duelFxBurst {
	0% { transform: translate(0, 0) scale(0.6); opacity: 0; }
	20% { opacity: 1; }
	100% { transform: translate(var(--fx-x, 0), var(--fx-y, 0)) scale(1.15); opacity: 0; }
}
@keyframes duelFxSlash {
	0% { transform: translate(-18px, -18px) rotate(-25deg) scale(0.7); opacity: 0; }
	25% { opacity: 1; }
	100% { transform: translate(22px, 22px) rotate(-25deg) scale(1.2); opacity: 0; }
}
@keyframes duelFxRise {
	0% { transform: translate(0, 8px); opacity: 0; }
	25% { opacity: 1; }
	100% { transform: translate(var(--fx-x, 0), -52px); opacity: 0; }
}

/* ── Lane FX: anything traveling attacker → target ────────────────────────── */
.duel-fx-travel {
	position: absolute;
	left: 0;
	top: 0;
	z-index: 6;
	pointer-events: none;
	animation: duelTravel 0.38s linear both;
}
@keyframes duelTravel {
	0% {
		transform: translate(calc(var(--fx-fx) - 50%), calc(var(--fx-fy) - 50%)) rotate(var(--fx-ang, 0deg));
		opacity: 0;
	}
	12% { opacity: 1; }
	100% {
		transform: translate(calc(var(--fx-tx) - 50%), calc(var(--fx-ty) - 50%)) rotate(var(--fx-ang, 0deg));
		opacity: 1;
	}
}
.duel-fx-travel--spin { animation-name: duelTravelSpin; }
@keyframes duelTravelSpin {
	0% {
		transform: translate(calc(var(--fx-fx) - 50%), calc(var(--fx-fy) - 50%)) rotate(0deg);
		opacity: 0;
	}
	12% { opacity: 1; }
	100% {
		transform: translate(calc(var(--fx-tx) - 50%), calc(var(--fx-ty) - 50%)) rotate(720deg);
		opacity: 1;
	}
}

/* Orb projectile with a comet tail (tail trails opposite the flight angle). */
.duel-fx-orb {
	width: 16px;
	height: 16px;
}
.duel-fx-orb::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: radial-gradient(circle at 35% 35%, #fff, currentColor 65%);
	box-shadow: 0 0 16px currentColor, 0 0 34px currentColor;
}
.duel-fx-orb::after {
	content: "";
	position: absolute;
	right: 100%;
	top: 50%;
	width: 46px;
	height: 10px;
	transform: translateY(-50%);
	background: linear-gradient(270deg, currentColor, transparent);
	opacity: 0.7;
	border-radius: 5px;
	filter: blur(2px);
}
.duel-fx-orb--fire { color: #ff8a3d !important; }
.duel-fx-orb--light { color: #b9f0c4 !important; }

/* A tall crest sweeping the lane (water). */
.duel-fx-wave {
	width: 30px;
	height: 96px;
}
.duel-fx-wave::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: linear-gradient(90deg, transparent, currentColor);
	box-shadow: 0 0 18px currentColor;
	opacity: 0.85;
}

/* Glyph riding the lane (wind 🌀, song 🎵). */
.duel-fx-glyph {
	font-size: 1.5rem;
	text-shadow: 0 0 12px currentColor;
}

/* Sustained beam from attacker to target. */
.duel-fx-beam {
	position: absolute;
	z-index: 6;
	height: 12px;
	margin-top: -6px;
	transform-origin: 0 50%;
	border-radius: 7px;
	pointer-events: none;
	background: linear-gradient(180deg, transparent, currentColor 25%, #fff 50%, currentColor 75%, transparent);
	box-shadow: 0 0 22px currentColor;
	animation: duelBeamFire 0.72s ease-out both;
}
@keyframes duelBeamFire {
	0% { transform: rotate(var(--fx-ang)) scaleX(0); opacity: 0.6; }
	16% { transform: rotate(var(--fx-ang)) scaleX(1); opacity: 1; }
	72% { transform: rotate(var(--fx-ang)) scaleX(1); opacity: 1; }
	100% { transform: rotate(var(--fx-ang)) scaleX(1); opacity: 0; }
}

/* Expanding shockwave ring. */
.duel-fx-ring {
	position: absolute;
	z-index: 5;
	width: 26px;
	height: 26px;
	margin: -13px;
	border: 3px solid currentColor;
	border-radius: 50%;
	box-shadow: 0 0 14px currentColor, inset 0 0 8px currentColor;
	animation: duelRing calc(var(--fx-speed, 1) * 0.55s) ease-out both;
	pointer-events: none;
}
.duel-fx-ring--big {
	border-width: 4px;
	animation-duration: calc(var(--fx-speed, 1) * 0.7s);
}
@keyframes duelRing {
	0% { transform: scale(0.3); opacity: 0; }
	15% { opacity: 1; }
	100% { transform: scale(4.6); opacity: 0; }
}

/* Full-field impact flash. */
.duel-fx-flash {
	position: absolute;
	inset: 0;
	z-index: 7;
	background: #fff;
	animation: duelFlash calc(var(--fx-speed, 1) * 0.28s) ease-out both;
	pointer-events: none;
}
@keyframes duelFlash {
	0% { opacity: var(--fx-o, 0.35); }
	100% { opacity: 0; }
}

/* Slash/claw streaks. */
.duel-fx-streak {
	position: absolute;
	z-index: 6;
	height: 7px;
	border-radius: 4px;
	background: linear-gradient(90deg, transparent, #fff 35%, currentColor 65%, transparent);
	box-shadow: 0 0 14px currentColor;
	animation: duelStreak calc(var(--fx-speed, 1) * 0.42s) ease-out both;
	pointer-events: none;
}
@keyframes duelStreak {
	0% { transform: translate(-50%, -50%) rotate(var(--fx-ang)) scaleX(0.2); opacity: 0; }
	25% { opacity: 1; }
	100% { transform: translate(-50%, -50%) rotate(var(--fx-ang)) scaleX(1.15); opacity: 0; }
}

/* Lightning bolt segments (spark). */
.duel-fx-bolt {
	position: absolute;
	z-index: 6;
	height: 5px;
	border-radius: 3px;
	background: linear-gradient(90deg, #fff, currentColor);
	box-shadow: 0 0 14px currentColor;
	animation: duelBolt calc(var(--fx-speed, 1) * 0.32s) linear both;
	pointer-events: none;
}
@keyframes duelBolt {
	0% { transform: translate(-50%, -50%) rotate(var(--fx-ang)); opacity: 0; }
	20% { opacity: 1; }
	45% { opacity: 0.4; }
	65% { opacity: 1; }
	100% { transform: translate(-50%, -50%) rotate(var(--fx-ang)); opacity: 0; }
}

/* Motion-blur trail behind a charge. */
.duel-fx-trail {
	position: absolute;
	z-index: 1;
	height: 26px;
	margin-top: -13px;
	transform-origin: 0 50%;
	border-radius: 13px;
	background: linear-gradient(90deg, transparent, currentColor);
	filter: blur(4px);
	animation: duelTrail calc(var(--fx-speed, 1) * 0.5s) ease-out both;
	pointer-events: none;
}
@keyframes duelTrail {
	0% { transform: rotate(var(--fx-ang)) scaleX(0); opacity: 0; }
	30% { opacity: 0.5; }
	100% { transform: rotate(var(--fx-ang)) scaleX(1); opacity: 0; }
}

/* Converging elements (frost shards, coil chains, burst gather). */
.duel-fx-conv {
	position: absolute;
	z-index: 6;
	font-size: 1.15rem;
	text-shadow: 0 0 10px currentColor;
	animation: duelConverge 0.4s ease-in both;
	pointer-events: none;
}
@keyframes duelConverge {
	0% { transform: translate(calc(var(--fx-x) - 50%), calc(var(--fx-y) - 50%)) scale(1); opacity: 0; }
	25% { opacity: 1; }
	100% { transform: translate(-50%, -50%) scale(0.5); opacity: 0.9; }
}
.duel-fx-shard {
	width: 12px;
	height: 26px;
	clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
	background: linear-gradient(180deg, #dff3ff, #7fd0ff);
	box-shadow: 0 0 12px #9fdcff;
}
.duel-fx-chain { font-size: 1.35rem; }

/* Quake fissures rising from the floor. */
.duel-fx-crack {
	position: absolute;
	z-index: 4;
	width: 16px;
	height: 52px;
	margin-left: -8px;
	clip-path: polygon(50% 0, 72% 22%, 58% 38%, 86% 58%, 64% 74%, 78% 100%, 22% 100%, 40% 70%, 14% 52%, 38% 34%, 22% 18%);
	background: linear-gradient(180deg, currentColor, transparent);
	box-shadow: 0 0 10px currentColor;
	animation: duelCrackUp calc(var(--fx-speed, 1) * 0.6s) ease-out both;
	pointer-events: none;
}
@keyframes duelCrackUp {
	0% { transform: translateY(36px) scaleY(0.2); opacity: 0; }
	30% { opacity: 1; }
	70% { transform: translateY(-6px) scaleY(1); opacity: 1; }
	100% { transform: translateY(-12px) scaleY(1); opacity: 0; }
}

/* Flames climbing the target (fire). */
.duel-fx-flame {
	position: absolute;
	z-index: 5;
	font-size: 1.5rem;
	filter: drop-shadow(0 0 10px rgba(255, 120, 40, 0.8));
	animation: duelFlameUp calc(var(--fx-speed, 1) * 0.7s) ease-out both;
	pointer-events: none;
}
@keyframes duelFlameUp {
	0% { transform: translate(-50%, 10px) scale(0.5); opacity: 0; }
	30% { opacity: 1; }
	100% { transform: translate(-50%, -46px) scale(1.3); opacity: 0; }
}

/* Shadow wisps curling upward. */
.duel-fx-wisp {
	position: absolute;
	z-index: 5;
	width: 9px;
	height: 48px;
	border-radius: 5px;
	background: linear-gradient(180deg, rgba(140, 80, 220, 0.85), transparent);
	filter: blur(1px);
	animation: duelWisp calc(var(--fx-speed, 1) * 0.8s) ease-out both;
	pointer-events: none;
}
@keyframes duelWisp {
	0% { transform: translateY(26px) scaleY(0.4); opacity: 0; }
	30% { opacity: 0.9; }
	100% { transform: translate(6px, -34px) scaleY(1.1); opacity: 0; }
}

/* Radial bloom over a combatant — dark (shadow) or light (heal). */
.duel-fx-bloom {
	position: absolute;
	z-index: 4;
	width: 170px;
	height: 170px;
	margin: -85px;
	border-radius: 50%;
	animation: duelBloom calc(var(--fx-speed, 1) * 0.8s) ease-out both;
	pointer-events: none;
}
.duel-fx-bloom--dark { background: radial-gradient(circle, rgba(34, 12, 58, 0.92), rgba(34, 12, 58, 0) 70%); }
.duel-fx-bloom--light { background: radial-gradient(circle, rgba(190, 255, 200, 0.5), transparent 70%); }
@keyframes duelBloom {
	0% { transform: scale(0.25); opacity: 0; }
	35% { opacity: 1; }
	75% { opacity: 0.85; }
	100% { transform: scale(1.15); opacity: 0; }
}

/* Bite jaws snapping shut. */
.duel-fx-jaw {
	position: absolute;
	z-index: 6;
	width: 58px;
	height: 14px;
	margin-left: -29px;
	background: linear-gradient(180deg, #fff, currentColor);
	box-shadow: 0 0 12px currentColor;
	pointer-events: none;
}
.duel-fx-jaw--top {
	clip-path: polygon(0 0, 100% 0, 88% 100%, 70% 40%, 50% 100%, 30% 40%, 12% 100%);
	animation: duelJawTop calc(var(--fx-speed, 1) * 0.44s) ease-in both;
}
.duel-fx-jaw--bot {
	clip-path: polygon(12% 0, 30% 60%, 50% 0, 70% 60%, 88% 0, 100% 100%, 0 100%);
	animation: duelJawBot calc(var(--fx-speed, 1) * 0.44s) ease-in both;
}
@keyframes duelJawTop {
	0% { transform: translateY(-48px); opacity: 0; }
	30% { opacity: 1; }
	72% { transform: translateY(-9px); opacity: 1; }
	100% { transform: translateY(-9px); opacity: 0; }
}
@keyframes duelJawBot {
	0% { transform: translateY(36px); opacity: 0; }
	30% { opacity: 1; }
	72% { transform: translateY(-1px); opacity: 1; }
	100% { transform: translateY(-1px); opacity: 0; }
}

/* Barrier dome (shield/brace). */
.duel-fx-dome {
	position: absolute;
	z-index: 5;
	width: 150px;
	height: 84px;
	margin-left: -75px;
	margin-top: -64px;
	border-radius: 50% 50% 0 0 / 100% 100% 0 0;
	border: 2px solid currentColor;
	border-bottom: none;
	background: radial-gradient(ellipse at 50% 100%, rgba(255, 255, 255, 0.14), transparent 75%);
	box-shadow: 0 0 24px currentColor;
	transform-origin: 50% 100%;
	animation: duelDome calc(var(--fx-speed, 1) * 0.8s) ease-out both;
	pointer-events: none;
}
@keyframes duelDome {
	0% { transform: scaleY(0); opacity: 0; }
	30% { transform: scaleY(1.08); opacity: 1; }
	55% { transform: scaleY(1); opacity: 0.9; }
	100% { transform: scaleY(1); opacity: 0; }
}

/* Web snapping over the target. */
.duel-fx-web {
	position: absolute;
	z-index: 5;
	font-size: 58px;
	margin-left: -29px;
	margin-top: -32px;
	filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.5));
	animation: duelWeb calc(var(--fx-speed, 1) * 0.9s) ease-out both;
	pointer-events: none;
}
@keyframes duelWeb {
	0% { transform: scale(0.2) rotate(-50deg); opacity: 0; }
	30% { transform: scale(1.25) rotate(0); opacity: 1; }
	45% { transform: scale(1); }
	80% { transform: scale(1); opacity: 1; }
	100% { transform: scale(1); opacity: 0; }
}

/* ── Intro + settle overlays ──────────────────────────────────────────────── */
.duel-intro,
.duel-settle {
	position: absolute;
	inset: 0;
	z-index: 8;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(8, 6, 14, 0.66);
	backdrop-filter: blur(2px);
	transition: opacity 0.3s ease;
	padding: 18px;
}
.duel-intro.is-gone { opacity: 0; pointer-events: none; }
.duel-intro-card,
.duel-settle-card {
	background: var(--duel-panel);
	border: 1px solid var(--duel-line);
	border-radius: 16px;
	padding: 20px 18px;
	text-align: center;
	max-width: 380px;
	width: 100%;
	box-shadow: 0 18px 60px rgba(0, 0, 0, 0.65);
}
.duel-intro-vs { font-size: 1.2rem; margin: 0 0 8px; }
.duel-intro-bark {
	font-size: 0.88rem;
	opacity: 0.85;
	line-height: 1.45;
	margin: 0 0 14px;
}
.duel-intro-go { width: 100%; }
.duel-settle { z-index: 10; }
.duel-settle-title { font-size: 1.25rem; font-weight: 800; margin-bottom: 8px; }
.duel-settle-body {
	font-size: 0.86rem;
	line-height: 1.5;
	opacity: 0.9;
	margin: 0 0 14px;
}
.duel-summary { font-size: 0.74rem; opacity: 0.7; }
.duel-settle-actions {
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.duel-grade { letter-spacing: 0.12em; }
.duel-grade--flawless { color: #ffd166; text-shadow: 0 0 16px rgba(255, 209, 102, 0.5); }
.duel-grade--loss { color: #ff8a7a; }

/* ── Command box ──────────────────────────────────────────────────────────── */
.duel-commands {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 8px;
	padding: 10px 12px calc(env(safe-area-inset-bottom, 0px) + 12px);
	background: rgba(0, 0, 0, 0.55);
	border-top: 1px solid var(--duel-line);
}
.duel-commands--five .duel-cmd:first-child { grid-column: span 2; }
.duel-cmd {
	position: relative;
	display: flex;
	align-items: center;
	gap: 8px;
	min-height: 54px;
	padding: 8px 10px;
	border-radius: 12px;
	border: 1px solid var(--duel-line);
	background: rgba(255, 255, 255, 0.06);
	color: var(--duel-text);
	font-weight: 700;
	font-size: 0.88rem;
	cursor: pointer;
	transition: transform 0.1s ease, background 0.12s ease, opacity 0.12s ease;
	touch-action: manipulation;
}
.duel-cmd:active:not(:disabled) { transform: scale(0.97); }
.duel-cmd:disabled { opacity: 0.38; cursor: default; }
.duel-cmd--magic { border-color: rgba(199, 125, 255, 0.5); box-shadow: inset 0 0 18px rgba(199, 125, 255, 0.12); }
.duel-cmd--thrill { border-color: rgba(255, 158, 87, 0.5); box-shadow: inset 0 0 18px rgba(255, 158, 87, 0.12); }
.duel-cmd--wayfinder { border-color: rgba(94, 200, 168, 0.5); box-shadow: inset 0 0 18px rgba(94, 200, 168, 0.12); }
.duel-cmd--urgent:not(:disabled) {
	animation: duelPulse 0.7s ease-in-out infinite;
	border-color: #ffd166;
}
.duel-cmd-icon { font-size: 1.3rem; flex: 0 0 auto; }
.duel-cmd-name {
	flex: 1 1 auto;
	text-align: left;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.duel-cmd-sub {
	font-size: 0.66rem;
	opacity: 0.75;
	font-weight: 600;
	flex: 0 0 auto;
}

/* Long-press tooltip */
.duel-tip {
	position: fixed;
	left: 50%;
	bottom: calc(env(safe-area-inset-bottom, 0px) + 120px);
	transform: translateX(-50%) translateY(8px);
	z-index: 1300;
	background: var(--duel-panel);
	border: 1px solid var(--duel-line);
	border-radius: 10px;
	color: var(--duel-text);
	font-size: 0.78rem;
	line-height: 1.4;
	padding: 8px 12px;
	max-width: min(90vw, 360px);
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.2s ease, transform 0.2s ease;
}
.duel-tip.is-in { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ── Responsive scale-up (tablet / desktop) ───────────────────────────────── */
@media (min-width: 480px) {
	.duel-sprite--boss { width: 128px; height: 128px; }
	.duel-sprite--boss .duel-sprite-emoji { font-size: 86px; line-height: 128px; }
	.duel-sprite--hero { width: 140px; height: 140px; }
	.duel-sprite--hero .duel-sprite-emoji { font-size: 94px; line-height: 140px; }
}
@media (min-width: 768px) {
	.duel-arena {
		--duel-boss-x: 64%;
		--duel-hero-x: 33%;
	}
	.duel-sprite--boss { width: 168px; height: 168px; }
	.duel-sprite--boss .duel-sprite-emoji { font-size: 112px; line-height: 168px; }
	.duel-sprite--hero { width: 184px; height: 184px; }
	.duel-sprite--hero .duel-sprite-emoji { font-size: 124px; line-height: 184px; }
	.duel-hpbox { width: min(46%, 300px); padding: 10px 14px; }
	.duel-hpbox--boss { top: 14px; left: 14px; }
	.duel-hpbox--player { right: 14px; bottom: 64px; }
	.duel-hpbox-name { font-size: 1rem; }
	.duel-bar { height: 12px; }
	.duel-stageline { font-size: 1rem; bottom: 12px; }
	.duel-commands {
		grid-template-columns: repeat(2, minmax(0, 280px));
		justify-content: center;
		gap: 10px;
		padding-top: 14px;
	}
	.duel-cmd { min-height: 60px; font-size: 0.95rem; }
	.duel-commands--five .duel-cmd:first-child { grid-column: span 2; }
}
@media (min-width: 1100px) {
	.duel-arena {
		max-width: 1000px;
		width: 100%;
		margin: 0 auto;
	}
	.duel-sprite--boss { width: 208px; height: 208px; }
	.duel-sprite--boss .duel-sprite-emoji { font-size: 140px; line-height: 208px; }
	.duel-sprite--hero { width: 228px; height: 228px; }
	.duel-sprite--hero .duel-sprite-emoji { font-size: 152px; line-height: 228px; }
	.duel-commands { padding-bottom: 18px; }
}
/* Short landscape phones: compress vertical chrome so the arena still fits. */
@media (max-height: 480px) {
	.duel-arena {
		--duel-boss-feet: 38%;
		--duel-hero-feet: 7%;
		--duel-ground-h: 40%;
	}
	.duel-sprite--boss { width: 76px; height: 76px; }
	.duel-sprite--boss .duel-sprite-emoji { font-size: 50px; line-height: 76px; }
	.duel-sprite--hero { width: 84px; height: 84px; }
	.duel-sprite--hero .duel-sprite-emoji { font-size: 56px; line-height: 84px; }
	.duel-hpbox { padding: 5px 8px; }
	.duel-hpbox--player { bottom: 44px; }
	.duel-stageline { bottom: 6px; padding: 3px 10px; font-size: 0.76rem; }
	.duel-cmd { min-height: 42px; }
	.duel-commands { gap: 6px; padding-top: 6px; }
}

/* Reduced motion: no bob/shake/pulse, no action/reaction/FX keyframes; bars snap.
   (play-duel.js also skips the whole FX playbook under reduced motion.) */
@media (prefers-reduced-motion: reduce) {
	.duel-sprite--boss,
	.duel-sprite--hero,
	.duel-winding .duel-sprite,
	.duel-stageline--telegraph,
	.duel-cmd--urgent:not(:disabled),
	.duel-sprite[class*="duel-act--"],
	.duel-sprite[class*="duel-react--"],
	[class*="duel-fx-"] {
		animation: none !important;
	}
	.duel-bar-fill { transition: none; }
	.duel-shake,
	.duel-shake--big { animation: none; }
}

/* D38 class resource meter (class-combat-design.md §2) — Momentum / Charge / Track. */
.duel-resource {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	margin-top: 0.25rem;
}
.duel-resource-track {
	flex: 1;
	height: 5px;
	border-radius: 4px;
	background: rgba(255, 255, 255, 0.1);
	overflow: hidden;
}
.duel-resource-fill {
	display: block;
	height: 100%;
	width: 0%;
	border-radius: 4px;
	transition: width 0.35s ease;
}
.duel-resource-fill--momentum {
	background: linear-gradient(90deg, #ff9d5c, #ff5e3a);
}
.duel-resource-fill--charge {
	background: linear-gradient(90deg, #c08bff, #7be0ff);
}
.duel-resource-fill--track {
	background: linear-gradient(90deg, #6bf0a0, #2e9e5b);
}
.duel-resource-fill.is-full {
	box-shadow: 0 0 8px rgba(255, 220, 120, 0.8);
	animation: duelResourceFull 0.9s ease-in-out infinite alternate;
}
@keyframes duelResourceFull {
	from { filter: brightness(1); }
	to { filter: brightness(1.4); }
}
@media (prefers-reduced-motion: reduce) {
	.duel-resource-fill.is-full { animation: none; }
}
.duel-resource-label {
	flex: none;
	font-size: 0.62rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	color: var(--text-muted, #9aa);
	min-width: 5.5em;
	text-align: right;
}
