/* Shared desktop companion presentation. Each pet owns its artwork and its
   movement controller; the site physics integrator owns this 96px body. */
body .desktop-site-pet {
  position: absolute;
  top: 0;
  left: 0;
  bottom: auto;
  width: 96px;
  height: 96px;
  z-index: 85;
  padding: 0;
  border: 0;
  background-color: transparent;
  background-repeat: no-repeat;
  background-size: 400% 400%;
  image-rendering: auto;
  cursor: grab;
  touch-action: none;
  user-select: none;
  filter: drop-shadow(0 6px 7px rgba(0,0,0,.45));
  transition: none;
}
body .desktop-site-pet.is-dragging {
  z-index: 87;
  cursor: grabbing;
  filter: drop-shadow(0 10px 9px rgba(0,0,0,.55));
}
/* Evolution changes only the artwork presentation. The page-body transform,
   convex hull and saved position remain owned by script.js. */
body .desktop-site-pet[data-pet-species="zub"].zub-evolving {
  z-index: 89;
  pointer-events: none;
  will-change: filter, translate;
  animation: zub-evolution-light 1.38s ease-in-out both;
}
body .desktop-site-pet[data-pet-species="zub"].zub-evolving::before {
  content: "";
  position: absolute;
  inset: -16px;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
    rgba(255,255,255,.98) 0%, rgba(244,254,255,.75) 31%,
    rgba(166,232,255,.3) 55%, transparent 73%);
  mix-blend-mode: screen;
  animation: zub-evolution-aura 1.38s ease-out both;
}
@keyframes zub-evolution-light {
  0% { filter: brightness(1) drop-shadow(0 5px 7px rgba(0,0,0,.4)); translate: 0 0; }
  18% { filter: brightness(2) drop-shadow(0 0 9px rgba(255,255,255,.9)); translate: 0 -2px; }
  34% { filter: brightness(0) invert(1) drop-shadow(0 0 13px white) drop-shadow(0 0 20px rgba(175,244,255,.95)); translate: 0 -5px; }
  47% { filter: brightness(2.5) drop-shadow(0 0 15px white) drop-shadow(0 0 26px rgba(190,245,255,.9)); translate: 0 -7px; }
  58% { filter: brightness(0) invert(1) drop-shadow(0 0 17px white) drop-shadow(0 0 32px rgba(184,247,255,.95)); translate: 0 -8px; }
  72% { filter: brightness(2.4) drop-shadow(0 0 17px white) drop-shadow(0 0 26px rgba(184,247,255,.9)); translate: 0 -5px; }
  86% { filter: brightness(1.4) drop-shadow(0 0 14px rgba(224,255,255,.9)); translate: 0 -2px; }
  100% { filter: drop-shadow(0 6px 7px rgba(0,0,0,.45)); translate: 0 0; }
}
@keyframes zub-evolution-aura {
  0% { opacity: 0; scale: .65; }
  22% { opacity: .36; scale: .95; }
  48% { opacity: .9; scale: 1.12; }
  70% { opacity: .95; scale: 1.25; }
  100% { opacity: 0; scale: 1.43; }
}
@media (prefers-reduced-motion: reduce) {
  body .desktop-site-pet[data-pet-species="zub"].zub-evolving,
  body .desktop-site-pet[data-pet-species="zub"].zub-evolving::before {
    animation: none;
  }
}
body .desktop-site-pet[data-pet-species="zub"].zub-loved::after {
  content: "♥";
  position: absolute;
  top: -13px;
  right: 4px;
  color: #ff82b2;
  font-size: 24px;
  pointer-events: none;
  animation: zub-heart 1.3s ease-out both;
}
/* Each deliberate completed pet displays the stage's care progress. */
body .desktop-site-pet[data-pet-species="zub"].zub-loved[data-zub-care]::after {
  content: "♥ " attr(data-zub-care);
  font-size: 17px;
  font-weight: 700;
  white-space: nowrap;
  right: -8px;
  text-shadow: 0 1px 5px rgba(0,0,0,.8);
}
@keyframes zub-heart {
  from { opacity: 0; translate: 0 6px; scale: .7; }
  30% { opacity: 1; }
  to { opacity: 0; translate: 0 -19px; scale: 1.15; }
}
@media (prefers-reduced-motion: reduce) {
  body .desktop-site-pet[data-pet-species="zub"].zub-loved::after { animation: none; opacity: 1; }
}

/* Critter-specific holographic shell. Layering is
   deliberate: frame-0 ball above sprite art; affection ::after stays above both.
   Only presentation changes: the 76.8px physics circle remains untouched. */
body .desktop-site-pet[data-pet-species="critter"] {
  background-image: none !important;
  isolation: isolate;
}
body .desktop-site-pet[data-pet-species="critter"]::before {
  content: "";
  position: absolute;
  inset: 10%;
  z-index: 2;
  pointer-events: none;
  background: url("/assets/images/desktop-pet-critter.png?v=6b7f962") 0 0 / 400% 400% no-repeat;
  opacity: 0.42;
  mix-blend-mode: lighten;
  transform-origin: center;
  transform: rotate(var(--critter-ball-angle, 0deg));
  filter:
    saturate(1.2)
    brightness(1.04)
    drop-shadow(0 0 4px rgba(255, 199, 84, 0.58))
    drop-shadow(0 0 10px rgba(255, 132, 32, 0.44));
}
/* 72% inner artwork (10% smaller than the former 80%); the shell above
   remains inset 10%, so its diameter and physical contact never change. */
body [data-pet-species="critter"] .critter-character {
  position: absolute;
  inset: 14%;
  z-index: 1;
  pointer-events: none;
  background-repeat: no-repeat;
  background-size: 400% 400%;
  image-rendering: auto;
  transform-origin: 50% 65%;
  transform: translateX(var(--critter-gaze,0px)) scale(var(--critter-pose-scale,1)) scaleX(var(--critter-face,1)) rotate(var(--critter-tilt,0deg));
  transition: transform 160ms ease-out;
}
/* Row-two atlas expressions replace the entire inner character frame.
   No pseudo-element icons: the hamster shell stays concentric above it. */
@media (prefers-reduced-motion:reduce) {
  body [data-pet-species="critter"] .critter-character { transition:none; }
}

/* The speech bubble stays on Zub's facing side: the shared body mirrors
   it when facing left, then this child counter-mirrors its lettering only.
   This also overrides the normal care-heart while feeding is playing. */
body .desktop-site-pet[data-pet-species="zub"].pet-fed::after,
body .desktop-site-pet[data-pet-species="zub"].pet-fed.zub-loved[data-zub-care]::after {
  content: attr(data-feed-label);
  position: absolute;
  top: -24px;
  right: -21px;
  z-index: 3;
  color: #ffcb82;
  font-size: 14px;
  font-weight: 900;
  line-height: 1.2;
  white-space: nowrap;
  pointer-events: none;
  text-shadow: 0 1px 5px rgba(0,0,0,.9), 0 0 8px rgba(255,163,53,.65);
  transform: scaleX(var(--zub-nom-unmirror, 1));
  transform-origin: center;
  animation: zub-nom-sequence 1.28s ease-out both;
}
@keyframes zub-nom-sequence {
  0% { opacity: 0; translate: 0 8px; scale: .55; }
  12% { opacity: 1; translate: 0 -4px; scale: 1.18; }
  24% { translate: 0 -1px; scale: .94; }
  37% { translate: 0 -6px; scale: 1.14; }
  48% { translate: 0 -2px; scale: .98; }
  61% { translate: 0 -8px; scale: 1.16; }
  75% { opacity: 1; translate: 0 -7px; scale: 1; }
  100% { opacity: 0; translate: 0 -19px; scale: .88; }
}
@media (prefers-reduced-motion: reduce) {
  body .desktop-site-pet[data-pet-species="zub"].pet-fed::after,
  body .desktop-site-pet[data-pet-species="zub"].pet-fed.zub-loved[data-zub-care]::after {
    animation: none;
    opacity: 1;
  }
}

/* A held edible glows while the player keeps it inside Zub's feeding area.
   Removing the food before the hold completes cancels the interaction. */
body .home-page-object-loot.is-feeding-zub {
  filter: drop-shadow(0 0 7px rgba(255, 194, 88, .9));
}

/* Affection stays legible outside the translucent rolling shell. */
body .desktop-site-pet[data-pet-species="critter"].critter-petting::after {
  content: "♥";
  position: absolute;
  z-index: 4;
  top: -14px;
  left: 50%;
  font-size: 22px;
  line-height: 1;
  color: #ff9ac4;
  text-shadow: 0 0 6px rgba(255, 115, 172, .85);
  pointer-events: none;
  animation: critter-affection 1.6s ease-out both;
}
@keyframes critter-affection {
  0% { opacity: 0; translate: -50% 8px; scale: .7; }
  16% { opacity: 1; translate: -50% -4px; scale: 1.25; }
  55% { opacity: 1; translate: -50% -12px; scale: 1; }
  100% { opacity: 0; translate: -50% -25px; scale: 1.15; }
}
@media (prefers-reduced-motion: reduce) {
  body .desktop-site-pet[data-pet-species="critter"].critter-petting::after {
    animation: none;
    opacity: 1;
  }
}

/* Voidling: the same 96px document-physics body and exact 4x4 atlas. */
body .desktop-site-pet[data-pet-species="voidling"] {
  background-image: url("/assets/images/pet_voidling.png");
  background-size: 400% 400%;
  background-repeat: no-repeat;
  cursor: grab;
  filter: drop-shadow(0 0 7px rgba(127, 42, 219, .48));
}
/* Grow the rendered creature around its centre without resizing the physics
   body's authored 96px world dimensions. */
body .desktop-site-pet[data-pet-species="voidling"] {
  transform-origin: 50% 50%;
}
body .desktop-site-pet[data-pet-species="voidling"].voidling-crystallizing {
  pointer-events: none;
  cursor: default;
}
body .desktop-site-pet[data-pet-species="voidling"].voidling-crystal-flash {
  animation: voidling-white-crystallize 360ms ease-out both;
}
@keyframes voidling-white-crystallize {
  0% { filter: brightness(1) drop-shadow(0 0 7px rgba(127,42,219,.48)); }
  24%, 53% { filter: brightness(0) invert(1) drop-shadow(0 0 20px #fff); }
  75% { filter: brightness(2.7) saturate(0) drop-shadow(0 0 14px #fff); }
  100% { filter: brightness(1) drop-shadow(0 0 7px rgba(127,42,219,.48)); }
}
@media (prefers-reduced-motion: reduce) {
  body .desktop-site-pet[data-pet-species="voidling"].voidling-crystal-flash {
    animation: none;
  }
}
body .desktop-site-pet[data-pet-species="voidling"].voidling-awake { cursor: grab; }
body .desktop-site-pet[data-pet-species="voidling"].voidling-hidden {
  opacity: 0;
  pointer-events: none;
}
body .desktop-site-pet[data-pet-species="voidling"].voidling-annoyed {
  filter: drop-shadow(0 0 14px rgba(189, 67, 245, .9));
}
body .voidling-crystal-shard {
  background-repeat: no-repeat !important;
  image-rendering: auto;
  filter: drop-shadow(0 0 5px rgba(165, 65, 255, .75));
}
body .voidling-particle {
  position: absolute;
  width: var(--void-size, 5px);
  height: var(--void-size, 5px);
  /* The page-home objects are z:10, other pages z:85. Stay underneath
     the actual Voidling body at either scene stacking level. */
  z-index: 8;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle at 40% 32%, rgba(125,63,177,.72),
    rgba(53,20,91,.6) 56%, transparent 80%);
  box-shadow: 0 0 5px rgba(113, 40, 180, .34);
  animation: voidling-particle-out var(--void-time, 780ms) ease-out forwards;
}
@keyframes voidling-particle-out {
  0% { opacity: .85; transform: translate(0, 0) scale(1); }
  100% { opacity: 0; transform: translate(var(--void-x, 0px), var(--void-y, -38px)) scale(.08); }
}
body .voidling-grab-hand {
  position: absolute;
  z-index: 90;
  pointer-events: none;
  width: 96px;
  height: 96px;
  background: url("/assets/images/pet_voidling.png") 100% 33.333333% / 400% 400% no-repeat;
  filter: drop-shadow(0 0 9px #8d37e8);
  transform: translate3d(0, 0, 0) scale(.75);
}
@media (prefers-reduced-motion: reduce) {
  body .voidling-particle { animation-duration: 80ms; }
}

/* Crystal impacts are not generic crate splinters. The four solid shard
   quadrants use pet_voidling.png cell 2; this layered FX supplies a smoky
   vacuum shockwave and violet fracture motes, behind the physical crystal. */
body .voidling-crystal-break {
  position: absolute;
  z-index: 9;
  width: 0;
  height: 0;
  pointer-events: none;
}
body .voidling-crystal-break::before,
body .voidling-crystal-break::after {
  content: "";
  position: absolute;
  left: 0; top: 0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
body .voidling-crystal-break::before {
  width: 24px; height: 24px;
  background: radial-gradient(circle, rgba(20,3,39,.92) 10%,
    rgba(92,27,131,.8) 38%, rgba(118,43,174,.24) 59%, transparent 75%);
  box-shadow: 0 0 13px rgba(105,42,165,.38);
  animation: voidling-crystal-rift 750ms ease-out forwards;
}
body .voidling-crystal-break::after {
  width: 10px; height: 10px;
  border: 2px solid rgba(147,66,204,.66);
  box-shadow: 0 0 8px rgba(75,20,135,.48);
  animation: voidling-crystal-ring 750ms ease-out forwards;
}
body .voidling-crystal-break.is-shattering::before,
body .voidling-crystal-break.is-shattering::after {
  animation-duration: 930ms;
}
body .voidling-crystal-break > i {
  position: absolute;
  left: 0; top: 0;
  width: 9px; height: 9px;
  border-radius: 44% 56% 67% 33%;
  background: radial-gradient(circle, rgba(108,41,164,.82), rgba(32,7,67,.7) 52%, transparent 82%);
  box-shadow: 0 0 4px rgba(107,39,159,.35);
  opacity: 0;
  animation: voidling-crystal-smoke 860ms ease-out var(--rift-delay,0ms) forwards;
}
@keyframes voidling-crystal-rift {
  0% { opacity: .95; transform: translate(-50%,-50%) scale(.35); }
  38% { opacity: .82; transform: translate(-50%,-50%) scale(3.2); }
  100% { opacity: 0; transform: translate(-50%,-50%) scale(5.8); }
}
@keyframes voidling-crystal-ring {
  0% { opacity: .9; transform: translate(-50%,-50%) scale(.3); }
  100% { opacity: 0; transform: translate(-50%,-50%) scale(9); }
}
@keyframes voidling-crystal-smoke {
  0% { opacity: 0; transform: translate(-50%,-50%) scale(.45); }
  20% { opacity: .87; }
  100% { opacity: 0; transform: translate(
    calc(-50% + var(--rift-x,0px)), calc(-50% + var(--rift-y,0px))) scale(2.6); }
}
@media (prefers-reduced-motion: reduce) {
  body .voidling-crystal-break::before,
  body .voidling-crystal-break::after,
  body .voidling-crystal-break > i { animation-duration: 90ms; }
}

/* The physical crystal chips remain violet even when later impacts destroy
   or trim them. Never reuse the ordinary crate's blue/orange sparks. */
body .home-destruction-burst-void .home-destruction-flash {
  width: 19px; height: 19px;
  border-color: rgba(136,49,205,.74);
  background: radial-gradient(circle, rgba(15,2,37,.86), rgba(81,25,136,.42) 55%, transparent);
  box-shadow: 0 0 12px rgba(85,23,147,.49), inset 0 0 9px rgba(29,3,69,.62);
}
body .home-destruction-burst-void .home-destruction-chip,
body .home-destruction-burst-void .home-destruction-chip:nth-child(3n),
body .home-destruction-burst-void .home-destruction-chip:nth-child(4n) {
  background: rgba(92,37,149,.78);
  box-shadow: 0 0 5px rgba(96,34,161,.48);
}

/* Homepage companions live above every authored page surface. Keep only
   sticky site chrome above the document-space physics layer. */
body.page-home .home-presence-physics-layer {
  z-index: 90 !important;
}
body.page-home .site-message-stack {
  z-index: 101;
}
body.page-home .topbar {
  z-index: 102;
}
