/* 枫叶小助手: the Minecraft-style desk pet. Everything here is positioned from pet.js's
   fixed-size stage (190 x 250 css px); the figure's soles sit on the stage's bottom edge. */
.pet-root,
.pet-recall {
  /* The blog page zooms its own html element by 0.9 (--page-zoom), which scales every length below it -
     including this one, whose position and hit-testing are all computed in viewport px. Cancelling the
     page zoom here keeps one set of numbers working on both pages; the property is 1 everywhere else. */
  zoom: calc(1 / var(--page-zoom, 1));
}
.pet-root {
  position: fixed;
  left: 0;
  top: 0;
  /* Above the page's own scroll rail (z-index 900), which is drawn as an element rather than by the browser and
     was cutting through the figure whenever it drifted to the right-hand edge; still below the intro splash at
     1000, so it never floats over the opening screen. */
  z-index: 950;
  width: 190px;
  height: 250px;
  pointer-events: none;
  transform-origin: 0 0;
  will-change: transform;
  /* How big the figure is drawn, as a plain number pet.js puts inside its own transform:
     `translate3d(pos) scale(--pet-scale)`. It must NOT be the CSS `scale` property - that one scales the
     translation as well, so on a phone every position the script computed arrived at 55% of itself and the
     figure sat half a screen away from where the script thought it was, with an invisible wall in front of
     it. Written there, the scale happens first and the translation stays in viewport px. */
  --pet-scale: 1;
  transition:
    opacity 0.35s ease,
    visibility 0s linear 0s;
}
.pet-root.is-hidden {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.3s ease,
    visibility 0s linear 0.3s;
}
.pet-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* The figure's shadow on the page behind it. drop-shadow blurs the *silhouette*, not the sprite, so
     the pixel art stays crisp while the shadow follows every pose - peek, drift, hanging by the collar -
     without a line of JavaScript. Two of them: a tight one that reads as contact and a wide soft one that
     spreads it. Both are warm brown, the same ink as the site's other shadows. */
  filter: drop-shadow(2px 4px 4px rgba(74, 44, 22, 0.3)) drop-shadow(5px 14px 18px rgba(74, 44, 22, 0.2));
}
/* Dark mode has no light to catch, so the shadow is only there to lift the figure off the page. */
body.theme-dark .pet-canvas {
  filter: drop-shadow(2px 4px 4px rgba(0, 0, 0, 0.45)) drop-shadow(5px 14px 18px rgba(0, 0, 0, 0.32));
}
/* A filter on a canvas that repaints every frame is a blur pass per frame; that is exactly what
   performance-lite is for. */
html.performance-lite .pet-canvas {
  filter: none;
}
.pet-hit {
  position: absolute;
  left: 50%;
  top: 14%;
  width: 96px;
  height: 78%;
  margin: 0 0 0 -48px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: grab;
  pointer-events: auto;
  /* Vertical swipes still scroll the page. The box sits over the page's left edge, exactly where a thumb
     starts a scroll, and `none` swallowed those swipes; pulling the figure sideways still drags it, and a
     scroll that takes the gesture ends the drag through pointercancel. */
  touch-action: pan-y;
  -webkit-tap-highlight-color: transparent;
}
.pet-hit:active {
  cursor: grabbing;
}
.pet-hit:focus-visible {
  outline: 2px dashed #ee7b00;
  outline-offset: 2px;
}

/* Bubble and menu share the glass the blog's hover cards use: the topbar's paper tint with a
   heavier blur and a bright inner edge, square corners. */
.pet-bubble,
.pet-menu {
  --pet-edge: rgba(255, 255, 255, 0.7);
  position: absolute;
  left: var(--pet-ax, 50%);
  top: var(--pet-ay, 20px);
  z-index: 2;
  box-sizing: border-box;
  color: #241b16;
  font: 13px/1.5 var(--site-serif, KJing, "Noto Serif SC", "Songti SC", serif);
  background: rgba(255, 253, 251, 0.34);
  border: 1px solid var(--pet-edge);
  -webkit-backdrop-filter: blur(22px) saturate(180%) brightness(1.04);
  backdrop-filter: blur(22px) saturate(180%) brightness(1.04);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.75),
    inset 0 0 0 1px rgba(255, 255, 255, 0.25),
    8px 12px 28px rgba(62, 34, 16, 0.16);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(-50%, calc(-100% + 6px)) scale(0.98);
  transform-origin: 50% 100%;
  transition:
    opacity 0.24s ease,
    transform 0.24s ease,
    visibility 0s linear 0.24s;
}
.pet-bubble.is-on,
.pet-menu.is-on {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, -100%) scale(1);
  transition-delay: 0s;
}
/* The bubble's own edge, on the one side a box cannot draw it. A border runs the whole way round, so any
   tab hung under the bubble had that line drawn straight across the join, and riding the tab up over it
   only swapped a white line for a bright one (two translucent layers on top of each other). So the bottom
   edge is not a border here at all: it is two background strips that stop either side of the tab, and the
   tab below starts exactly where they stop. Nothing overlaps, nothing doubles up, and the tab and the
   panel are one shape. --pet-tail is a length (the tab's centre) written by pet.js every frame. */
.pet-bubble {
  --pet-tail: 50%;
  width: max-content;
  max-width: 214px;
  padding: 8px 12px;
  border-bottom: 0;
  background-image: linear-gradient(var(--pet-edge), var(--pet-edge)), linear-gradient(var(--pet-edge), var(--pet-edge));
  background-repeat: no-repeat;
  background-origin: border-box;
  background-position: left bottom, right bottom;
  background-size:
    max(0px, calc(var(--pet-tail) - 6px)) 1px,
    max(0px, calc(100% - var(--pet-tail) - 6px)) 1px;
  /* the inner highlight, split the same way: no ring segment may cross the join either */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.75),
    inset 1px 0 0 rgba(255, 255, 255, 0.25),
    inset -1px 0 0 rgba(255, 255, 255, 0.25),
    8px 12px 28px rgba(62, 34, 16, 0.16);
}
/* The tail is a square, not a point: every other corner on this site is square. pet.js sets --pet-tail
   to where the head actually is, so a bubble pushed in from the page edge to stay readable still points
   at the figure it belongs to.
   It starts exactly where the panel's bottom edge stops (`bottom: -8px`, no overlap) and takes the
   panel's own tint and blur, so the two read as one shape with one outline: the panel's edge runs along
   the bottom, turns down the tab's side, across its foot and back up, and carries on. */
.pet-bubble::after {
  content: "";
  position: absolute;
  left: var(--pet-tail, 50%);
  bottom: -8px;
  width: 12px;
  height: 8px;
  margin-left: -6px;
  background-color: inherit;
  -webkit-backdrop-filter: inherit;
  backdrop-filter: inherit;
  border: 1px solid var(--pet-edge);
  border-top: 0;
}
.pet-menu {
  top: calc(var(--pet-ay, 20px) - 6px);
  /* --pet-mx is the anchor pushed 84px right and then held inside the page by pet.js: on a phone the plain
     offset started the menu off the screen. */
  left: var(--pet-mx, calc(var(--pet-ax, 50%) + 84px));
  width: 176px;
  padding: 6px;
  display: grid;
  gap: 2px;
}
.pet-menu {
  transform: translate(8px, 0) scale(0.96);
  transform-origin: 0 0;
}
.pet-menu.is-on {
  pointer-events: auto;
  transform: translate(0, 0) scale(1);
}
.pet-menu-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px 8px;
  margin-bottom: 4px;
  border-bottom: 1px solid rgba(238, 123, 0, 0.28);
  color: #c25f00;
  font-size: 14px;
}
.pet-face {
  flex: none;
  display: inline-block;
  width: 24px;
  height: 24px;
  background-image: var(--pet-skin-hat), var(--pet-skin-head);
  background-size: 192px 192px;
  background-position:
    -120px -24px,
    -24px -24px;
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
.pet-menu button {
  display: block;
  width: 100%;
  margin: 0;
  padding: 7px 10px;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pet-menu button:hover,
.pet-menu button:focus-visible {
  background: rgba(238, 123, 0, 0.16);
  color: #b55500;
  outline: 0;
}
.pet-menu button:focus-visible {
  box-shadow: inset 0 0 0 1px rgba(238, 123, 0, 0.6);
}
.pet-menu hr {
  width: 100%;
  height: 1px;
  margin: 4px 0;
  border: 0;
  background: rgba(238, 123, 0, 0.22);
}

.pet-recall {
  position: fixed;
  /* Bottom-left corner: out of the way of the music player's own controls, which live on the right. The
     music bar floats over the bottom of the page at z-index 300, so a chip pinned 14px from the bottom sat
     underneath it; --music-bar-height is the bar's own height, written by music-player.js and 0 when the bar
     is hidden or has slid away. */
  --pet-recall-inset: 14px;
  left: var(--pet-recall-inset);
  bottom: calc(var(--music-bar-height, 0px) + var(--pet-recall-inset));
  z-index: 240;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.7);
  background-color: rgba(255, 253, 251, 0.34);
  background-image: var(--pet-skin-hat), var(--pet-skin-head);
  background-size: 256px 256px;
  background-position:
    -160px -32px,
    -32px -32px;
  background-repeat: no-repeat;
  background-origin: content-box;
  background-clip: content-box;
  padding: 3px;
  image-rendering: pixelated;
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.75),
    6px 8px 20px rgba(62, 34, 16, 0.18);
  opacity: 0;
  visibility: hidden;
  transform: translate3d(0, 12px, 0);
  transition:
    opacity 0.25s ease,
    bottom 0.25s ease,
    transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
    visibility 0s linear 0.35s;
}
.pet-recall.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.pet-recall:hover {
  transform: translate3d(0, -3px, 0);
}
.pet-recall:focus-visible {
  outline: 2px dashed #ee7b00;
  outline-offset: 2px;
}

body.theme-dark .pet-bubble,
body.theme-dark .pet-menu {
  --pet-edge: rgba(255, 221, 190, 0.3);
  color: #f6e6d8;
  /* background-color, not the shorthand: the bubble's bottom edge is a background layer, and the
     shorthand would wipe it out along with the tint. */
  background-color: rgba(25, 16, 11, 0.5);
  box-shadow:
    inset 0 1px 0 rgba(255, 221, 190, 0.2),
    inset 0 0 0 1px rgba(255, 221, 190, 0.08),
    8px 12px 28px rgba(0, 0, 0, 0.36);
}
body.theme-dark .pet-bubble {
  box-shadow:
    inset 0 1px 0 rgba(255, 221, 190, 0.2),
    inset 1px 0 0 rgba(255, 221, 190, 0.08),
    inset -1px 0 0 rgba(255, 221, 190, 0.08),
    8px 12px 28px rgba(0, 0, 0, 0.36);
}
body.theme-dark .pet-menu-head {
  color: #ffab4d;
}
body.theme-dark .pet-menu button:hover,
body.theme-dark .pet-menu button:focus-visible {
  background: rgba(255, 138, 22, 0.2);
  color: #ffc58a;
}
body.theme-dark .pet-recall {
  background-color: rgba(25, 16, 11, 0.5);
  border-color: rgba(255, 221, 190, 0.3);
}

html.performance-lite .pet-bubble,
html.performance-lite .pet-menu {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background-color: rgba(255, 253, 251, 0.94);
}
html.performance-lite body.theme-dark .pet-bubble,
html.performance-lite body.theme-dark .pet-menu {
  background-color: rgba(25, 16, 11, 0.94);
}

@media (max-width: 800px) {
  /* A third of the screen was too much figure for a phone; 0.55 puts it at about a quarter of the width,
     and leaves the page room to be dragged across. */
  .pet-root {
    --pet-scale: 0.55;
  }
  .pet-recall {
    --pet-recall-inset: 10px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .pet-root,
  .pet-bubble,
  .pet-menu,
  .pet-recall {
    transition-duration: 0.01s;
  }
}
