/* ============================================================
   HypeCity Games — "Editorial Arcade" FX layer
   Games redesign 2026-05-21 (branch agent/games-redesign)

   A shared, ADDITIVE polish layer for the games (Would You Rather,
   Higher or Lower, the games hub, and Tycoon game screens). It
   extends — never replaces — the Architectural Editorial tokens:
   same cream canvas, brass accent, Fraunces display, JetBrains Mono
   labels, tactile hard-edge shadows. What it adds is *game juice*:
   depth, motion, satisfying state feedback, and premium micro-
   interactions.

   Conventions
   -----------
   • All classes are namespaced `gfx-` so they never collide with a
     page's existing CSS and can be opted into surgically.
   • Tokens are read with var(... , fallback) so the layer renders
     correctly even on the older self-contained game pages whose
     inline :root differs slightly from tokens.css.
   • Motion is fully gated: every animation is neutralised under
     `prefers-reduced-motion: reduce`. Hover/lift transforms collapse
     to a flat (but still legible) state. We never hide information
     or block interaction behind motion.
   ============================================================ */

:root {
  /* Game-specific accents layered on top of the brand palette.
     Gold = triumph / streak fire. Brass = the workhorse accent. */
  --gfx-gold:        var(--gold, #C9A961);
  --gfx-gold-deep:   var(--gold-deep, #9A7C28);
  --gfx-brass:       var(--brass, #8B6F3D);
  --gfx-brass-deep:  var(--brass-deep, #5E4D2A);
  --gfx-good:        var(--pos, #4A6B4A);
  --gfx-bad:         var(--neg, #8B4444);
  --gfx-ink:         var(--ink-primary, #1F1D1A);

  /* Spring-y easing curves — the heart of the "satisfying" feel. */
  --gfx-spring:  cubic-bezier(.34, 1.56, .64, 1);   /* overshoot pop  */
  --gfx-out:     cubic-bezier(.22, 1, .36, 1);       /* smooth settle  */
  --gfx-snappy:  cubic-bezier(.4, 0, .2, 1);
}

/* ============================================================
   1. KEYFRAMES
   ============================================================ */
@keyframes gfx-pop {
  0%   { transform: scale(.82); opacity: 0; }
  60%  { transform: scale(1.04); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes gfx-rise {
  0%   { transform: translateY(18px); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}
@keyframes gfx-rise-sm {
  0%   { transform: translateY(8px); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}
@keyframes gfx-sweep {           /* shine sweep across a surface */
  0%   { transform: translateX(-130%) skewX(-18deg); }
  100% { transform: translateX(230%) skewX(-18deg); }
}
@keyframes gfx-glow-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--gfx-glow-color, rgba(201,169,97,.45)); }
  50%      { box-shadow: 0 0 0 10px var(--gfx-glow-color-0, rgba(201,169,97,0)); }
}
@keyframes gfx-shake {
  0%, 100% { transform: translateX(0); }
  15%, 75% { transform: translateX(-9px); }
  30%, 60% { transform: translateX(9px); }
  45%      { transform: translateX(-5px); }
}
@keyframes gfx-good-flash {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.035); }
  100% { transform: scale(1); }
}
@keyframes gfx-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}
@keyframes gfx-flicker {         /* streak-fire flicker */
  0%, 100% { transform: scale(1) rotate(-1.5deg); opacity: 1; }
  25%      { transform: scale(1.08) rotate(2deg); opacity: .92; }
  50%      { transform: scale(.97) rotate(-1deg); opacity: 1; }
  75%      { transform: scale(1.05) rotate(1.5deg); opacity: .95; }
}
@keyframes gfx-count-blur {      /* number "settling" on count-up end */
  0%   { filter: blur(3px); opacity: .4; transform: translateY(6px); }
  100% { filter: blur(0);   opacity: 1;  transform: translateY(0); }
}
@keyframes gfx-ring {
  0%   { transform: scale(.6); opacity: .7; }
  100% { transform: scale(2.1); opacity: 0; }
}
@keyframes gfx-grad-shift {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}
@keyframes gfx-spin {
  to { transform: rotate(360deg); }
}
@keyframes gfx-bar-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* ============================================================
   2. ENTRANCE / STAGGER
   ============================================================ */
.gfx-rise   { animation: gfx-rise .55s var(--gfx-out) both; }
.gfx-pop    { animation: gfx-pop .5s var(--gfx-spring) both; }

.gfx-stagger > * { animation: gfx-rise .6s var(--gfx-out) both; }
.gfx-stagger > *:nth-child(1) { animation-delay: .04s; }
.gfx-stagger > *:nth-child(2) { animation-delay: .11s; }
.gfx-stagger > *:nth-child(3) { animation-delay: .18s; }
.gfx-stagger > *:nth-child(4) { animation-delay: .25s; }
.gfx-stagger > *:nth-child(5) { animation-delay: .32s; }
.gfx-stagger > *:nth-child(6) { animation-delay: .39s; }
.gfx-stagger > *:nth-child(7) { animation-delay: .46s; }
.gfx-stagger > *:nth-child(8) { animation-delay: .53s; }

/* ============================================================
   3. TACTILE CARD / BUTTON — lift + press with a hard editorial shadow
   ============================================================ */
.gfx-lift {
  transition: transform .22s var(--gfx-spring),
              box-shadow .22s var(--gfx-out),
              border-color .22s var(--gfx-snappy);
  will-change: transform;
}
.gfx-lift:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 38px -12px rgba(31,29,26,.32),
              0 6px 0 0 var(--gfx-ink);
}
.gfx-lift:active { transform: translateY(-1px); transition-duration: .08s; }

/* Premium primary button: hard tactile shadow that "presses" down */
.gfx-btn {
  position: relative;
  border: 1.5px solid var(--gfx-ink);
  box-shadow: var(--shadow-tactile-brass, 0 4px 0 0 var(--gfx-brass-deep));
  transition: transform .12s var(--gfx-snappy), box-shadow .12s var(--gfx-snappy);
  overflow: hidden;
}
.gfx-btn:hover  { transform: translateY(-2px); box-shadow: 0 6px 0 0 var(--gfx-brass-deep); }
.gfx-btn:active { transform: translateY(3px);  box-shadow: 0 1px 0 0 var(--gfx-brass-deep); }

/* ============================================================
   4. SHINE SWEEP — a light glint passes over the surface
   Add `.gfx-shine` to a position:relative, overflow:hidden element.
   ============================================================ */
.gfx-shine { position: relative; overflow: hidden; }
.gfx-shine::after {
  content: "";
  position: absolute;
  top: -20%; left: 0;
  width: 45%; height: 140%;
  background: linear-gradient(100deg,
              transparent 0%,
              rgba(255,255,255,.55) 50%,
              transparent 100%);
  transform: translateX(-130%) skewX(-18deg);
  pointer-events: none;
  opacity: 0;
}
.gfx-shine:hover::after,
.gfx-shine.is-sweeping::after { opacity: 1; animation: gfx-sweep .9s var(--gfx-out); }

/* ============================================================
   5. GLOW / RING / FLOAT / FIRE
   ============================================================ */
.gfx-glow      { animation: gfx-glow-pulse 2.4s ease-in-out infinite; }
.gfx-float     { animation: gfx-float 4.5s ease-in-out infinite; }
.gfx-fire      { animation: gfx-flicker 1.6s ease-in-out infinite; transform-origin: 50% 80%; }
.gfx-shake     { animation: gfx-shake .5s var(--gfx-snappy); }
.gfx-good-flash{ animation: gfx-good-flash .5s var(--gfx-spring); }

/* Expanding ring (emitted on a correct answer / milestone). JS injects
   a `.gfx-ring-el` child into a relatively-positioned host. */
.gfx-ring-el {
  position: absolute; inset: 0; margin: auto;
  width: 80%; height: 80%;
  border-radius: inherit;
  border: 2px solid var(--gfx-gold);
  pointer-events: none;
  animation: gfx-ring .7s var(--gfx-out) forwards;
}

/* ============================================================
   6. ANIMATED GRADIENT BORDER — for "live"/featured surfaces
   ============================================================ */
.gfx-grad-border {
  position: relative;
  isolation: isolate;
}
.gfx-grad-border::before {
  content: "";
  position: absolute; inset: -1.5px;
  border-radius: inherit;
  padding: 1.5px;
  background: linear-gradient(110deg,
              var(--gfx-brass), var(--gfx-gold), var(--gfx-brass), var(--gfx-gold));
  background-size: 200% 100%;
  animation: gfx-grad-shift 4s linear infinite;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
  z-index: -1;
}

/* ============================================================
   7. NUMBERS — tabular figures + count-up settle
   ============================================================ */
.gfx-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.gfx-num.is-counting { will-change: contents; }
.gfx-num.is-settled  { animation: gfx-count-blur .35s var(--gfx-out); }

/* ============================================================
   8. CONFETTI CANVAS (driven by games-fx.js)
   ============================================================ */
.gfx-confetti-canvas {
  position: fixed;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 9999;
}

/* ============================================================
   9. LIVE DOT (used in eyebrows/badges) — softer than a hard blink
   ============================================================ */
.gfx-live-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--gfx-gold);
  box-shadow: 0 0 0 0 var(--gfx-gold);
  animation: gfx-glow-pulse 2s ease-in-out infinite;
  --gfx-glow-color: rgba(201,169,97,.5);
  --gfx-glow-color-0: rgba(201,169,97,0);
}

/* ============================================================
   10. SPINNER (premium loading)
   ============================================================ */
.gfx-spinner {
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 3px solid var(--brass-soft, rgba(139,111,61,.14));
  border-top-color: var(--gfx-brass);
  animation: gfx-spin .8s linear infinite;
}

/* ============================================================
   11. ACCESSIBILITY — never regress focus or motion preferences
   ============================================================ */
/* Stronger, brand-consistent focus ring for game controls. */
.gfx-focus:focus-visible,
.gfx-btn:focus-visible,
.gfx-lift:focus-visible {
  outline: 3px solid var(--gfx-brass);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  /* Kill every decorative animation. Content still appears (both = no
     start state lingering), interactions still work — just no motion. */
  .gfx-rise, .gfx-pop, .gfx-stagger > *,
  .gfx-glow, .gfx-float, .gfx-fire, .gfx-shake, .gfx-good-flash,
  .gfx-live-dot, .gfx-spinner, .gfx-grad-border::before,
  .gfx-num.is-settled, .gfx-ring-el {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .gfx-shine::after { display: none !important; }
  .gfx-lift { transition: border-color .15s ease, box-shadow .15s ease; }
  .gfx-lift:hover { transform: none; box-shadow: 0 4px 0 0 var(--gfx-ink); }
  .gfx-btn, .gfx-btn:hover, .gfx-btn:active { transform: none; }
}
