/* ==========================================================================
   Filepath: app/static/css/mascot.css
   Huginn and Muninn - the perched ravens.

   Odin keeps two birds who fly out and come back with what they saw, which is
   what an agent does, so they are the accent rather than the subject. They go
   where nothing is happening: the sign-in door, an empty box, a 404. Never
   beside a fault. A cartoon bird perched next to a failing disk reads as
   mockery.

   The movement is deliberately almost nothing. One blink of 230ms and one
   ruffle inside a nine second loop, so it is caught in peripheral vision and
   never competes with the page. The sheet is four 32x32 frames, hand-authored
   rather than generated, because a blink is two pixels changing colour and a
   generated frame redraws the whole bird and makes it wobble:

     0 idle     eye open, white glint
     1 half     upper lid down one pixel
     2 shut     closed, one dark lash line
     3 ruffle   wing marking lifted one pixel, feathers settling

   The image URLs are relative and therefore unversioned, same as
   logo-icon.svg elsewhere. That is deliberate: sw.js only caches URLs that
   carry static_v()'s ?v=, so an unstamped asset always goes to the network
   and can never be pinned to a stale copy in a service worker.
   ========================================================================== */

/* The perch itself. The bird stands ON whatever follows it, so this must not
   take part in the normal flow spacing, and it must never eat a click. */
.wgw-perch {
  display: flex;
  justify-content: flex-end;
  margin-bottom: -2px;
  pointer-events: none;
}

.wgw-perch--start { justify-content: flex-start; }

.wgw-raven {
  /* Not optional. A bare <span> is inline, and an inline box ignores width and
     height, so outside a flex perch the bird renders at zero size and simply
     is not there. It has to carry its own display. */
  display: inline-block;
  flex: none;
  width: 32px;
  height: 32px;
  background-image: url('../images/mascot/raven-right.png');
  background-repeat: no-repeat;
  background-size: 400% 100%;
  background-position: 0 0;
  image-rendering: pixelated;
  animation: wgw-raven-idle 9s step-end infinite;
}

/* Facing west. At the right-hand edge of a column this is the one you want:
   the bird looks into the content rather than off the page. */
.wgw-raven--left { background-image: url('../images/mascot/raven-left.png'); }

/* Head turned back over its shoulder. At the right-hand edge it reads as a
   bird that walked past and looked back, which is why it has the page about
   something forgotten. */
.wgw-raven--look { background-image: url('../images/mascot/raven-look.png'); }

/* Integer scales only. A pixel sprite at 1.5x renders some pixels two device
   pixels wide and some one, which no amount of image-rendering can fix. */
.wgw-raven--2x,
.wgw-vegtam--2x { width: 64px; height: 64px; }

/* The pair must never blink in unison, which is the thing that would give
   them away as one sprite used twice. A negative delay starts mid-loop. */
.wgw-raven--b { animation-delay: -4.3s; }

@keyframes wgw-raven-idle {
  0%      { background-position: 0 0; }
  14%     { background-position: 33.333% 0; }
  14.7%   { background-position: 66.667% 0; }
  16%     { background-position: 33.333% 0; }
  16.6%   { background-position: 0 0; }
  61%     { background-position: 100% 0; }
  63%     { background-position: 0 0; }
  64.2%   { background-position: 100% 0; }
  65.8%   { background-position: 0 0; }
  100%    { background-position: 0 0; }
}

/* Frame 0 is a complete sprite, so stillness costs nothing here. */
@media (prefers-reduced-motion: reduce) {
  .wgw-raven {
    animation: none;
    background-position: 0 0;
  }
}

/* ── the empty box ───────────────────────────────────────────────────────
   A raven on the rim of an empty state. The state keeps its own icon: the
   icon says WHAT is missing, the bird is there because an empty box is a
   dead end, and a dead end is exactly where this works. One rule covers the
   18 templates that use .fk-empty. The inline variant has no border to perch
   on, so it is left alone. */
.fk-empty:not(.fk-empty--inline) { position: relative; }

.fk-empty:not(.fk-empty--inline)::after {
  content: "";
  position: absolute;
  right: 2rem;
  top: -30px;
  width: 32px;
  height: 32px;
  background: url('../images/mascot/raven-left.png') 0 0 / 400% 100% no-repeat;
  image-rendering: pixelated;
  animation: wgw-raven-idle 9s step-end infinite;
  animation-delay: -6.1s;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .fk-empty:not(.fk-empty--inline)::after { animation: none; }
}

/* ── Vegtam ──────────────────────────────────────────────────────────────
   The wanderer, and the one Odin calls himself when he is out on the road:
   Vegtam, the way-accustomed one. He earns the 404 and nothing else, because
   somebody lost is the one person a signpost is for. Still, never the 500:
   whoever is reading that is having a bad day already. */
.wgw-vegtam {
  display: block;
  width: 64px;
  height: 64px;
  margin: 0 auto 1.1rem;
  background: url('../images/mascot/vegtam-idle.png') 0 0 / 200% 100% no-repeat;
  image-rendering: pixelated;
  animation: wgw-vegtam-idle 9s step-end infinite;
}

/* He shifts his weight twice in nine seconds: the body drops one pixel and the
   boots stay planted, which is all a standing figure does. Generated frames
   were not an option here. Every animation endpoint refuses a canvas under
   64x64, and 64 is the size at which this model stops abstracting and starts
   painting a face, so a generated walk would have been a different character
   wearing the same hat. */
@keyframes wgw-vegtam-idle {
  0%     { background-position: 0 0; }
  36%    { background-position: 100% 0; }
  40.5%  { background-position: 0 0; }
  77%    { background-position: 100% 0; }
  81%    { background-position: 0 0; }
  100%   { background-position: 0 0; }
}

/* Error pages only. He settles like everywhere else, and once in twelve
   seconds he shrugs: shoulders up under the hat, forearms out. Five frames,
   the first two being the idle pair so the resting figure is identical to the
   one on the sign-in panel and only the move is different.

   The shrug is posed, not drawn. `estimate-skeleton` read a full humanoid rig
   off the 32px sprite for a tenth of a generation, the shoulders, elbows and
   wrists were moved by hand in normalised coordinates, and
   `animate-with-skeleton` rendered the three positions. That endpoint takes
   16px upward, unlike `animate-with-text`, which is locked to exactly 64.

   Kept OFF the sign-in showcase deliberately. A shrug means "I do not know",
   which is honest on a 404 and quite wrong on the page where somebody is
   trying to log in. */
.wgw-vegtam--lost {
  background-image: url('../images/mascot/vegtam-lost.png');
  background-size: 800% 100%;
  animation: wgw-vegtam-lost 14s step-end infinite;
}

/* 0 rest, 1 settle, 2-4 shrug, 5-7 point. He settles, then shrugs, then
   gestures onward, which is the whole of what a signpost can do for somebody
   who is already lost. */
@keyframes wgw-vegtam-lost {
  0%      { background-position: 0 0; }
  16%     { background-position: 14.2857% 0; }
  19%     { background-position: 0 0; }
  40%     { background-position: 28.5714% 0; }
  41%     { background-position: 42.8571% 0; }
  42%     { background-position: 57.1428% 0; }
  47%     { background-position: 42.8571% 0; }
  48%     { background-position: 28.5714% 0; }
  49%     { background-position: 0 0; }
  62%     { background-position: 71.4285% 0; }
  63%     { background-position: 85.7142% 0; }
  64%     { background-position: 100% 0; }
  72%     { background-position: 85.7142% 0; }
  73%     { background-position: 71.4285% 0; }
  74%     { background-position: 0 0; }
  100%    { background-position: 0 0; }
}

/* Walking, in profile, for the page that is about getting started. Four
   frames, the passing pose used twice the way walk cycles do. */
.wgw-vegtam--walk {
  background-image: url('../images/mascot/vegtam-walk.png');
  background-size: 400% 100%;
  animation: wgw-vegtam-walk .72s step-end infinite;
}

/* Explicit positions rather than a steps() slide. With background-size given
   as a percentage, a percentage background-position aligns that point of the
   IMAGE with the same point of the box, so the four frames are at 0, 33.333,
   66.667 and 100, and a negative offset does not step through them. */
@keyframes wgw-vegtam-walk {
  0%    { background-position: 0 0; }
  25%   { background-position: 33.333% 0; }
  50%   { background-position: 66.667% 0; }
  75%   { background-position: 100% 0; }
  100%  { background-position: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .wgw-vegtam--lost,
  .wgw-vegtam--walk { animation: none; background-position: 0 0; }
}

/* Three unplaced sprites are kept in images/mascot for whatever wants them:
   vegtam-east.png (three quarter profile), vegtam-north.png (from behind, no
   face at all), and vegtam-greet.png, five frames of him touching his hat
   brim. The greeting was on the sign-in panel and came off: he reads as
   pasted on there whatever is under his feet, and the pages he keeps are the
   ones where he has a job. No CSS is kept for it; a dead rule is worse than a
   missing one, as the .theme-switcher rule in mobile.css proved. */

/* A raven on the rim of a card that is already positioned, which is how the
   smaller error pages carry one. Not the 500 or the 502. */
.wgw-raven--rim {
  position: absolute;
  right: 2rem;
  top: -30px;
}

.wgw-raven--rim-start {
  position: absolute;
  left: 2rem;
  top: -30px;
}

@media (prefers-reduced-motion: reduce) {
  .wgw-vegtam { animation: none; background-position: 0 0; }
}
