/* ============================================================================
   FOREFITTER — Chip, and the loading state built around him

   This is the single definition of the mascot's rig: his coat, his kit and his
   walk cycle. Two things use it, and they only differ in where he stands:

     · the hub's ticker  — he walks the top edge of the marquee (hub styles.css
       positions him; everything about how he *looks and moves* is here)
     · .ff-load          — the suite's loading state, where he walks a short
       treadmill belt while a route or chunk is on its way

   He is drawn from the palette, not from literals, so he re-tints himself per
   theme: a tan prairie gopher in Carbon, a deep brown with a clubhouse-green
   bag in Clubhouse. The token sheet's prefers-reduced-motion block neutralises
   the whole rig for free — do not re-implement that here.

   The SVG geometry is inline at each use (the hub's index.html, and
   ForeFitterLoader.tsx for the Next bays) because it has to inherit theme
   custom properties — an <img> or background-image can't. If you change his
   anatomy, change it in both.
   ========================================================================== */

.gopher {
  display: block;
  --gp-fur:   var(--copper);
  --gp-fur-2: var(--copper-deep);
  --gp-belly: #f6e3c0;
  --gp-dark:  #241a06;
  --gp-step:  0.66s;
}
.gopher * { transform-box: view-box; }

/* coat */
.gp-body, .gp-head, .gp-ear { fill: var(--gp-fur); }
.gp-leg rect, .gp-leg ellipse, .gp-arm rect, .gp-arm circle { fill: var(--gp-fur-2); }
.gp-tail { fill: none; stroke: var(--gp-fur-2); stroke-width: 7; stroke-linecap: round; }
.gp-belly, .gp-muzzle, .gp-ear-in { fill: var(--gp-belly); }
.gp-nose { fill: var(--gp-dark); }
.gp-eye  { fill: var(--gp-dark); }
.gp-glint { fill: #fff; opacity: 0.9; }
.gp-tooth { fill: #fffdf4; }
.gp-whisk path { stroke: var(--gp-fur-2); stroke-width: 1.1; stroke-linecap: round; opacity: 0.75; fill: none; }
.gp-shadow { fill: #000; opacity: 0.22; }
:root[data-theme="light"] .gp-shadow { opacity: 0.13; }

/* house colours: volt visor, volt bag */
.gp-cap { fill: none; stroke: var(--volt); stroke-width: 7.5; stroke-linecap: round; }
.gp-brim { fill: var(--volt-deep); }
.gp-bagbody { fill: var(--volt); }
.gp-bagband { fill: var(--volt-deep); opacity: 0.85; }
.gp-bagpkt  { fill: var(--volt-deep); opacity: 0.55; }
.gp-strap   { fill: none; stroke: var(--volt-deep); stroke-width: 4.5; stroke-linecap: round; }
.gp-clubs path { stroke: var(--ink-dim); stroke-width: 2.4; stroke-linecap: round; fill: none; }
.gp-head-d { fill: var(--ink); }
.gp-head-i { fill: var(--ink-dim); }
.gp-head-p { fill: var(--copper-deep); }

/* --- the stride: every limb turns about its own joint --- */
.gp-bob    { transform-origin: 52px 90px; animation: gpBob  var(--gp-step) ease-in-out infinite; }
.gp-leg    { transform-origin: 0 0; }
.gp-leg-b  { translate: 45px 86px; animation: gpLegB var(--gp-step) ease-in-out infinite; }
.gp-leg-f  { translate: 58px 86px; animation: gpLegF var(--gp-step) ease-in-out infinite; }
.gp-arm    { transform-origin: 0 0; translate: 64px 64px; animation: gpArm var(--gp-step) ease-in-out infinite; }
.gp-tail   { transform-origin: 41px 96px; animation: gpTail calc(var(--gp-step) * 2) ease-in-out infinite; }
.gp-bag    { transform-origin: 30px 92px; animation: gpBag var(--gp-step) ease-in-out infinite; animation-delay: .07s; }
.gp-headg  { transform-origin: 54px 58px; animation: gpHead var(--gp-step) ease-in-out infinite; }
.gp-ear-l  { transform-origin: 38px 24px; animation: gpEar 3.4s ease-in-out infinite; }
.gp-ear-r  { transform-origin: 68px 20px; animation: gpEar 3.4s ease-in-out infinite; animation-delay: .12s; }

@keyframes gpBob  { 0%,100% { translate: 0 0; } 25% { translate: 0 -1.7px; } 50% { translate: 0 0; } 75% { translate: 0 -1.7px; } }
@keyframes gpLegF { 0%,100% { rotate: 25deg; }  50% { rotate: -22deg; } }
@keyframes gpLegB { 0%,100% { rotate: -22deg; } 50% { rotate: 25deg; } }
@keyframes gpArm  { 0%,100% { rotate: -28deg; } 50% { rotate: 20deg; } }
@keyframes gpTail { 0%,100% { rotate: -8deg; }  50% { rotate: 10deg; } }
@keyframes gpBag  { 0%,100% { rotate: -2.6deg; } 50% { rotate: 2.6deg; } }
@keyframes gpHead { 0%,100% { rotate: 1.4deg; } 50% { rotate: -1.4deg; } }
@keyframes gpEar  { 0%,86%,100% { rotate: 0deg; } 90% { rotate: -14deg; } 94% { rotate: 7deg; } }

/* dust kicked off the back of the belt */
.gp-puff { fill: var(--ink-faint); opacity: 0; transform-origin: 30px 115px; }
.gp-puff-1 { animation: gpPuff 1.32s linear infinite; }
.gp-puff-2 { animation: gpPuff 1.32s linear infinite; animation-delay: .66s; }
@keyframes gpPuff {
  0%   { opacity: 0;    translate: 0 0;        scale: 0.5; }
  18%  { opacity: 0.38; }
  100% { opacity: 0;    translate: -15px -4px; scale: 1.9; }
}

/* ---------------- the loading state ----------------
   Chip on a treadmill: he strides in place, the belt runs out from under him.
   Used for indeterminate waits with room to breathe — a route or a chunk on
   its way. Content-shaped skeletons stay skeletons; they hold the layout, and
   a mascot can't do that job. */
.ff-load {
  display: grid; place-items: center; align-content: center;
  min-height: var(--ff-load-min, 260px);
  padding: 40px 20px;
  width: 100%;
}
.ff-load__chip { height: var(--ff-load-size, 96px); width: auto; }
.ff-load__belt {
  width: clamp(110px, 24vw, 172px); height: 3px; margin-top: -1px;
  border-radius: 2px; background: var(--line-hard);
  position: relative; overflow: hidden;
}
.ff-load__belt::before {
  content: ""; position: absolute; inset: 0; width: 200%;
  background: repeating-linear-gradient(90deg, var(--volt) 0 9px, transparent 9px 22px);
  animation: ffBelt 0.5s linear infinite;
}
@keyframes ffBelt { to { transform: translateX(-22px); } }
.ff-load__label {
  font-family: var(--mono); font-size: var(--fs-micro); letter-spacing: var(--tr-label);
  text-transform: uppercase; color: var(--ink-faint); margin-top: 16px; text-align: center;
}
