/* The widget's face, at any size, for agentgraft.com.
 *
 * A port of the "Launcher face" section of src/embed/styles.css, driven by
 * the real controller (launcher-face.js here is a symlink to the widget's).
 * The only change is a scale factor: set --k on a .face to grow it. The
 * controller writes gaze in launcher pixels (±9 / ±6.5), so every offset
 * here is multiplied by --k and a 76px launcher's behaviour reads the same
 * at 760px.
 *
 * The rendering is 2.5D, as in the widget: the eyes sit on a plane that
 * turns toward what they look at, each is shaded like a capsule with a
 * glint that slides against the gaze, and a blink squashes. Add .face-disc
 * (with --disc) to give the face a body: a lit sphere with a contact shadow
 * and the widget's body motion (breathe, puff, squash, sway, nod, yawn,
 * bounce, arrive).
 *
 * Colour comes from --face-eye (the lit eye) and --face-glow on the host.
 */

.face {
  --k: 1;
  --ag-lx: 0px;
  --ag-ly: 0px;
  --ag-gx: 0;
  --ag-gy: 0;
  --ag-near: 0;
  --ag-blink: 1;
  --ag-lid: 1;
  --ag-eye-w: calc(9px * var(--k));
  --ag-eye-h: calc(23px * var(--k));
  --ag-eye-gap: calc(15px * var(--k));
  --ag-eye-curious: calc(25px * var(--k));
  --ag-eye-excited: calc(26px * var(--k));
  --face-eye: #fff;
  --face-glow: rgba(255, 255, 255, 0.5);
  --face-hand: var(--face-eye);
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  position: relative;
  perspective: calc(240px * var(--k));
}

.face-eyes {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--ag-eye-gap);
  pointer-events: none;
  transform-style: preserve-3d;
  transform: translate(calc(var(--ag-gx) * var(--k) * 1px), calc(var(--ag-gy) * var(--k) * 1px))
             rotateY(calc(var(--ag-gx) * 2.2deg))
             rotateX(calc(var(--ag-gy) * -2.6deg))
             scale(calc(1 + 0.08 * var(--ag-near)));
  rotate: calc(var(--ag-cock, 0deg) + var(--ag-gaze-tilt, 0deg));
  transition: transform 110ms cubic-bezier(0.2, 0.8, 0.2, 1),
              rotate 320ms var(--spring);
}

.face-eye {
  position: relative;
  width: var(--ag-eye-w);
  height: var(--ag-eye-h);
  border-radius: var(--ag-eye-w);
  /* A capsule: darker at the edges, lit down the middle. */
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--face-eye) 86%, #000) 0%,
    var(--face-eye) 24%,
    color-mix(in srgb, var(--face-eye) 78%, #fff) 44%,
    var(--face-eye) 70%,
    color-mix(in srgb, var(--face-eye) 84%, #000) 100%);
  box-shadow: 0 0 calc(14px * var(--k)) var(--face-glow),
              inset 0 calc(-2px * var(--k)) calc(2.5px * var(--k)) rgba(0, 0, 0, 0.12);
  /* A blink squashes: the eye widens a touch as the lid comes down. */
  transform: scaleX(calc(1 + (1 - var(--ag-blink)) * 0.22))
             scaleY(calc(var(--ag-lid) * var(--ag-blink)));
  transition: transform 110ms ease-in-out,
              height 260ms var(--ease),
              border-radius 260ms var(--ease),
              filter 600ms ease;
}

/* The glint. The light is fixed, so as the eyes turn right it slides left. */
.face-eye::after {
  content: "";
  position: absolute;
  left: 22%;
  top: 8%;
  width: 30%;
  height: 16%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0));
  transform: translate(calc(var(--ag-gx) * -0.1px * var(--k)), calc(var(--ag-gy) * -0.12px * var(--k)));
  transition: transform 110ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.face[data-ag-face="curious"] .face-eye { height: var(--ag-eye-curious); }
.face[data-ag-face="curious"] .face-eyes { --ag-cock: -5deg; }

/* Pleased, once you are on it: the warm squint. */
.face.is-pettable:hover .face-eye {
  height: calc(12px * var(--k));
  border-radius: calc(9px * var(--k)) calc(9px * var(--k)) calc(4px * var(--k)) calc(4px * var(--k));
  translate: 0 calc(-1px * var(--k));
}
.face.is-pettable:hover .face-eyes { --ag-cock: 0deg; }

.face[data-ag-face="thinking"] { --ag-lid: 0.8; }
.face[data-ag-face="thinking"] .face-eyes {
  animation: face-read 3.4s cubic-bezier(0.3, 0, 0.2, 1) infinite;
  transition: none;
}
.face[data-ag-face="thinking"][data-ag-think="search"] { --ag-lid: 0.88; }
.face[data-ag-face="thinking"][data-ag-think="search"] .face-eyes {
  animation: face-search 5.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.face[data-ag-face="thinking"][data-ag-think="scan"] .face-eyes {
  animation: face-scan 2.3s cubic-bezier(0.3, 0, 0.25, 1) infinite;
}

.face[data-ag-face="excited"] .face-eye { height: var(--ag-eye-excited); }
.face[data-ag-face="excited"] .face-eyes { animation: face-hop 2.2s var(--spring) infinite; }

.face[data-ag-face="drowsy"] { --ag-lid: 0.5; }
.face[data-ag-face="drowsy"] .face-eye { filter: saturate(0.85) brightness(0.92); }

.face[data-ag-face="dozing"] { --ag-lid: 0.12; }
.face[data-ag-face="dozing"] .face-eye { filter: saturate(0.6) brightness(0.8); }

.face.ag-launcher-waking .face-eyes { animation: face-stretch 760ms var(--spring); }

.face-hand {
  position: absolute;
  top: calc(-12px * var(--k));
  right: calc(-6px * var(--k));
  width: calc(30px * var(--k));
  height: calc(30px * var(--k));
  color: var(--face-hand);
  pointer-events: none;
  opacity: 0;
  scale: 0.3;
  translate: calc(-5px * var(--k)) calc(9px * var(--k));
  transform-origin: 50% 88%;
  transition: opacity 200ms var(--ease), scale 380ms var(--spring), translate 380ms var(--spring);
}
.face-hand svg { display: block; width: 100%; height: 100%; fill: currentColor; }
.face[data-ag-face="excited"] .face-hand {
  opacity: 1;
  scale: 1;
  translate: 0 0;
  animation: face-wave 2.6s ease-in-out 380ms 4, face-wave-idle 9s ease-in-out 11s infinite;
}

/* The controller's keyframes are in launcher pixels, so they scale too. */
@keyframes face-read {
  0%, 14%   { translate: calc(-4px * var(--k)) calc(1px * var(--k)); }
  22%, 36%  { translate: calc(3px * var(--k)) calc(1px * var(--k)); }
  44%, 58%  { translate: calc(-3px * var(--k)) calc(-2px * var(--k)); }
  66%, 80%  { translate: calc(4px * var(--k)) calc(-2px * var(--k)); }
  88%, 100% { translate: 0 0; }
}
@keyframes face-search {
  0%, 6%    { translate: calc(-4px * var(--k)) calc(1px * var(--k)); }
  14%, 20%  { translate: calc(3px * var(--k)) calc(1px * var(--k)); }
  30%, 48%  { translate: calc(-6px * var(--k)) calc(-5px * var(--k)); }
  58%, 66%  { translate: calc(-3px * var(--k)) calc(1px * var(--k)); }
  76%, 88%  { translate: calc(4px * var(--k)) calc(1px * var(--k)); }
  96%, 100% { translate: 0 0; }
}
@keyframes face-scan {
  0%, 8%    { translate: calc(-5px * var(--k)) calc(-3px * var(--k)); }
  22%, 30%  { translate: calc(4px * var(--k)) calc(-2px * var(--k)); }
  44%, 52%  { translate: calc(-5px * var(--k)) calc(1px * var(--k)); }
  66%, 74%  { translate: calc(4px * var(--k)) calc(3px * var(--k)); }
  88%, 100% { translate: 0 0; }
}
@keyframes face-stretch {
  0%   { scale: 1 1; }
  28%  { scale: 1.12 0.84; }
  56%  { scale: 0.93 1.13; }
  78%  { scale: 1.04 0.97; }
  100% { scale: 1 1; }
}
@keyframes face-hop {
  0%, 62%, 100% { translate: 0 0; }
  70%           { translate: 0 calc(-3px * var(--k)); }
  80%           { translate: 0 calc(1px * var(--k)); }
  88%           { translate: 0 calc(-1px * var(--k)); }
}
@keyframes face-wave {
  0% { rotate: 0deg; } 6% { rotate: -22deg; } 13% { rotate: 14deg; }
  20% { rotate: -18deg; } 27% { rotate: 10deg; } 34% { rotate: -8deg; }
  42%, 100% { rotate: 0deg; }
}
@keyframes face-wave-idle {
  0% { rotate: 0deg; } 1.7% { rotate: -22deg; } 3.7% { rotate: 14deg; }
  5.7% { rotate: -18deg; } 7.7% { rotate: 10deg; } 9.7% { rotate: -8deg; }
  12%, 100% { rotate: 0deg; }
}

/* ── The body (.face-disc) ─────────────────────────────────────────────
 * The same motion vocabulary as the widget's launcher, on four channels
 * that never fight: transform breathes, scale puffs and squashes,
 * translate leans and jumps, rotate sways and nods. */
.face-disc {
  --disc: #1E2BD6;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 26%,
    color-mix(in srgb, var(--disc) 62%, #fff) 0%,
    var(--disc) 42%,
    color-mix(in srgb, var(--disc) 80%, #000) 100%);
  box-shadow: inset 0 calc(-5px * var(--k)) calc(10px * var(--k)) rgba(0, 0, 0, 0.16),
              inset 0 calc(2px * var(--k)) calc(3px * var(--k)) rgba(255, 255, 255, 0.3);
  transform-origin: 50% 92%;
  translate: calc(var(--ag-near) * var(--ag-gx) * 0.4px * var(--k))
             calc(var(--ag-near) * var(--ag-gy) * 0.3px * var(--k));
  transition: scale 460ms cubic-bezier(0.34, 1.7, 0.5, 1),
              translate 380ms cubic-bezier(0.2, 0.8, 0.2, 1),
              rotate 900ms cubic-bezier(0.4, 0, 0.2, 1);
  animation: face-arrive 720ms cubic-bezier(0.34, 1.6, 0.5, 1) backwards,
             face-breathe 5.6s ease-in-out 720ms infinite;
}
.face-disc::before {
  content: "";
  position: absolute;
  left: 14%;
  right: 14%;
  bottom: -14%;
  height: 16%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(15, 20, 64, 0.3), rgba(15, 20, 64, 0));
  filter: blur(calc(1.5px * var(--k)));
  z-index: -1;
  transition: scale 460ms cubic-bezier(0.34, 1.7, 0.5, 1);
  animation: face-shadow-breathe 5.6s ease-in-out 720ms infinite;
}
.face-disc.is-pettable:hover { scale: 1.08; }
.face-disc.is-pettable:hover::before { scale: 1.12; }
.face-disc.is-pettable:active { scale: 1.02 0.9; transition-duration: 110ms; }
.face-disc[data-ag-face="thinking"] {
  animation: face-breathe 5.6s ease-in-out infinite, face-sway 2.6s ease-in-out infinite;
}
.face-disc[data-ag-face="drowsy"] { rotate: -4deg; }
.face-disc[data-ag-face="dozing"] { rotate: -9deg; animation: face-breathe-deep 8s ease-in-out infinite; }
.face-disc.ag-launcher-waking { animation: face-yawn 760ms cubic-bezier(0.34, 1.4, 0.5, 1); }
.face-disc[data-ag-face="excited"] {
  animation: face-bounce 1.15s cubic-bezier(0.3, 0, 0.3, 1) 3,
             face-bounce-idle 11s cubic-bezier(0.3, 0, 0.3, 1) 3.45s infinite;
}
.face-disc[data-ag-face="excited"]::before {
  animation: face-shadow-bounce 1.15s cubic-bezier(0.3, 0, 0.3, 1) 3,
             face-shadow-bounce-idle 11s cubic-bezier(0.3, 0, 0.3, 1) 3.45s infinite;
}
/* The body jumps, so the eyes' own hop would double up. */
.face-disc[data-ag-face="excited"] .face-eyes { animation: none; }

@keyframes face-arrive {
  0%   { scale: 0.4; opacity: 0; }
  60%  { scale: 1.08; opacity: 1; }
  100% { scale: 1; opacity: 1; }
}
@keyframes face-breathe {
  0%, 100% { transform: scale(1, 1); }
  50%      { transform: scale(0.992, 1.022); }
}
@keyframes face-breathe-deep {
  0%, 100% { transform: scale(1.01, 0.985) translateY(calc(1px * var(--k))); }
  50%      { transform: scale(0.985, 1.035) translateY(0); }
}
@keyframes face-shadow-breathe {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(0.94); opacity: 0.85; }
}
@keyframes face-sway {
  0%, 100% { rotate: -3deg; }
  50%      { rotate: 3deg; }
}
@keyframes face-yawn {
  0%   { scale: 1 1; }
  28%  { scale: 1.1 0.86; }
  56%  { scale: 0.94 1.12; }
  78%  { scale: 1.03 0.97; }
  100% { scale: 1 1; }
}
@keyframes face-bounce {
  0%   { translate: 0 0;                          scale: 1 1; }
  12%  { translate: 0 0;                          scale: 1.1 0.88; }
  40%  { translate: 0 calc(-30px * var(--k));    scale: 0.94 1.08; }
  52%  { translate: 0 calc(-32px * var(--k));    scale: 1 1; }
  74%  { translate: 0 0;                          scale: 1.14 0.84; }
  84%  { translate: 0 calc(-5px * var(--k));     scale: 0.98 1.03; }
  100% { translate: 0 0;                          scale: 1 1; }
}
@keyframes face-shadow-bounce {
  0%, 12%, 100% { translate: 0 0;                           scale: 1;    opacity: 1; }
  40%           { translate: 0 calc(30px * var(--k));      scale: 0.6;  opacity: 0.4; }
  52%           { translate: 0 calc(32px * var(--k));      scale: 0.55; opacity: 0.35; }
  74%           { translate: 0 0;                           scale: 1.15; opacity: 1; }
  84%           { translate: 0 calc(5px * var(--k));       scale: 0.92; opacity: 0.85; }
}
@keyframes face-bounce-idle {
  0%          { translate: 0 0;                          scale: 1 1; }
  1.25%       { translate: 0 0;                          scale: 1.1 0.88; }
  4.2%        { translate: 0 calc(-30px * var(--k));    scale: 0.94 1.08; }
  5.4%        { translate: 0 calc(-32px * var(--k));    scale: 1 1; }
  7.7%        { translate: 0 0;                          scale: 1.14 0.84; }
  8.8%        { translate: 0 calc(-5px * var(--k));     scale: 0.98 1.03; }
  10.5%, 100% { translate: 0 0;                          scale: 1 1; }
}
@keyframes face-shadow-bounce-idle {
  0%, 1.25%, 10.5%, 100% { translate: 0 0;                      scale: 1;    opacity: 1; }
  4.2%  { translate: 0 calc(30px * var(--k)); scale: 0.6;  opacity: 0.4; }
  5.4%  { translate: 0 calc(32px * var(--k)); scale: 0.55; opacity: 0.35; }
  7.7%  { translate: 0 0;                      scale: 1.15; opacity: 1; }
  8.8%  { translate: 0 calc(5px * var(--k));  scale: 0.92; opacity: 0.85; }
}

@media (prefers-reduced-motion: reduce) {
  .face-eyes, .face-eye, .face-eye::after { transition: none; animation: none !important; }
  .face-disc, .face-disc::before { animation: none !important; transition: none; translate: none; }
  .face[data-ag-face="excited"] .face-hand { animation: none; rotate: -12deg; }
}
