/* Startseiten-Brett (#heroBoard, app/hero-board.js + hero-board-fx.js +
   hero-board-depth.js): Tiefe, Farbsprache des Spiels und die kleinen Momente.
   Laedt nach home.css und ueberschreibt gezielt main-04/05.
   - Neigung folgt dem Mauszeiger: --hero-rx/--hero-rz setzt hero-board-depth.js.
     Nur der Rahmen ist eine 3D-Ebene; im Inneren gibt es keine 3D-Transformation.
     Die Figuren liegen in der Brettebene und werden passend zur Neigung gestaucht
     (translate/scale aus --hero-rx, ohne Transition: so folgen sie jedem Bild
     sofort, nur das Anheben (transform) gleitet). Das sieht exakt so aus wie die
     fruehere Gegendrehung per rotateX (in einem flachen Elternteil wird sie
     ohnehin plattgedrueckt), braucht aber weder 3D-Sortierung noch eine
     Zwischen-Ebene fuers Gitter: die liess in Chromium bei 150 % Skalierung
     die untere Bretthaelfte beim Neigen verschwinden (Rahmen blieb, Felder und
     Figuren fehlten). Darum auch kein overflow: hidden mehr im Gitter.
   - Jede Figur steht auf einem flachen Bodenschatten in der Brettebene.
   - Zug = Gold, Schlag = Rot: Eckwinkel am letzten Zug, Rahmen behaelt die Farbe,
     Rand-Leuchten + Ruck beim Schlag (Keyframes mpMarkSnap/mpMarkFade/mpEdgeFlash/
     mpImpact aus main-14.css, mpCrystalPulse/mpCrystalCheck aus mana-spend.css). */

/* ── Rahmen folgt der Neigung ── */
.heroBoardFrame {
  transform: rotateX(var(--hero-rx, 38deg)) rotateZ(var(--hero-rz, -3deg));
  /* Flach statt preserve-3d (main-04): kein 3D-Sortierkontext, alles im Rahmen
     ist eine Ebene; Kristalle und Marker zeichnen direkt mit seiner Neigung. */
  transform-style: flat;
  /* Die Neigung aendert die Transformation in jedem Bild: mit will-change behaelt
     der Compositor die gerasterte Ebene und zeichnet sie nicht neu. */
  will-change: transform;
  transition: border-color .7s ease, box-shadow .7s ease;
}
/* Kein Zuschnitt im Gitter (main-04: overflow hidden): Felder und Figuren
   bleiben ohnehin in ihren Kaestchen, und ein Zuschnitt unter der Neigung
   braeuchte wieder eine Zwischen-Ebene. */
.heroBoardGrid,
.heroBoardTile { overflow: visible; }

/* ── Figur: Bodenschatten in der Brettebene, Bild gestaucht wie aufgestellt ── */
.heroBoardPiece::before {
  content: "";
  position: absolute;
  left: 23%;
  right: 23%;
  top: 63%;
  height: 22%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%, rgba(0, 0, 0, .62), rgba(0, 0, 0, .3) 48%, transparent 72%);
  opacity: .8;
  transition: opacity .18s ease, transform .18s ease;
  pointer-events: none;
}
.heroPieceArt {
  position: relative;
  width: 78%;
  height: 78%;
  /* 2D-Bild einer um -rx gekippten Figur mit translateY(-19%) translateZ(8px):
     y' = cos(rx) * y - 19% * cos(rx) + 8px * sin(rx). Ohne Transition, damit
     die Figur der Neigung sofort folgt; nur transform (Anheben) gleitet. */
  translate: 0 calc(-19% * cos(var(--hero-rx, 38deg)) + 8px * sin(var(--hero-rx, 38deg)));
  scale: 1 cos(var(--hero-rx, 38deg));
  transform-origin: center bottom;
  /* Eigene Compositor-Ebene (2D, ohne Zuschnitt): die Stauchung aendert sich mit
     jedem Bild der Neigung, so bleibt der Rahmen unangetastet (kein Neuzeichnen). */
  will-change: transform;
  transition: transform .18s ease, opacity .2s ease;
}
.heroBoardStage .heroBoardPiece img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform: none;
  filter: drop-shadow(0 5px 5px rgba(0, 0, 0, .55));
  transition: filter .18s ease;
}
/* Koenigs-Kristall (render/crystal-flare.js): Maske aus Bild und _leer-Bild,
   hellt nur den Kristall auf, Takt an der Wanduhr. Bei Gefahr rot, 2,4 s. */
.heroPieceArt .crystalPulse {
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  mix-blend-mode: plus-lighter;
  opacity: 0;
  filter: none;
  animation: mpCrystalPulse 4.8s ease-in-out infinite;
  animation-delay: var(--mp-t, 0ms);
  pointer-events: none;
}
.heroBoardPiece.inDanger .crystalPulse {
  mix-blend-mode: normal;
  opacity: 1;
  animation-name: mpCrystalCheck;
  animation-duration: 2.4s;
}
/* Matt: tiefrot, atmet nur noch schwer (mpCrystalMate aus mana-spend.css). */
.heroBoardPiece.isMated .crystalPulse {
  animation-name: mpCrystalMate;
  animation-duration: 4.8s;
}

/* Angehoben (gewaehlt): hoch und mit Luft, der Bodenschatten bleibt klein zurueck.
   Die Zahlen sind das 2D-Bild der frueheren 3D-Werte (translateY -32%, 38px zum
   Betrachter) bei 38 Grad: -13% + 30px * tan(38deg); Hover entsprechend
   -25%/20px: -6% + 12px * tan(38deg). */
.heroBoardPiece.isLifted .heroPieceArt {
  transform: translateY(calc(-13% + 23.44px)) scale(1.07);
}
.heroBoardStage .heroBoardPiece.isLifted img {
  filter:
    drop-shadow(0 26px 16px rgba(0, 0, 0, .82))
    drop-shadow(0 0 12px rgba(77, 208, 196, .55));
}
.heroBoardPiece.isLifted::before { opacity: .35; transform: scale(.72); }
/* Maus ueber eigener Figur, solange man dran ist: sie hebt sich leicht an. */
@media (hover: hover) and (pointer: fine) {
  .heroBoardStage.is-your-turn .heroBoardTile:hover > .heroBoardPiece.ownPiece:not(.isLifted) .heroPieceArt {
    transform: translateY(calc(-6% + 9.38px)) scale(1.02);
  }
  .heroBoardStage.is-your-turn .heroBoardTile:hover > .heroBoardPiece.ownPiece:not(.isLifted)::before { opacity: .55; transform: scale(.86); }
}
.heroBoardStage.is-playable .heroBoardTile { cursor: var(--mp-cur-arrow); }
.heroBoardStage.is-playable.is-your-turn .heroBoardTile:has(> .ownPiece),
.heroBoardStage.is-playable .heroBoardTile.target-move,
.heroBoardStage.is-playable .heroBoardTile.target-capture { cursor: var(--mp-cur-pointer); }

/* Unterwegs (Kopie fliegt) oder gerade geschlagen: das Original ist weg. */
.heroBoardPiece.isMoving,
.heroBoardPiece.isCaptured { opacity: 0; }
.heroBoardStage .heroBoardPiece.isCaptured img { transform: none; opacity: 1; transition: none; }

/* ── Geschlagene Figur: vom Angreifer weggestossen, kippt und versinkt ──
   Geist mit demselben Bild (hero-board-fx.js setzt Richtung und Neigung):
   rutscht ein halbes Feld in Schlagrichtung, kippt nach hinten/vorn und zur
   Seite, verblasst. Faellt sie nach vorn, liegt sie vor dem Angreifer. */
.heroGhost { z-index: 3; transition: translate .5s cubic-bezier(.25, .7, .4, 1); }
.heroGhost.is-front { z-index: 5; }
/* Der Geist traegt seine Stauchung fest fuer 38 Grad in transform, damit das
   Kippen (rotateX/rotateZ aus den Tipp-Werten, plattgedrueckt zu scaleY/rotate)
   in einer Transition ablaeuft, die die Neigung nicht neu startet. */
.heroGhost .heroPieceArt {
  translate: none;
  scale: none;
  transform: translateY(calc(-19% * cos(38deg) + 8px * sin(38deg))) scaleY(cos(38deg));
  transition: transform .5s cubic-bezier(.4, 0, .75, .5), opacity .5s ease-in;
}
.heroGhost::before { transition: opacity .3s ease; }
.heroGhost.is-falling { translate: var(--push-x, 0%) var(--push-y, 0%); }
.heroGhost.is-falling::before { opacity: 0; }
.heroGhost.is-falling .heroPieceArt {
  --tip: calc(var(--tip-x, 0deg) - 38deg);
  transform: translateY(calc(8px * sin(var(--tip)))) scaleY(cos(var(--tip))) rotate(var(--tip-z, 0deg)) translateY(-8%) scale(.92);
  opacity: 0;
}
/* Splitter: Knochen bzw. Holz, klein, nur ueber die Brettebene. */
.heroShard {
  position: absolute;
  z-index: 6;
  border-radius: 1px;
  pointer-events: none;
  will-change: transform, opacity;
}
.heroShard.is-hollow { background: #e9e1cc; box-shadow: inset 0 0 0 .5px rgba(60, 50, 40, .45); }
.heroShard.is-raiders { background: #c08d3e; box-shadow: inset 0 0 0 .5px rgba(40, 24, 8, .5); }

/* ── Letzter Zug: zwei Eckwinkel je Feld (Ziel kraeftig, Start leiser) ── */
.heroMark {
  --mk: rgba(226, 190, 110, .95);
  --mk-len: 28%;
  --mk-w: 2px;
  position: absolute;
  inset: 6%;
  z-index: 5;
  opacity: 0;
  pointer-events: none;
}
.heroBoardTile.last-capture .heroMark { --mk: rgba(240, 108, 108, .95); }
.heroBoardTile.last-to .heroMark {
  opacity: 1;
  filter: drop-shadow(0 0 3px var(--mk));
  background:
    linear-gradient(var(--mk), var(--mk)) right top / var(--mk-len) var(--mk-w) no-repeat,
    linear-gradient(var(--mk), var(--mk)) right top / var(--mk-w) var(--mk-len) no-repeat,
    linear-gradient(var(--mk), var(--mk)) left bottom / var(--mk-len) var(--mk-w) no-repeat,
    linear-gradient(var(--mk), var(--mk)) left bottom / var(--mk-w) var(--mk-len) no-repeat;
}
.heroBoardTile.last-from .heroMark {
  --mk-len: 20%;
  inset: 14%;
  opacity: .55;
  background:
    linear-gradient(var(--mk), var(--mk)) left top / var(--mk-len) var(--mk-w) no-repeat,
    linear-gradient(var(--mk), var(--mk)) left top / var(--mk-w) var(--mk-len) no-repeat,
    linear-gradient(var(--mk), var(--mk)) right bottom / var(--mk-len) var(--mk-w) no-repeat,
    linear-gradient(var(--mk), var(--mk)) right bottom / var(--mk-w) var(--mk-len) no-repeat;
}
.heroBoardTile.last-snap.last-to .heroMark { animation: mpMarkSnap .42s cubic-bezier(.2, 1.5, .4, 1) both; }
.heroBoardTile.last-snap.last-from .heroMark { animation: mpMarkFade .5s ease-out both; }

/* ── Rahmen traegt die Farbe der letzten Aktion, Rand-Leuchten, Ruck ── */
.heroBoardFrame.is-last-move {
  --edge: 226, 190, 110;
  transition: border-color .8s ease-in-out .12s, box-shadow 1s ease-in-out .12s;
}
.heroBoardFrame.is-last-capture {
  --edge: 236, 98, 98;
  transition: border-color .14s ease-out .24s, box-shadow .55s cubic-bezier(.2, .8, .3, 1) .24s;
}
.heroBoardFrame.is-last-move,
.heroBoardFrame.is-last-capture {
  border-color: rgba(var(--edge), .8);
  box-shadow:
    0 80px 120px -20px rgba(0, 0, 0, .95),
    0 30px 60px -10px rgba(0, 0, 0, .7),
    0 0 0 3px #0a0a0a,
    0 0 0 4px rgba(var(--edge), .6),
    0 0 34px rgba(var(--edge), .3),
    inset 0 0 0 1px rgba(var(--edge), .5),
    inset 0 0 80px rgba(0, 0, 0, .55);
}
.heroBoardFrame.is-flash-move    { --flash: 226, 190, 110; }
.heroBoardFrame.is-flash-capture { --flash: 240, 72, 78; }
.heroBoardFrame.is-edgeFlash::after {
  content: "";
  position: absolute;
  inset: -4px;
  z-index: 5;
  pointer-events: none;
  box-shadow:
    0 0 0 2px rgba(var(--flash, 226, 190, 110), .8),
    0 0 42px 4px rgba(var(--flash, 226, 190, 110), .45),
    inset 0 0 24px rgba(var(--flash, 226, 190, 110), .22);
  animation: mpEdgeFlash .9s ease-in-out forwards;
}
.heroBoardFrame.is-impact       { animation: mpImpact .3s cubic-bezier(.2, .8, .3, 1); }
.heroBoardFrame.is-impact-heavy { animation: mpImpact .42s cubic-bezier(.2, .8, .3, 1); }
/* Rote Vignette im Brett beim Schlag: Rand kraeftig, Mitte klar. */
.heroBoardVeil {
  position: absolute;
  inset: 0;
  z-index: 6;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at 50% 50%, transparent 56%, rgba(240, 72, 78, .14) 82%, rgba(240, 72, 78, .32) 100%);
}
.heroBoardVeil.is-on { animation: mpEdgeFlash .75s ease-in-out forwards; }

/* ── Umwandlung: Goldring steigt am Fuss der neuen Dame auf ── */
.heroRing {
  position: absolute;
  left: 50%;
  top: 74%;
  width: 72%;
  height: 72%;
  z-index: 5;
  border: 2px solid rgba(226, 190, 110, .95);
  border-radius: 50%;
  box-shadow: 0 0 8px rgba(226, 190, 110, .55);
  pointer-events: none;
  animation: heroRingUp .7s cubic-bezier(.2, .7, .3, 1) forwards;
}
@keyframes heroRingUp {
  from { transform: translate(-50%, -50%) scale(.3); opacity: 1; }
  to   { transform: translate(-50%, -50%) scale(1.25); opacity: 0; }
}

/* ── Aufmarsch beim Seitenaufruf und Heimkehr der Gefallenen ──
   Hollow steigt aus dem Boden (Wischen von unten), Raiders setzen von oben auf
   und federn. Solange marschiert wird, ruhen Marker, Auswahl und Glanz. */
.heroBoardStage.is-arriving .heroBoardTile::before { animation: none !important; opacity: 0 !important; }
.heroBoardStage.is-arriving .heroBoardTile.selected { box-shadow: none; }
.heroBoardStage.is-arriving .heroBoardPiece.highlight img { animation: none; }
.heroBoardStage.is-arriving .heroBoardPiece { animation: heroPieceIn .5s ease-out var(--arrive, 0ms) both; }
.heroBoardStage.is-arriving .heroBoardPiece::before { animation: heroShadowIn .6s ease-out var(--arrive, 0ms) both; }
.heroBoardStage.is-arriving .heroBoardPiece.is-hollow .heroPieceArt,
.heroBoardPiece.is-returning.is-hollow .heroPieceArt { animation: heroArtRise .72s cubic-bezier(.22, .8, .24, 1) var(--arrive, 0ms) both; }
.heroBoardStage.is-arriving .heroBoardPiece.is-raiders .heroPieceArt,
.heroBoardPiece.is-returning.is-raiders .heroPieceArt { animation: heroArtDrop .64s cubic-bezier(.34, 1.25, .5, 1) var(--arrive, 0ms) both; }
.heroBoardPiece.is-returning { --arrive: 0ms; animation: heroPieceIn .5s ease-out both; }
.heroBoardPiece.is-returning::before { animation: heroShadowIn .6s ease-out both; }
@keyframes heroPieceIn {
  from { opacity: 0; }
  35%  { opacity: 1; }
  to   { opacity: 1; }
}
@keyframes heroShadowIn {
  from { opacity: 0; transform: scale(.55); }
  60%  { opacity: 0; transform: scale(.7); }
  to   { opacity: .8; transform: scale(1); }
}
/* Start- und Endwerte sind das 2D-Bild der frueheren 3D-Wege (4%/-16px bzw.
   -52%/80px) bei 38 Grad: 23% - 24px * tan(38deg) bzw. -33% + 72px * tan(38deg). */
@keyframes heroArtRise {
  from { transform: translateY(calc(23% - 18.75px)) scaleY(.92); clip-path: inset(100% 0 0 0); }
  to   { transform: translateY(0) scaleY(1); clip-path: inset(-10% 0 0 0); }
}
@keyframes heroArtDrop {
  from { transform: translateY(calc(-33% + 56.25px)) scale(1.06); }
  to   { transform: translateY(0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .heroPieceArt .crystalPulse { display: none; }
  .heroMark, .heroBoardFrame, .heroBoardVeil, .heroRing { animation: none !important; }
  .heroBoardPiece.is-returning, .heroBoardPiece.is-returning::before, .heroBoardPiece.is-returning .heroPieceArt { animation: none !important; }
  .heroGhost, .heroGhost .heroPieceArt { transition: none; }
}
