import { useEffect, useMemo, useRef, useState } from 'react'; import './App.css'; const MATCH_DURATION = 70; const SUPPORTED_REGION = 'US only'; const API_ROUTING_LABEL = 'NA1 platform + AMERICAS match routing'; // ─── Input sanitization ─────────────────────────────────────────────────────── // Accepted format: one or more uppercase letters/digits, an underscore, then // one or more digits only. Examples: NA1_1234567890 EUW1_9876543210 const MATCH_ID_REGEX = /^[A-Z0-9]+_\d+$/; const MATCH_ID_MAX_LEN = 30; const sanitizeMatchId = (raw) => raw .toUpperCase() .replace(/[^A-Z0-9_]/g, '') .replace(/_{2,}/g, '_') .slice(0, MATCH_ID_MAX_LEN); // ─── Constants ──────────────────────────────────────────────────────────────── const MODEL_META = [ { key: 'xgboost', label: 'XGBoost', short: 'Teamfight Pattern', colorClass: 'xgboost' }, { key: 'lstm', label: 'LSTM', short: 'Momentum Curve', colorClass: 'lstm' }, { key: 'logreg', label: 'Logistic Regression', short: 'Stability Baseline', colorClass: 'logistic' }, ]; const EXAMPLE_MATCH_IDS = ['NA1_5498339609', 'NA1_5498663444', 'NA1_5504289306']; const EVENT_FILTERS = ['all', 'kills', 'objectives', 'structures']; const EVENT_TYPE_COLORS = { all: '#c6a769', kills: '#ff5f7a', objectives: '#19d7ff', structures: '#f0932b', }; // ─── Utilities ──────────────────────────────────────────────────────────────── // eslint-disable-next-line no-unused-vars const clamp = (value, min, max) => Math.min(Math.max(value, min), max); // ─── Components ─────────────────────────────────────────────────────────────── function AnimatedBackground() { return (