/* The portrait: the photograph in the shape it sits in, the canvas the engine
 * draws him on, and the props his idle acts bring along. The markup is
 * template-parts/content/portrait.php; assets/js/face/javi.js brings it to
 * life. `.plush` is the picture's own square: give it a width and it does
 * the rest.
 *
 * The shape's geometry is defined here and nowhere else, as fractions of the
 * picture: its centre (--frame-x, --frame-y), half its width (--frame-r) and
 * its top edge (--frame-top). The engine reads the same numbers to clip him.
 */
.plush {
  --frame-x: 0.5;
  --frame-y: 0.57;
  --frame-r: 0.43;
  --frame-top: calc(var(--frame-y) - var(--frame-r));
  --frame-left: calc(var(--frame-x) - var(--frame-r));
  --frame-right: calc(1 - var(--frame-x) - var(--frame-r));
  position: relative;
  aspect-ratio: 1;
  /* His props are sized against him (cqw), so they stay in proportion on a
   * phone and on a desk. */
  container-type: inline-size;
  /* Pressing and holding him is how a finger takes hold: it mustn't select
   * anything, call up a menu, or flash the tap highlight. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.plush[data-frame="square"] { --frame-y: 0.5; --frame-r: 0.42; --frame-top: 0.36; }

/* What he sits in: a disc, or a block that runs to the bottom of the picture. */
.plush-frame {
  position: absolute;
  left: calc(var(--frame-left) * 100%); top: calc(var(--frame-top) * 100%);
  width: calc(var(--frame-r) * 200%); height: calc(var(--frame-r) * 200%);
  border-radius: 50%;
  /* The theme's orange (resources/css/tokens.css) where its stylesheet is
   * loaded; the same value on pages that stand alone, like the Face Lab. */
  background: var(--color-orange, #fa5b01);
}
.plush[data-frame="square"] .plush-frame { height: auto; bottom: 0; border-radius: 0; }
.plush[data-frame="none"] .plush-frame { display: none; }

/* The photograph, clipped the way the engine clips him: to the shape's
 * sides and bottom, open at the top so his head pops out. This is what shows
 * until he's live, and all that shows without JavaScript or WebGL. */
.plush[data-frame="circle"] > :is(img, .plush-hit) {
  clip-path: inset(
    0 calc(var(--frame-right) * 100%) calc((1 - var(--frame-y) - var(--frame-r)) * 100%) calc(var(--frame-left) * 100%)
    round 0 0 calc(var(--frame-r) * 100%) calc(var(--frame-r) * 100%)
  );
}
.plush[data-frame="square"] > :is(img, .plush-hit) {
  clip-path: inset(0 calc(var(--frame-right) * 100%) 0 calc(var(--frame-left) * 100%));
}

.plush > img,
.plush-hit { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Where he can be touched (a button with nothing of a button's looks): the
 * same shape, so a finger in the empty corners is the page's. On him, swipes
 * up and down still scroll the page and pinches still zoom it; sideways
 * swipes, and a finger that rests on him, take hold (the engine sees to
 * that). */
.plush-hit {
  z-index: 3; display: block; margin: 0; padding: 0; border: 0; border-radius: 0;
  appearance: none; -webkit-appearance: none; background: none; color: inherit; font: inherit;
  touch-action: pan-y pinch-zoom; outline: 0;
}
/* While his skin is well out of place it can be touched wherever it has got
 * to inside his picture; the engine works out whether a touch is on him. */
.plush.is-stretched > .plush-hit { clip-path: none; }
/* Reached with the keyboard, the shape he sits in shows it: a ring of two
 * colours, so it reads on a light page and on a dark one. */
.plush:has(.plush-hit:focus-visible) .plush-frame,
.plush[data-frame="none"]:has(.plush-hit:focus-visible) { outline: 3px solid #0a0a0a; outline-offset: 3px; box-shadow: 0 0 0 9px #fff; }
/* The canvas is bigger than the picture by the engine's `pad` (--plush-pad,
 * which the engine sets on it) on every side, so stretched skin has
 * somewhere to go. It never takes the pointer. */
.plush canvas {
  position: absolute; z-index: 2;
  left: calc(var(--plush-pad) * -100%); top: calc(var(--plush-pad) * -100%);
  width: calc(100% + var(--plush-pad) * 200%); height: calc(100% + var(--plush-pad) * 200%);
  pointer-events: none;
}
/* The photograph is what shows until the engine is running, and if it can't. */
.plush.is-live > img { visibility: hidden; }

/* --- Props ---------------------------------------------------------------- */

/* Sizes are fractions of his picture's width (cqw), with a fixed size
 * ahead of each for browsers that don't know the unit. */

/* The phantom hand that comes to tug his cheek: a cursor where there's a
 * mouse, a fingertip on a touch screen. */
.plush-ghost {
  position: absolute; left: 0; top: 0; z-index: 5;
  width: 1.75rem; height: 1.75rem;
  width: clamp(1.2rem, 4.4cqw, 2.25rem); height: clamp(1.2rem, 4.4cqw, 2.25rem);
  pointer-events: none; opacity: 0; transition: opacity .18s;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .35));
  will-change: transform;
}
.plush-ghost path { fill: #fff; stroke: #0a0a0a; stroke-width: 1.6; stroke-linejoin: round; }
.plush-ghost.is-here { opacity: 1; }
.plush-ghost .grab,
.plush-ghost .tip,
.plush-ghost.is-gripping .open { display: none; }
.plush-ghost.is-gripping .grab { display: block; }
/* `.is-touch` (from javi.js): the visitor is using fingers. */
.plush.is-touch .plush-ghost { width: 2.6rem; height: 2.6rem; width: clamp(2.2rem, 12cqw, 3.4rem); height: clamp(2.2rem, 12cqw, 3.4rem); filter: none; }
.plush.is-touch .plush-ghost path { display: none; }
.plush.is-touch .plush-ghost .tip {
  display: block;
  fill: rgba(255, 255, 255, .45); stroke: rgba(255, 255, 255, .95); stroke-width: 2;
  paint-order: stroke; filter: drop-shadow(0 0 1.5px rgba(0, 0, 0, .6));
  transform-box: fill-box; transform-origin: center; transition: transform .12s ease-out, fill .12s;
}
.plush.is-touch .plush-ghost.is-gripping .tip { transform: scale(.78); fill: rgba(255, 255, 255, .8); }

/* The fly. Its wings beat about their hinges in flight and fold back along
 * the body once it lands. The pale edge keeps it visible on a dark page. */
.plush-fly {
  position: absolute; left: 0; top: 0; z-index: 5;
  width: 1.9rem; height: 1.9rem;
  width: clamp(1.25rem, 4.75cqw, 2.4rem); height: clamp(1.25rem, 4.75cqw, 2.4rem);
  pointer-events: none; opacity: 0;
  will-change: transform;
}
.plush-fly.is-here { opacity: 1; }
.plush-fly .body { fill: #0a0a0a; stroke: rgba(255, 255, 255, .7); stroke-width: .7; paint-order: stroke; }
.plush-fly .eye { fill: var(--color-orange, #fa5b01); }
.plush-fly .wing { fill: rgba(255, 255, 255, .85); stroke: #0a0a0a; stroke-width: 1; transform-box: view-box; }
.plush-fly .wing.left { transform-origin: 15px 15px; }
.plush-fly .wing.right { transform-origin: 17px 15px; }
.plush-fly.is-here .wing.left { animation: plush-wing-left 40ms linear infinite alternate; }
.plush-fly.is-here .wing.right { animation: plush-wing-right 40ms linear infinite alternate; }
.plush-fly.is-landed .wing.left { animation: none; transform: rotate(-62deg); }
.plush-fly.is-landed .wing.right { animation: none; transform: rotate(62deg); }
@keyframes plush-wing-left { from { transform: rotate(24deg); } to { transform: rotate(-20deg); } }
@keyframes plush-wing-right { from { transform: rotate(-24deg); } to { transform: rotate(20deg); } }

/* The puff of breath that sees the fly off. javi.js places it at his mouth. */
.plush-puff {
  position: absolute; z-index: 4;
  width: 4rem; height: 4rem;
  width: 10cqw; height: 10cqw;
  pointer-events: none; opacity: 0;
  animation: plush-puff 380ms ease-out forwards;
}
.plush-puff path { fill: none; stroke-linecap: round; }
.plush-puff .under { stroke: #0a0a0a; stroke-width: 5.5; }
.plush-puff .over { stroke: #fff; stroke-width: 2.6; }
@keyframes plush-puff {
  0% { opacity: 0; transform: translate(-50%, -80%) scale(.45); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -135%) scale(1.15); }
}

/* Notes drifting off his lips while he whistles. Pale with a dark edge, so
 * they read on his face, on the frame and on whatever is behind it. How far
 * each drifts is its own (--drift, 0–1, from javi.js). */
.plush-note {
  --far: 12rem;
  --up: 6rem;
  position: absolute; z-index: 4;
  font: 400 2.6rem/1 "Apple Symbols", "Segoe UI Symbol", "Noto Sans Symbols 2", sans-serif;
  color: #fff;
  text-shadow: 0 0 2px #0a0a0a, 1px 1px 0 #0a0a0a, -1px 1px 0 #0a0a0a, 1px -1px 0 #0a0a0a, -1px -1px 0 #0a0a0a;
  pointer-events: none; opacity: 0;
  animation: plush-note 1.9s ease-out forwards;
}
@supports (width: 1cqw) {
  .plush-note { --far: 30cqw; --up: 15cqw; font-size: clamp(1.4rem, 6.5cqw, 3rem); }
}
@keyframes plush-note {
  0% { opacity: 0; transform: translate(0, 0) scale(.5) rotate(-8deg); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(var(--far) * var(--drift, 1)), calc(var(--up) * -1)) scale(1.15) rotate(14deg); }
}

@media (prefers-reduced-motion: reduce) {
  .plush-fly.is-here .wing { animation: none; }
}
