/* Lebendiges Brett: die Figuren ruhen nie ganz (Schalter "Lebendiges Brett" im
   Zahnrad, game-settings.js; aus = #boardWrap.mp-lifeOff, gesetzt in
   board-turn-cues.js). Raiders wiegen sich wie Schiffe vor Anker, Hollow schwebt
   einen Hauch ueber dem Boden, Classic bleibt Stein und zeigt nur selten einen
   Glanz auf der Silhouette. Den Rahmen-Glanz hat board-light.css.
   Takt: alles haengt an der Wanduhr wie der Koenigskristall (4,8 s; Seelenfunken
   mit eigenem Takt je Funke). Das Brett
   baut die Chips beim Hover neu; data-anim-period am Bild bzw. an den Spans
   (render/board-idle.js) laesst render/anim-clock.js --mp-t setzen, die Phase
   bleibt. Nie am Chip selbst animieren: dort liegen Anheben und Absetzen
   (.selected/.chipSettle, main-14).
   Alles ist an #board gebunden: Drag-Geist (body), Effekt-Geister (#boardFxLayer)
   und Aufmarsch (.mpIntro) tragen dieselben Klassen und sollen stillstehen.
   :where() haelt die Spezifitaet niedrig, damit Schach/Matt (mana-spend.css,
   spaeter geladen) und die Auswahl-Regeln weiter gewinnen. */

/* Amplitude: wer am Zug ist, lebt voll; die wartende Seite ruht mit 45 %, die
   Armee eines Koenigs im Schach atmet flacher (55 %). Registriert, damit der
   Wechsel am Feld weich ueberblendet (das Feld bleibt ueber Renders bestehen,
   der Chip nicht). */
@property --idle-amp {
  syntax: '<number>';
  inherits: true;
  initial-value: 1;
}
#board .sq { transition: --idle-amp .9s ease; }
:where(#boardWrap[data-turn="w"]) #board .sq:has(> .chip.b),
:where(#boardWrap[data-turn="b"]) #board .sq:has(> .chip.w) { --idle-amp: .45; }

/* Spaltenphase: die Mitte (d/e) zuerst, der Rand (a/h) 480 ms spaeter, so laeuft
   die Duenung von der Mitte nach aussen ueber die Reihe. #board enthaelt nur die
   64 Felder (render/board.js). */
#board .sq:nth-child(8n+4), #board .sq:nth-child(8n+5) { --sq-off: 0; }
#board .sq:nth-child(8n+3), #board .sq:nth-child(8n+6) { --sq-off: 1; }
#board .sq:nth-child(8n+2), #board .sq:nth-child(8n+7) { --sq-off: 2; }
#board .sq:nth-child(8n+1), #board .sq:nth-child(8n+8) { --sq-off: 3; }
/* Verzoegerung: Wanduhr + Spaltenversatz, minus eine Periode, damit sie nie
   positiv wird (sonst stuende ein neu gebauter Chip kurz still). Am Element
   selbst gerechnet, denn --mp-t steht dort inline (anim-clock.js), nicht am Feld. */
#board .chip .pieceAsset,
#board .chip .crystalPulse,
#board .chip .crystalCast,
#board .chip .idleWake {
  --idle-delay: calc(var(--mp-t, 0ms) + var(--sq-off, 0) * 160ms - 4800ms);
}
/* Seelenfunken haben eigenen Takt und eigene Phase (render/board-idle.js);
   --mp-t kommt dort aus demselben Takt (data-anim-period je Funke). Zwei
   Perioden abziehen: nie positiv. */
#board .chip .idleMote {
  --mote-delay: calc(var(--mp-t, 0ms) - var(--mote-phase, 0ms) - var(--mote-period, 4800ms) * 2);
}
#board .chip .idleSheen {
  --sheen-delay: calc(var(--mp-t, 0ms) + var(--sq-off, 0) * 220ms - 9600ms);
}

/* Ausserhalb des Bretts (Geister per cloneNode) gibt es die Ebenen nicht. */
.chip .idleWake, .chip .idleMote, .chip .idleSheen { display: none; }

/* ── Raiders auf Duenung ───────────────────────────────────────────────── */
/* (Die Wisch-Kopie .crystalFrom behaelt ihre eigene Animation: mana-spend.css,
   gleiche Spezifitaet, spaeter geladen.) */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-pirate .pieceAsset {
  transform-origin: 50% 90%;
  animation: mpIdleSway 4800ms ease-in-out infinite;
  animation-delay: var(--idle-delay);
}
/* Der Kristall des Kapitaens liegt als eigene Ebene auf dem Bild (mana-spend.css)
   und muss dieselbe Bewegung mitmachen, sonst entsteht ein Geisterbild. */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-pirate .crystalPulse {
  transform-origin: 50% 90%;
  animation: mpCrystalPulse 4.8s ease-in-out infinite, mpIdleSway 4800ms ease-in-out infinite;
  animation-delay: var(--mp-t, 0ms), var(--idle-delay);
}
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-pirate.auraTouched-debuff .crystalPulse {
  animation-name: mpCrystalPulseDebuff, mpIdleSway;
}
/* Ebenso das Aufleuchten beim Wirken (render/crystal-cast.js): die Huelle schaukelt
   mit, das Leuchten darin hat seine eigene Uhr. */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-pirate .crystalCast {
  transform-origin: 50% 90%;
  animation: mpIdleSway 4800ms ease-in-out infinite;
  animation-delay: var(--idle-delay);
}
@keyframes mpIdleSway {
  0%, 100% { rotate: calc(var(--idle-amp, 1) * -1.1deg); translate: 0 0; }
  25%      { translate: 0 calc(var(--idle-amp, 1) * -1.2%); }
  50%      { rotate: calc(var(--idle-amp, 1) * 1.1deg); translate: 0 0; }
  75%      { translate: 0 calc(var(--idle-amp, 1) * -1.2%); }
}
/* Wellenring am Fuss: scharfe Linie, kein Schein; laeuft im Tiefpunkt des
   Schaukelns aus (0 % = Figur unten). Liegt hinter der Figur (z -1 im Chip). */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip .idleWake {
  display: block;
  position: absolute;
  left: 50%;
  bottom: 2%;
  width: 56%;
  height: 16%;
  z-index: -1;
  pointer-events: none;
  translate: -50% 0;
  border-radius: 50%;
  border: 1.5px solid rgba(186, 236, 255, .75);
  opacity: 0;
  animation: mpIdleWake 4800ms ease-out infinite;
  animation-delay: var(--idle-delay);
}
@keyframes mpIdleWake {
  0%   { scale: .7;  opacity: 0; }
  10%  { opacity: calc(var(--idle-amp, 1) * .7); }
  55%  { scale: 1.12; opacity: 0; }
  100% { scale: 1.12; opacity: 0; }
}

/* ── Hollow schwebt im Seelennebel ─────────────────────────────────────── */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-zombie .pieceAsset {
  transform-origin: 50% 90%;
  animation: mpIdleFloat 4800ms ease-in-out infinite;
  animation-delay: var(--idle-delay);
}
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-zombie .crystalPulse {
  transform-origin: 50% 90%;
  animation: mpCrystalPulse 4.8s ease-in-out infinite, mpIdleFloat 4800ms ease-in-out infinite;
  animation-delay: var(--mp-t, 0ms), var(--idle-delay);
}
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-zombie.auraTouched-debuff .crystalPulse {
  animation-name: mpCrystalPulseDebuff, mpIdleFloat;
}
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.deck-zombie .crystalCast {
  transform-origin: 50% 90%;
  animation: mpIdleFloat 4800ms ease-in-out infinite;
  animation-delay: var(--idle-delay);
}
@keyframes mpIdleFloat {
  0%, 100% { translate: 0 0; scale: 1; }
  50%      { translate: 0 calc(var(--idle-amp, 1) * -2%); scale: calc(1 + var(--idle-amp, 1) * .01); }
}
/* Ein bis drei Seelenfunken steigen hinter dem Sockel auf (z -1: sichtbar nur, wo
   die Figur sie freigibt). Der Span ist die Laufstrecke (Breite 20 % der Figur,
   Hoehe = Steighoehe), der Punkt sitzt mittig an seinem unteren Ende: translate
   in Prozent heisst Steigen um die Strecke und Drift um Bruchteile der Breite.
   Stelle, Drift, Hoehe, Groesse, Takt, Phase und Helligkeit je Funke aus
   render/board-idle.js, damit keine zwei Figuren gleich funkeln. Harte Kanten
   (Rand in der Hollow-Deckfarbe, weisser Kern), kein Schein. */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip .idleMote {
  display: block;
  position: absolute;
  left: calc(var(--mote-x, 50%) - 10%);
  bottom: 8%;
  width: 20%;
  height: var(--mote-h, 34%);
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  /* linear: die Zwischenpunkte des Schlangenwegs tragen translate, mit ease-in
     bremste der Funke an jedem Zwischenpunkt auf null und stockte zweimal. */
  animation: mpIdleMote var(--mote-period, 4800ms) linear infinite;
  animation-delay: var(--mote-delay);
}
#board .chip .idleMote::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: var(--mote-size, 3px);
  height: var(--mote-size, 3px);
  margin-left: calc(var(--mote-size, 3px) / -2);
  box-sizing: border-box;
  border-radius: 50%;
  background: #e8fff8;
  border: 1px solid rgba(0, 230, 168, .95);
}
/* Leichter Schlangenweg: erst zur Seite, zurueck, am Ende weiter hinaus. */
@keyframes mpIdleMote {
  0%   { translate: 0 0; opacity: 0; }
  15%  { opacity: calc(var(--idle-amp, 1) * var(--mote-peak, .8)); }
  45%  { translate: calc(var(--mote-dx, 0%) * .75) -45%; }
  75%  { translate: calc(var(--mote-dx, 0%) * .35) -75%; opacity: calc(var(--idle-amp, 1) * var(--mote-peak, .8) * .75); }
  100% { translate: var(--mote-dx, 0%) -100%; opacity: 0; }
}

/* ── Classic: Glanz wandert ueber die Silhouette ───────────────────────── */
/* Stein bewegt sich nicht, nur das Licht lebt: alle 9,6 s ein schmaler, scharfer
   Streifen, per Maske (inline, render/board-idle.js: dieselbe Bilddatei) exakt auf
   die Silhouette beschnitten. Geometrie wie .crystalPulse (mana-spend.css). Den
   Rest der Periode steht der Streifen ausserhalb der Maske. */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip .idleSheen {
  display: block;
  position: absolute;
  inset: -6%;
  width: 112%;
  height: 112%;
  pointer-events: none;
  -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;
  background: linear-gradient(112deg,
    transparent 44%, rgba(255, 250, 230, .5) 49%, #fff 50%, rgba(255, 250, 230, .5) 51%, transparent 56%) no-repeat;
  background-size: 320% 100%;
  opacity: calc(var(--idle-amp, 1) * .45);
  animation: mpIdleSheen 9600ms linear infinite;
  animation-delay: var(--sheen-delay);
}
/* Dunkle Figuren vertragen mehr Licht. */
:where(#boardWrap:not(.mp-lifeOff)) #board .chip.b .idleSheen { opacity: calc(var(--idle-amp, 1) * .7); }
@keyframes mpIdleSheen {
  0%    { background-position: 115% 0; }
  11.5% { background-position: -15% 0; }
  100%  { background-position: -15% 0; }
}

/* ── Ringe und Funken weichen, wo schon ein Ring am Fuss liegt ─────────── */
#board .chip.auraTouched .idleWake,
#board .sq.selected .idleWake,
#board .sq.chipSettle .idleWake,
#board .sq.pickCandidate .idleWake,
#board .sq.actionSourceTarget .idleWake { display: none; }

/* ── Im Schach haelt der Koenig den Atem an ────────────────────────────── */
/* Der bedrohte Koenig erstarrt (sein Kristall pulsiert rot weiter, mana-spend.css
   gewinnt dort); seine Armee wechselt in den 2,4-s-Takt des Schach-Rings mit
   halber Amplitude. Phasensicher, weil 4800 = 2 x 2400 und alle Delays aus
   derselben Uhr kommen. Matt: dasselbe Erstarren. */
#board .sq.kingInCheck .chip .pieceAsset,
#board .sq.kingMated .chip .pieceAsset,
#board .sq.kingInCheck .chip .crystalCast,
#board .sq.kingMated .chip .crystalCast,
#board .sq.kingInCheck .chip .idleWake,
#board .sq.kingMated .chip .idleWake,
#board .sq.kingInCheck .chip .idleMote,
#board .sq.kingMated .chip .idleMote,
#board .sq.kingInCheck .chip .idleSheen,
#board .sq.kingMated .chip .idleSheen { animation: none; }
#board.mp-check-w .sq:has(> .chip.w),
#board.mp-check-b .sq:has(> .chip.b) { --idle-amp: .55; }
#board.mp-check-w .sq:has(> .chip.w) :is(.pieceAsset, .crystalPulse, .crystalCast, .idleWake),
#board.mp-check-b .sq:has(> .chip.b) :is(.pieceAsset, .crystalPulse, .crystalCast, .idleWake) {
  animation-duration: 2400ms;
}
/* Funken steigen im Schach doppelt so schnell; halber eigener Takt bleibt
   phasensicher zur Uhr (Periode = 2 x halbe Periode). */
#board.mp-check-w .sq:has(> .chip.w) .idleMote,
#board.mp-check-b .sq:has(> .chip.b) .idleMote { animation-duration: calc(var(--mote-period, 4800ms) / 2); }
#board.mp-check-w .sq:has(> .chip.w) .idleSheen,
#board.mp-check-b .sq:has(> .chip.b) .idleSheen { animation-duration: 4800ms; }

/* ── Handy: nur die Bewegung, keine Ringe und Funken (GPU-Dauerlast) ───── */
body.mp-phone #board .idleWake,
body.mp-phone #board .idleMote,
body.mp-phone #board .idleSheen { display: none; }

/* Keine Dauerbewegung; den Kristall blendet mana-spend.css dort ohnehin aus. */
@media (prefers-reduced-motion: reduce) {
  #board .chip.deck-pirate .pieceAsset,
  #board .chip.deck-zombie .pieceAsset,
  #board .chip .crystalCast { animation: none; }
  #board .chip .idleWake,
  #board .chip .idleMote,
  #board .chip .idleSheen { display: none; }
}
