/* ============================================================
   THE HOLOGRAM CARD — black glass, white neon piece, turning for ever.
   Built by holoArt() in js/core.js. See the note there before editing.

   ⚠⚠ THE TRANSFORM AND THE GLOW ARE ON DIFFERENT ELEMENTS ON PURPOSE.
   .holo-spin only ever rotates (compositor work); .holo-sil carries the
   drop-shadow bloom and never moves, so the neon is rasterised once.
   ⚠ NEVER put a `filter` or an `animation` on .holo-spin itself — that is the
   re-rasterise-every-frame fault v0.785 took off the screen transition.
   ============================================================ */
.holo{
  position:absolute; inset:0; overflow:hidden; z-index:1;
  background:#000;                       /* the screen. flat black, no paper, no dots */
  perspective:220px;
  display:flex; align-items:center; justify-content:center;
  --holoGlow:#4fd2ff;                    /* the bloom colour — rarity re-tints it below */
}
.holo i{position:absolute; pointer-events:none; display:block;}
/* the faint projector grid */
.holo-grid{inset:0; opacity:.13;
  background-image:linear-gradient(var(--holoGlow) 1px, transparent 1px),
                   linear-gradient(90deg, var(--holoGlow) 1px, transparent 1px);
  background-size:14px 14px; background-position:center;}
/* scan lines: static stripes, plus ONE bar that drifts down the glass */
.holo-scan{inset:0; opacity:.5; mix-blend-mode:screen;
  background:repeating-linear-gradient(180deg, rgba(255,255,255,.13) 0 1px, transparent 1px 3px);}
.holo-glass{inset:0; z-index:4; mix-blend-mode:screen; opacity:.5;
  background:linear-gradient(180deg, transparent 0 42%, rgba(180,240,255,.5) 48%, rgba(180,240,255,.5) 52%, transparent 58% 100%);
  animation:holoSweep 3.4s linear infinite;}
@keyframes holoSweep{ from{transform:translate3d(0,-100%,0)} to{transform:translate3d(0,100%,0)} }
/* the beam the piece stands on */
.holo-floor{left:12%; right:12%; bottom:6%; height:12%; z-index:2; opacity:.5;
  background:radial-gradient(50% 50% at 50% 50%, var(--holoGlow) 0%, transparent 70%);}
/* ⚠ the axis: what keeps the card from blinking empty when the plane turns edge-on */
.holo-axis{top:12%; bottom:16%; left:50%; width:2px; margin-left:-1px; z-index:2; opacity:.34;
  background:linear-gradient(180deg, transparent, #fff 22%, #fff 78%, transparent);
  box-shadow:0 0 6px var(--holoGlow);}
/* the turn itself */
.holo-spin{position:relative; z-index:3; width:100%; height:100%;
  display:flex; align-items:center; justify-content:center;
  transform-style:flat; will-change:transform;
  animation:holoTurn 5.2s linear infinite;}
@keyframes holoTurn{ from{transform:rotateY(0deg)} to{transform:rotateY(360deg)} }
/* ⭐⭐⭐ v0.814 — THE PIECE MAY TURN ITS BACK; ITS LETTERING MAY NOT.
   (Odaroo, 2026-08-14: "when you put your cards on the field, I see the other cards that are
   mirrored on the enemy's side. If they're mirrored, it's okay, but sometimes they have a letter
   and a number that is also mirrored.")

   ⚠⚠⚠ THIS IS NOT A MIRRORED ENEMY CARD, WHICH IS WHY IT WAS LOOKED FOR IN THE WRONG FILE FIRST.
   `.unit.foe svg{transform:scaleX(-1)}` in css/battle.css is overridden for anything holographic
   (line 84 below) and never runs on a field piece. What is mirrored is the REAR HALF OF THE TURN:
   `holoTurn` sweeps rotateY through a full 360° on a `transform-style:flat` plane, so from 90° to
   270° the viewer is looking at the BACK of the artwork. For a chess knight that is just the piece
   turning round, and Odaroo said so ("if they're mirrored, it's okay"). For the A/K/Q/J of a
   playing card, the number on a pool ball or the value on a chip — all real <text>, painted by
   `hmNum` in js/holo-art.js — it is writing that reads backwards for half of every rotation.

   So the lettering counter-flips for exactly that half, and the piece keeps turning.
   ⚠⚠ IT SNAPS ON `steps`-LIKE KEYFRAME PAIRS AT 25% AND 75%, AND THAT IS WHY IT IS INVISIBLE: 25%
   of the turn is 90°, where the plane is edge-on and has no width on screen. The flip happens at
   the one instant of the cycle in which there is nothing to see. A tween would visibly squash the
   glyphs instead.
   ⚠⚠ THE DURATION IS RESTATED FOR EVERY SIZE OF HOLOGRAM. This animation is a SIBLING of the turn,
   not a child of it, so nothing keeps the two in step automatically — a hologram whose spin runs
   at 4.6s while its text flips on a 5.2s clock has the writing reversed for a moving fraction of
   each turn, which is worse than never flipping at all. Add a duration here for every
   `animation-duration` given to `.holo-spin`.
   ⚠ And wherever the turn is switched OFF the flip must go with it (a still card faces front, so
   there is no back to correct) — see `.card.acard` and the reduced-motion block at the end.

   ⭐⭐⭐ v0.830 — AND NOW THE WHOLE PIECE DOES IT, NOT JUST ITS LETTERING. (Odaroo, 2026-08-14:
   "let them rotate, but always make them face the same direction, like an optical illusion… the
   horses are always looking forward and not turning back, so it looks like everyone is continuing
   in the same direction.")
   ⚠⚠ THIS SUPERSEDES THE TEXT-ONLY RULE ABOVE — do not restore `.holo-sil svg text` from it. The
   counter-flip moved UP one element, from the `<text>` inside the drawing to the `<svg>` that
   holds the drawing, so the art and its lettering turn over together. A knight's head, a queen's
   crown and a pool ball's stripe were all still swapping ends for half of every turn, and eight
   pieces walking a field while half of them faced backwards is the confusion he filmed.
   ⚠⚠ IT IS ON THE `<svg>`, NEVER ON `.holo-sil`. The bloom lives on `.holo-sil` as a
   `drop-shadow` filter, and an animated transform on a filtered element re-rasterises the whole
   bloom every frame — the exact cost the note at the top of this file forbids.
   ⚠ The text must NOT keep a flip of its own: nested inside an svg that already counter-flips it
   would turn twice and read backwards for the half of the turn that used to be correct.
   ⚠ Everything the old rule said still holds: it snaps at 25%/75% (edge-on, nothing to see), the
   duration is a SIBLING of the turn and so is restated for every hologram size, and wherever the
   turn is switched off the flip goes with it. */
@keyframes holoTextFace{
  0%,24.999%{transform:scaleX(1)}
  25%,74.999%{transform:scaleX(-1)}
  75%,100%{transform:scaleX(1)}
}
.holo-sil > svg{transform-origin:center;
  animation:holoTextFace 5.2s linear infinite;}
.holo.mini .holo-sil > svg{animation-duration:4.2s;}
.holo.field .holo-sil > svg{animation-duration:4.6s;}
/* the re-lit piece. the bloom lives here and never moves. */
.holo-sil{width:84%; height:84%; display:flex; align-items:center; justify-content:center;
  filter:drop-shadow(0 0 2px #fff) drop-shadow(0 0 6px var(--holoGlow)) drop-shadow(0 0 13px var(--holoGlow));}
.holo-sil svg{width:100%; height:100%; image-rendering:pixelated;}
/* the rarity carries the bloom — the piece itself stays white on every card */
.card.r2 .holo{--holoGlow:#4fd2ff;}
.card.r3 .holo{--holoGlow:#b98cff;}
.card.r4 .holo{--holoGlow:#ffd24a;}
/* tiny holograms — deck slots, hand carts, drag ghosts: no grid, no sweep, quicker turn */
.holo.mini{perspective:140px;}
.holo.mini .holo-grid,.holo.mini .holo-glass,.holo.mini .holo-floor{display:none;}
.holo.mini .holo-scan{opacity:.34;}
.holo.mini .holo-spin{animation-duration:4.2s;}
.holo.mini .holo-sil{width:88%; height:88%;
  filter:drop-shadow(0 0 1px #fff) drop-shadow(0 0 5px var(--holoGlow));}
/* the big expanded card gets the full projector */
.holo.big .holo-sil{width:74%; height:74%;
  filter:drop-shadow(0 0 3px #fff) drop-shadow(0 0 9px var(--holoGlow)) drop-shadow(0 0 20px var(--holoGlow));}
/* ⭐⭐⭐ THE PROJECTOR WITH ITS GLASS TAKEN OFF — a card standing on the BATTLEFIELD (v0.799).
   Same piece, same re-lighting, same turn as the card face; what goes is everything that was
   only there to say "this is a screen": the black backing, the projector grid, the sweep, the
   scan lines and the beam. The arena has its own floor and its own light, and a black rectangle
   around every fighter would read as a bug.
   ⚠ `overflow:hidden` goes too — the bloom must be allowed to spill past the unit's 64px box.
   ⚠ The AXIS STAYS. It is not decoration here either: edge-on, a flat plane is invisible, and a
   fighter that blinks out of existence twice a turn looks exactly like a rendering fault. */
.holo.field{background:none; overflow:visible; perspective:180px; z-index:1;}
.holo.field .holo-grid,.holo.field .holo-glass,.holo.field .holo-floor,.holo.field .holo-scan{display:none;}
.holo.field .holo-axis{opacity:.22; top:18%; bottom:10%;}
.holo.field .holo-spin{animation-duration:4.6s;}
.holo.field .holo-sil{width:92%; height:92%;
  filter:drop-shadow(0 0 1px #fff) drop-shadow(0 0 4px var(--holoGlow)) drop-shadow(0 0 10px var(--holoGlow));}
/* the rarity bloom follows the card onto the floor (spawnUnit stamps hrN) */
.unit.hr2 .holo{--holoGlow:#4fd2ff;}
.unit.hr3 .holo{--holoGlow:#b98cff;}
.unit.hr4 .holo{--holoGlow:#ffd24a;}
/* ⭐⭐⭐ v0.816 — ON THE BATTLEFIELD, THE COLOUR SAYS WHOSE PIECE IT IS. NOT ITS RARITY.
   (Odaroo, 2026-08-14: "the enemies should be in purple, and the users' inkling cards should
   remain all blue. The enemy ones are going to be pink, like a type of pink-purple.")

   ⚠⚠ THE THREE RULES ABOVE HAD TO BE OVERRIDDEN, NOT EDITED. They are right everywhere a card is
   a CARD — in the hand, in the album, in a pack — where the bloom is how you read a LEGENDARY at
   a glance. They are wrong on the field, where the only question is which side a piece belongs
   to, and where a gold EPIC standing next to a gold EPIC told you nothing at all about who was
   winning. So the field re-tints and nothing else changes: `.unit` only exists on the field.
   ⚠ Specificity is the whole mechanism here — `.unit.foe .holo` (two classes on the unit) beats
   `.unit.hr4 .holo` on source order alone, but stating both anyway would be one more place to
   forget. Do not "simplify" these to `.foe .holo`: `.foe` is used on plenty of things that are
   not pieces on this field.
   ⚠ The rival's pink also drives `.ss-foeline b` in css/battle.css — the rival's turn sign and
   the rival's pieces are deliberately the same colour, so the two read as one player. */
.unit.foe .holo{--holoGlow:#ff5ad0;}                       /* the rival — pink-purple */
.unit:not(.foe) .holo{--holoGlow:#4fd2ff;}                 /* you — blue, always */
/* ⚠ THE UNIT'S OWN SVG RULES MUST NOT REACH INSIDE THE HOLOGRAM. `.unit svg` crops to 78% height
   (right for a sprite sitting on its feet, wrong for a piece centred in a projection) and
   `.unit.foe svg` mirrors it — meaningless on something already turning 360° on its axis, and it
   fights the spin's own transform. */
.unit .holo svg, .unit.foe .holo svg{width:100%; height:100%; transform:none;}
.unit .holo-sil{position:relative;}
.df-face:has(.holo){background:#05121a;}
.df-face.df-f .holo svg{width:100%; height:100%;}
/* ⚠ a hologram fills its window, so the paper card's art box must stop painting paper */
.card .art:has(.holo){background:#000; background-image:none;}
.xc-art:has(.holo){background:#000; background-image:none;}
@media (prefers-reduced-motion:reduce){
  .holo-spin{animation:none; transform:rotateY(-18deg);}
  .holo-glass{animation:none; opacity:.25;}
  /* ⚠ v0.814/v0.830 — the turn is off, so there is no back half to correct; leaving the flip
     running would mirror the whole PIECE on something that is already facing front. */
  .holo-sil > svg{animation:none; transform:none;}
}

/* ============================================================
   ⭐⭐⭐ v0.800 — THE SHELF IS STILL; ONLY THE CARD YOU OPEN TURNS (Odaroo, 2026-08-13)
   ------------------------------------------------------------
   He filmed the album flickering and stalling: "all cards are rotating... let's just
   make them static so they're looking face front, and only when you click on it,
   then you actually see the actual card artwork, like a hologram turning around."

   The album draws every card in the game at once, and each hologram was carrying
   FOUR independent costs — a `rotateY` animation, the sweeping glass bar, a
   `mix-blend-mode:screen` layer over the top, and `will-change:transform`. That
   last pair is what actually stalls a phone: `will-change` promotes every card to
   its own GPU layer, and a `mix-blend-mode` above it forces the whole stack to be
   re-composited every frame — so 37+ promoted layers all blending on every tick.
   One spinning card costs nothing; sixty of them cost the whole frame budget.

   ⚠⚠ SO A STILL CARD MUST GIVE UP THE LAYER, NOT JUST THE ANIMATION. Pausing the
   spin alone (`animation:none`) leaves the promotion and the blending in place and
   the shelf still stutters — that is the fix that looks right and changes nothing.
   ⚠ The AXIS goes with the spin. It exists only so a plane turning edge-on does not
   blink out; face-front there is nothing to hide, and a bar down the middle of a
   still piece just reads as a scratch.
   ⚠ The still card keeps the black glass, the grid and the scan lines — the look is
   unchanged, it is only holding its pose. `openCard()` is where it turns.
   ============================================================ */
.card.acard .holo-spin{animation:none; transform:none; will-change:auto;}
.card.acard .holo-sil > svg{animation:none; transform:none;}   /* v0.814/v0.830 — still card, no back half */
.card.acard .holo-glass{display:none;}
.card.acard .holo-axis{display:none;}
.card.acard .holo-scan{mix-blend-mode:normal; opacity:.28;}
.card.acard .holo-sil{filter:drop-shadow(0 0 2px #fff) drop-shadow(0 0 6px var(--holoGlow));}
