/* Desktop battle — shell level: full-window stage, scene media, cinematic states, the slim stone edge that replaces
   the pillar during battle, toast placement and legacy dialogs. The HUD itself (rune altar, boss banner, minion plates)
   lives in page-battle.css under .pg-battle. Geometry comes from page-battle.mjs (CSS variables on the battle section). */
#desktop-shell{display:none}.stage-media,.stage-cinematic-controls{display:none}
@media(min-width:1000px){
  body.desktop-game{height:100dvh;overflow:hidden;background:#080e12}
  body.desktop-game #desktop-shell{display:block}
  body.desktop-game>.ambient,body.desktop-game>.topbar,body.desktop-game>main>.page-heading,body.desktop-game>main>.campaign-toolbar,body.desktop-game>main>.page-footer{display:none}
  body.desktop-game>main{padding:0;margin:0;max-width:none}
  body.desktop-game:not(.desktop-battle)>main{display:none}
  body.desktop-game .game-layout,body.desktop-game .adventure-column,body.desktop-game .board-column{display:contents}
  body.desktop-game .battle-panel{position:fixed;inset:0;width:100vw;height:100dvh;min-height:0;max-height:none;border:0;border-radius:0;overflow:hidden;box-shadow:none;background:#080e12;isolation:isolate}
  body.desktop-game .battle-art,body.desktop-game .battle-video,body.desktop-game .battle-shade,body.desktop-game .embers{display:none}
  body.desktop-game .stage-media{display:block;position:absolute;inset:0;overflow:hidden;background:#080e12;pointer-events:none}
  .stage-mother,.stage-motion,.stage-bridge{position:absolute;display:block;max-width:none;max-height:none;object-fit:fill;user-select:none}
  .stage-bridge{z-index:2}.stage-bridge[hidden]{display:none}
  .stage-evolution-fx{position:absolute;inset:0;z-index:8;pointer-events:none;display:grid;place-items:center}
  .stage-evolution-fx[hidden]{display:none}
  .stage-evolution-fx:before{content:"";position:absolute;inset:0;background:#fff5e4;opacity:0;animation:stage-evolution-flash 420ms ease-out}
  .stage-evolution-fx strong{position:absolute;bottom:15%;font-size:clamp(24px,3.4vw,58px);letter-spacing:.2em;color:#fff1d0;text-shadow:0 3px 9px #000,0 0 25px #000;background:linear-gradient(90deg,transparent,#07080edb 20%,#07080edb 80%,transparent);padding:18px 70px;animation:stage-evolution-name 2800ms both}
  .stage-evolution-fx i{position:absolute;left:50%;top:43%;width:3px;height:8px;background:#f1e6cf;box-shadow:0 0 12px #fff;opacity:0;animation:stage-evolution-spark 1300ms ease-out var(--delay) both}
  @keyframes stage-evolution-flash{0%{opacity:.65}100%{opacity:0}}
  @keyframes stage-evolution-name{0%,10%{opacity:0;transform:translateY(15px)}30%,80%{opacity:1;transform:translateY(0)}100%{opacity:0}}
  @keyframes stage-evolution-spark{0%{opacity:0;transform:rotate(var(--angle)) translateY(15px)}15%{opacity:1}100%{opacity:0;transform:rotate(var(--angle)) translateY(var(--distance))}}
  .stage-mother{z-index:0}
  .stage-mother,.stage-bridge{mask-image:linear-gradient(90deg,transparent,#000 16px,#000 calc(100% - 16px),transparent),linear-gradient(0deg,transparent,#000 16px,#000 calc(100% - 16px),transparent);mask-composite:intersect}
  .stage-motion{opacity:0;z-index:1;transition:opacity 90ms linear;will-change:opacity}
  .stage-motion.is-visible{opacity:1}
  .stage-motion.stage-patch{mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent),linear-gradient(0deg,transparent,#000 6%,#000 94%,transparent);mask-composite:intersect}
  .stage-motion.stage-skill-overlay{z-index:3;mix-blend-mode:screen;mask-image:radial-gradient(ellipse,#000 35%,transparent 74%)}
  .stage-cinematic-playing .stage-mother{filter:brightness(.3);transition:filter .3s}
  .stage-boss-defeated .stage-mother{filter:brightness(.15) saturate(.55)}
  .stage-motion.stage-full-frame{mask-image:linear-gradient(90deg,transparent,#000 3%,#000 97%,transparent),linear-gradient(0deg,transparent,#000 4%,#000 96%,transparent);mask-composite:intersect}
  /* Boss scenes slide so the boss stands in the middle of the battlefield (left of the altar); full-frame cinematics stay centred. */
  body.desktop-game.desktop-battle .battle-panel:not(.minion-battle) .stage-media{transform:translateX(var(--pgb-scene-shift,0px));transition:transform .6s cubic-bezier(.3,.7,.2,1)}
  body.desktop-game.desktop-battle .battle-panel.stage-cinematic-playing .stage-media{transform:none}
  /* Cinematics play full window: the HUD steps aside (it never receives clicks meanwhile). */
  .stage-cinematic-playing .enemy-info,.stage-cinematic-playing .battle-bottom,.stage-cinematic-playing .enemy-sprites,.stage-cinematic-playing #boss-target,.stage-cinematic-playing .battle-topline{opacity:0;pointer-events:none}
  body.desktop-game:has(.stage-cinematic-playing) .board-panel,body.desktop-game:has(.stage-cinematic-playing) .squad-section,body.desktop-game:has(.stage-cinematic-playing) .turn-result,body.desktop-game:has(.stage-cinematic-playing) #enemy-conditions{opacity:0;pointer-events:none}
  body.desktop-game.desktop-battle:has(.stage-cinematic-playing) .pg-battle :is(.board-panel,.squad-section,.turn-result,#enemy-conditions,.pg-battle-altar,.pg-battle-combo,.pg-battle-layerbanner,.pg-battle-lethal,.pg-battle-reveal:not(.is-defeat)){opacity:0!important;pointer-events:none!important}
  body.desktop-game:has(.stage-cinematic-playing) .pg-battle .pg-battle-pause{opacity:.35}
  .stage-atmosphere{position:absolute;inset:0;z-index:2;overflow:hidden;--mote:#83b8c6;pointer-events:none;background:linear-gradient(90deg,rgba(5,11,15,.22),transparent 14%),linear-gradient(0deg,rgba(1,5,8,.7),transparent 20%,transparent 80%,rgba(1,5,8,.35))}
  .stage-media[data-element=fire] .stage-atmosphere{--mote:#fa994f}
  .stage-media[data-element=wood] .stage-atmosphere{--mote:#b7d27a}
  .stage-media[data-element=light] .stage-atmosphere{--mote:#e2cb8a}
  .stage-media[data-element=dark] .stage-atmosphere{--mote:#c4a1d8}
  .stage-atmosphere:after{content:"";position:absolute;inset:56% -15% -25%;background:radial-gradient(ellipse at 40% 70%,color-mix(in srgb,var(--mote) 8%,transparent),transparent 70%);animation:stage-fog 16s ease-in-out infinite alternate}
  .stage-atmosphere i{position:absolute;left:var(--x);bottom:-15px;width:3px;height:3px;border-radius:50%;background:var(--mote);box-shadow:0 0 10px var(--mote);opacity:0;animation:stage-mote calc(8s + var(--i)*.22s) linear var(--delay) infinite}
  body.desktop-game .stage-cinematic-controls:not([hidden]){position:absolute;display:flex;align-items:center;gap:22px;left:calc(var(--pgb-edge,74px) + 3vw);bottom:35px;z-index:20;color:#f0deb9;letter-spacing:.12em;text-shadow:0 2px 8px #000;font-family:"RuneSerif","Noto Serif SC",serif}
  .stage-cinematic-controls button:not(.uk-btn){padding:10px 16px;border:1px solid #bda37655;background:#0c141ba8;color:#e1d5b7;font:inherit;font-size:13px;cursor:pointer}
  body.desktop-game .battle-stage,body.desktop-game #enemy-targets,body.desktop-game .target-toolbar,body.desktop-game #mechanic-info,body.desktop-game .journey-footer{display:none}
  body.desktop-game:has(.minion-battle) #enemy-conditions,body.desktop-game:has(.stage-boss-defeated) #enemy-conditions,body.desktop-game.desktop-battle:has(.minion-battle) .pg-battle #enemy-conditions,body.desktop-game.desktop-battle:has(.stage-boss-defeated) .pg-battle #enemy-conditions{display:none}
  body.desktop-game .orb{max-width:var(--orb-native-side);max-height:var(--orb-native-side)}
  body.desktop-game .orb-state{background-size:min(100%,var(--orb-overlay-native-side))}
  body.desktop-game .orb-state-image{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;object-fit:contain;z-index:-1;pointer-events:none}

  /* The pillar folds into a slim carved stone edge (cut from the pillar art: carved top, a repeating panel, carved foot — never stretched past its pixels); the pause medallion sits in its top filigree. */
  body.desktop-game.desktop-battle{--pgb-edge:clamp(44px,3vw,64px)}
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"]{--ds-rail:var(--pgb-edge)}
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"] .ds-menu.ds-pillar{width:var(--pgb-edge);box-sizing:border-box;padding:calc(var(--pgb-edge)*1.08) 0 0;gap:clamp(6px,1.4vh,16px);justify-content:flex-start;background:none;border:0;background:url("./assets/pages/battle/edge-top.webp") center top/100% auto no-repeat,url("./assets/pages/battle/edge-bottom.webp") center bottom/100% auto no-repeat,url("./assets/pages/battle/edge-mid.webp") center top/100% auto repeat-y;filter:drop-shadow(5px 0 12px #000c)}
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"] .ds-pillar>.ds-medal{width:100%;min-height:0}
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"] .ds-medal-icon{width:calc(var(--pgb-edge)*.74)}
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"] .ds-medal-label{display:none}
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"] .ds-pillar .ds-dot{left:calc(50% + var(--pgb-edge)*.2);width:9px;height:9px}
  /* Full pages opened over the battle (召唤/图鉴/养成) bring the full pillar and breadcrumb back: battle chrome steps aside. */
  body.desktop-game.desktop-battle:has(#desktop-shell:not([data-screen="battle"])) .pg-battle :is(.pg-battle-plaque,.pg-battle-pause,.pg-battle-combo,.pg-battle-reveal,.pg-battle-layerbanner,.pg-battle-lethal){display:none!important}
  /* The stage plaque (page-battle) replaces 「远征进行中」 in the top bar. */
  body.desktop-game.desktop-battle .desktop-shell[data-screen="battle"] .ds-breadcrumb{visibility:hidden}
  /* Toasts appear over the battlefield, never over the altar. */
  body.desktop-game.desktop-battle .toast{left:var(--pgb-bf-c,50%);bottom:4vh;z-index:40;font-size:14px;background:linear-gradient(180deg,#1c2630f2,#0d151df2);border-color:#d4b47766;color:#f1e3c0}

  body.desktop-game dialog.modal{max-height:calc(100dvh - 96px);border-color:#a7895055;background:linear-gradient(135deg,#192830,#0b141c);box-shadow:0 25px 120px #000c}
  body.desktop-game dialog::backdrop{background:#01070ba8;backdrop-filter:blur(7px)}
  body.desktop-game #collection-dialog[data-section=collection] .summon-actions,body.desktop-game #collection-dialog[data-section=collection] #summon-rates,body.desktop-game #collection-dialog[data-section=collection] [data-train]{display:none}
  body.desktop-game #collection-dialog[data-section=train] .summon-actions,body.desktop-game #collection-dialog[data-section=train] #summon-rates{display:none}
  body.desktop-game #collection-dialog[data-section=summon] [data-train]{display:none}
}
@keyframes stage-mote{0%{transform:translate(0,0);opacity:0}15%{opacity:.65}80%{opacity:.4}100%{transform:translate(calc((var(--i) - 9)*12px),-80vh);opacity:0}}
@keyframes stage-fog{from{transform:translateX(-4%)}to{transform:translateX(5%)}}
@keyframes stage-breathe{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
@media(prefers-reduced-motion:reduce){.stage-atmosphere i,.stage-atmosphere:after,body.desktop-game .enemy-figure{animation:none}.stage-motion{transition:none}body.desktop-game.desktop-battle .battle-panel .stage-media{transition:none}}
/* Procedural boss motions (bosses whose new still has no matching video yet): StageMedia sets data-motion on .stage-media
   and every motion is a CSS animation on the still + its silhouette light (.stage-pm-glow, masked by the boss cut-out).
   Only translate / opacity / short filter pulses — the still is never scaled above its own pixels. */
@media(min-width:1000px){
  .stage-pm-glow{position:absolute;z-index:0;pointer-events:none;opacity:0;background:var(--pm-glow,#ffd9a0);mix-blend-mode:screen;mask-size:100% 100%;-webkit-mask-size:100% 100%;mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat}
  .stage-pm-glow[hidden]{display:none}
  .stage-media[data-element=fire]{--pm-glow:#ff7a2a;--pm-hot:#ffd29a}
  .stage-media[data-element=water]{--pm-glow:#4fb4ff;--pm-hot:#d6f1ff}
  .stage-media[data-element=wood]{--pm-glow:#7fe08a;--pm-hot:#e6ffd8}
  .stage-media[data-element=light]{--pm-glow:#ffd36a;--pm-hot:#fff6d8}
  .stage-media[data-element=dark]{--pm-glow:#b27cff;--pm-hot:#efe2ff}
  .stage-media[data-motion] .stage-mother,.stage-media[data-motion] .stage-pm-glow{will-change:transform,opacity,filter}
  .stage-media[data-motion] .stage-mother,.stage-media[data-motion] .stage-pm-glow{transform-origin:var(--pm-x,50%) 92%}
  /* uifix4: the mask is an inner rim of the silhouette (full source resolution), so the light only catches the outline; the
     rim layer runs the still's own motion first so it stays on the edge, then its light (the later animation owns opacity). */
  .stage-media[data-bleed=short] .stage-mother{mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent),linear-gradient(0deg,transparent,#000 14%,#000);mask-composite:intersect}
  /* idle: the giant breathes — a slow rise and fall and its own light swelling from inside the silhouette */
  .stage-media[data-motion=idle] .stage-mother{animation:stage-pm-breathe 5.6s ease-in-out infinite}
  .stage-media[data-motion=idle] .stage-pm-glow{animation:stage-pm-breathe 5.6s ease-in-out infinite,stage-pm-pulse 5.6s ease-in-out infinite}
  /* hit: recoil shake with a white flash on the body only */
  .stage-media[data-motion=hit] .stage-mother{animation:stage-pm-recoil .62s cubic-bezier(.3,.8,.3,1) both}
  .stage-media[data-motion=hit] .stage-pm-glow{background:var(--pm-hot,#fff);animation:stage-pm-recoil .62s cubic-bezier(.3,.8,.3,1) both,stage-pm-flash .62s ease-out both}
  /* attack: gathers (sinks, darkens), lunges at the party with a burning silhouette, then settles */
  .stage-media[data-motion=attack] .stage-mother{animation:stage-pm-lunge 1.15s cubic-bezier(.4,0,.2,1) both}
  .stage-media[data-motion=attack] .stage-pm-glow{background:var(--pm-hot,#fff);animation:stage-pm-lunge 1.15s cubic-bezier(.4,0,.2,1) both,stage-pm-charge 1.15s ease-in-out both}
  /* intro: rises out of the dark, its light ignites */
  .stage-cinematic-playing .stage-media[data-motion=intro] .stage-mother{animation:stage-pm-rise 2.6s cubic-bezier(.25,.6,.2,1) both}
  .stage-media[data-motion=intro] .stage-pm-glow{animation:stage-pm-ignite 2.6s ease-out both}
  .stage-cinematic-playing .stage-media[data-motion=intro] .stage-pm-glow{animation:stage-pm-rise 2.6s cubic-bezier(.25,.6,.2,1) both,stage-pm-ignite 2.6s ease-out both}
  /* defeat: a last flash, then it sinks and the colour drains (ends on the defeated still) */
  .stage-cinematic-playing .stage-media[data-motion=defeat] .stage-mother{animation:stage-pm-fall 2.8s cubic-bezier(.3,.1,.3,1) both}
  .stage-media[data-motion=defeat] .stage-pm-glow{background:var(--pm-hot,#fff);animation:stage-pm-dying 2.8s ease-out both}
  .stage-cinematic-playing .stage-media[data-motion=defeat] .stage-pm-glow{animation:stage-pm-fall 2.8s cubic-bezier(.3,.1,.3,1) both,stage-pm-dying 2.8s ease-out both}
  .stage-media[data-motion=defeated] .stage-mother{transform:translateY(26px);filter:brightness(.15) saturate(.55)}
  .stage-media[data-motion=defeated] .stage-pm-glow{transform:translateY(26px)}
  /* phase: the king's charge before the evolution cocoon — shaking ever harder until it is white-hot */
  .stage-cinematic-playing .stage-media[data-motion=phase] .stage-mother{animation:stage-pm-charge-up 2.2s ease-in both}
  .stage-media[data-motion=phase] .stage-pm-glow{background:#fff;animation:stage-pm-whiten 2.2s ease-in both}
  .stage-cinematic-playing .stage-media[data-motion=phase] .stage-pm-glow{animation:stage-pm-charge-up 2.2s ease-in both,stage-pm-whiten 2.2s ease-in both}
  @keyframes stage-pm-breathe{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
  @keyframes stage-pm-pulse{0%,100%{opacity:.05}50%{opacity:.26}}
  @keyframes stage-pm-recoil{0%{transform:translate(0,0);filter:none}8%{filter:brightness(1.35)}12%{transform:translate(-11px,4px)}30%{filter:none}26%{transform:translate(9px,-3px)}42%{transform:translate(-6px,2px)}60%{transform:translate(3px,-1px)}100%{transform:translate(0,0)}}
  @keyframes stage-pm-flash{0%{opacity:0}8%{opacity:.6}100%{opacity:0}}
  @keyframes stage-pm-lunge{0%{transform:translateY(0);filter:none}35%{transform:translateY(10px);filter:brightness(.72)}52%{transform:translate(0,-16px);filter:brightness(1.25)}58%{transform:translate(-8px,-12px)}64%{transform:translate(7px,-14px)}72%{transform:translate(-3px,-8px);filter:brightness(1.05)}100%{transform:translateY(0);filter:none}}
  @keyframes stage-pm-charge{0%{opacity:0}35%{opacity:.16}52%{opacity:.55}70%{opacity:.25}100%{opacity:0}}
  @keyframes stage-pm-rise{0%{opacity:0;transform:translateY(34px);filter:brightness(0)}38%{opacity:1;filter:brightness(.28)}68%{filter:brightness(1.3)}82%{transform:translateY(0);filter:brightness(1)}100%{opacity:1;transform:translateY(0);filter:none}}
  @keyframes stage-pm-ignite{0%,45%{opacity:0}66%{opacity:.55}100%{opacity:0}}
  @keyframes stage-pm-fall{0%{transform:translate(0,0);filter:none}5%{transform:translate(-12px,4px);filter:brightness(1.6)}10%{transform:translate(10px,-3px)}16%{transform:translate(-6px,2px);filter:brightness(1.1)}100%{transform:translateY(26px);filter:brightness(.15) saturate(.55)}}
  @keyframes stage-pm-dying{0%{opacity:0}6%{opacity:.45}30%{opacity:.12}100%{opacity:0}}
  @keyframes stage-pm-charge-up{0%{transform:translate(0,0);filter:none}20%{transform:translate(-2px,1px)}30%{transform:translate(2px,-1px)}45%{transform:translate(-4px,2px);filter:brightness(1.15)}55%{transform:translate(4px,-2px)}70%{transform:translate(-6px,3px);filter:brightness(1.4)}80%{transform:translate(6px,-3px)}90%{transform:translate(-7px,2px);filter:brightness(1.8)}100%{transform:translate(0,0);filter:brightness(2)}}
  @keyframes stage-pm-whiten{0%{opacity:0}60%{opacity:.35}100%{opacity:1}}
}
@media(prefers-reduced-motion:reduce){.stage-media[data-motion] .stage-mother,.stage-media[data-motion] .stage-pm-glow{animation:none!important}}
