/* ============================================================================
   WOBBLE FORGE — base.css
   File 2/6. Reset, app baseline, no-scroll lock, cross-platform input
   hardening, typography primitives, shared keyframes and utility classes.
   ========================================================================== */

/* ---- Reset --------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--wf-bg-b);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  overscroll-behavior: none;
  position: fixed;
  inset: 0;
  width: 100%;
  background: var(--wf-bg-b);
  color: var(--wf-cream);
  font-family: var(--wf-font-sans);
  font-size: var(--wf-fs-md);
  line-height: 1.35;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Kill the browser "pull to refresh" / rubber-band on every platform. */
  touch-action: none;
}

h1, h2, h3, h4, p, ul, ol, li, figure, blockquote {
  margin: 0;
  padding: 0;
}

ul, ol {
  list-style: none;
}

img, svg, canvas, video {
  display: block;
  max-width: 100%;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}

button {
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

a {
  color: var(--wf-cyan);
  text-decoration: none;
}

/* ---- Global interaction hardening --------------------------------------- */
html,
body,
#app {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
}

/* Only real text entry + assistive tech may select. */
input,
textarea,
select,
[contenteditable="true"],
.wf-selectable {
  -webkit-user-select: text;
  user-select: text;
}

/* Never let long-press drag or text-drag hijack gameplay. */
#app *:not(input):not(textarea):not(select) {
  -webkit-user-drag: none;
}

/* ---- Typography primitives ---------------------------------------------- */
h1, h2, h3,
.wf-display {
  font-family: var(--wf-font-display);
  font-weight: 900;
  text-transform: uppercase;
  line-height: var(--wf-lh-tight);
  letter-spacing: var(--wf-ls-tight);
}

.wf-label {
  font-family: var(--wf-font-sans);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: var(--wf-ls-wide);
  font-size: var(--wf-fs-xs);
}

.wf-value {
  font-family: var(--wf-font-display);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 1;
}

/* Force tabular figures anywhere a number ticks. */
#hud-score, #hud-best, #hud-combo, #hud-height, #hud-timer,
#res-score, #res-height, #res-best, #menu-best-height,
#menu-best-score, #menu-best-combo, .wf-gauge__num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

::selection {
  background: var(--wf-gold);
  color: var(--wf-navy);
}

/* ---- Focus ring ---------------------------------------------------------- */
:focus {
  outline: none;
}

:focus-visible {
  outline: 3px solid var(--wf-focus);
  outline-offset: 3px;
}

/* ---- Keyframes ----------------------------------------------------------- */
/* Slow breathing float for idle buttons / badges.
   Uses the independent `translate` property so it composes with the
   `transform`-based hover lift / active press instead of fighting it. */
@keyframes wf-breathe {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -2px; }
}

/* Gentle bob for logo decor, icons, arrows. */
@keyframes wf-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* Feedback floats: rise along a JS-supplied trajectory and fade out. */
@keyframes wf-float-rise {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) translate(0, 0) scale(0.7);
  }
  18% {
    opacity: 1;
    transform: translate(-50%, -50%) translate(calc(var(--dx, 0px) * 0.22), calc(var(--dy, -60px) * 0.35)) scale(1.12);
  }
  42% {
    transform: translate(-50%, -50%) translate(calc(var(--dx, 0px) * 0.5), calc(var(--dy, -60px) * 0.6)) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -50%) translate(var(--dx, 0px), var(--dy, -60px)) scale(0.96);
  }
}

/* Hard pop for score numbers / PERFECT labels. */
@keyframes wf-pop {
  0%   { transform: scale(0.9); }
  55%  { transform: scale(1.1); }
  100% { transform: scale(1); }
}

@keyframes wf-pop-in {
  0%   { opacity: 0; transform: scale(0.82); }
  60%  { opacity: 1; transform: scale(1.03); }
  100% { opacity: 1; transform: scale(1); }
}

/* Attention pulse (objective, coach, reward). */
@keyframes wf-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.045); }
}

@keyframes wf-pulse-ring {
  0%   { box-shadow: 0 0 0 0 rgba(255, 201, 60, 0.55); }
  100% { box-shadow: 0 0 0 16px rgba(255, 201, 60, 0); }
}

/* Wobble — the game's signature idle motion for logo/preview art. */
@keyframes wf-wobble {
  0%, 100% { transform: rotate(-3deg); }
  50%      { transform: rotate(3deg); }
}

@keyframes wf-wobble-soft {
  0%, 100% { transform: rotate(-1.5deg) translateX(-1px); }
  50%      { transform: rotate(1.5deg) translateX(1px); }
}

/* Impact shake — disabled under reduced-fx / reduced-motion. */
@keyframes wf-shake {
  0%, 100% { transform: translate3d(0, 0, 0); }
  20%      { transform: translate3d(-3px, 1px, 0); }
  40%      { transform: translate3d(3px, -1px, 0); }
  60%      { transform: translate3d(-2px, 1px, 0); }
  80%      { transform: translate3d(2px, 0, 0); }
}

/* Loading bar sheen sweep. */
@keyframes wf-sheen {
  0%   { transform: translateX(-120%); }
  100% { transform: translateX(320%); }
}

/* Indeterminate fill used when real progress is unavailable. */
@keyframes wf-loading-slide {
  0%   { left: -40%; width: 40%; }
  50%  { left: 25%;  width: 55%; }
  100% { left: 100%; width: 40%; }
}

@keyframes wf-spin {
  to { transform: rotate(360deg); }
}

@keyframes wf-flash-out {
  from { opacity: var(--wf-level, 0.8); }
  to   { opacity: 0; }
}

@keyframes wf-toast-in {
  0%   { opacity: 0; transform: translateY(14px) scale(0.94); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes wf-set-in {
  0%   { opacity: 0; transform: translateY(10px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* Screen enter/exit are defined in screens.css but share timing tokens. */

/* ---- Utility classes ----------------------------------------------------- */
/* Visible + interactive screen. */
.is-active {
  /* Marked here for discoverability; concrete visuals live in screens.css. */
}

/* Hard hide regardless of display value. */
.is-hidden,
[hidden] {
  display: none !important;
}

.wf-sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  word-wrap: normal;
}

.wf-visually-hidden {
  visibility: hidden;
  pointer-events: none;
}

/* Interaction opt-in for UI inside the pointer-events:none overlay. */
.wf-interactive {
  pointer-events: auto;
}

.wf-no-events {
  pointer-events: none;
}

/* State tint helpers reused by gauges, badges and floats. */
.is-ok      { --wf-tint: var(--wf-green); }
.is-warn    { --wf-tint: var(--wf-gold); }
.is-danger  { --wf-tint: var(--wf-red); }
.is-critical { --wf-tint: var(--wf-red-800); }

/* ---- Reduced motion ------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Kill transform-based movement entirely; keep opacity legibility. */
  .wf-btn,
  .wf-float,
  .wf-logo,
  .wf-mode-card,
  .wf-next,
  .wf-coach,
  .wf-intro {
    animation: none !important;
  }
  .wf-float {
    animation: wf-float-rise 900ms linear forwards !important;
  }
}

/* ---- Reduced FX (JS toggled from settings) ------------------------------- */
/* Drops shake / particle-heavy / decorative motion; keeps essential feedback. */
#app[data-reduced-fx="true"] .wf-flash,
#app[data-reduced-fx="true"] .wf-vignette {
  display: none;
}

#app[data-reduced-fx="true"] .wf-logo,
#app[data-reduced-fx="true"] .wf-logo__decor,
#app[data-reduced-fx="true"] .wf-next,
#app[data-reduced-fx="true"] .wf-preview,
#app[data-reduced-fx="true"] .wf-mode-card__art,
#app[data-reduced-fx="true"] .wf-collect__preview {
  animation: none !important;
}

#app[data-reduced-fx="true"] .wf-btn,
#app[data-reduced-fx="true"] .wf-coach,
#app[data-reduced-fx="true"] .wf-objective {
  animation-iteration-count: 1;
  animation-duration: 0.001ms;
}

#app[data-reduced-fx="true"] .wf-float {
  animation-duration: var(--wf-dur-slow);
}
