diff --git a/app.js b/app.js
new file mode 100644
index 0000000..f7f16dd
--- /dev/null
+++ b/app.js
@@ -0,0 +1,178 @@
+'use strict';
+
+// ── Category metadata ───────────────────────────────────────────────────────
+const CAT = {
+ all: { label: 'All Games', color: '#7c3aed', emoji: '🎮' },
+ action: { label: 'Action', color: '#ef4444', emoji: '⚡' },
+ adventure: { label: 'Adventure', color: '#fb923c', emoji: '🗺️' },
+ horror: { label: 'Horror', color: '#8b5cf6', emoji: '👻' },
+ idle: { label: 'Idle', color: '#84cc16', emoji: '💰' },
+ multiplayer: { label: 'Multiplayer', color: '#ec4899', emoji: '👥' },
+ music: { label: 'Music', color: '#14b8a6', emoji: '🎵' },
+ platformer: { label: 'Platformer', color: '#f97316', emoji: '🏃' },
+ puzzle: { label: 'Puzzle', color: '#06b6d4', emoji: '🧩' },
+ racing: { label: 'Racing', color: '#f59e0b', emoji: '🏎️' },
+ rpg: { label: 'RPG', color: '#a855f7', emoji: '⚔️' },
+ shooter: { label: 'Shooter', color: '#f43f5e', emoji: '🔫' },
+ sports: { label: 'Sports', color: '#10b981', emoji: '🏀' },
+ strategy: { label: 'Strategy', color: '#3b82f6', emoji: '♟️' },
+ other: { label: 'Other', color: '#64748b', emoji: '✨' },
+};
+
+// ── State ───────────────────────────────────────────────────────────────────
+let activeCat = 'all';
+let searchTerm = '';
+
+// ── DOM refs ────────────────────────────────────────────────────────────────
+const $ = id => document.getElementById(id);
+const grid = $('grid');
+const empty = $('empty');
+const overlay = $('overlay');
+const frame = $('game-frame');
+const loader = $('loader');
+const catBar = $('cat-bar');
+const searchEl = $('search');
+const clearBtn = $('search-clear');
+
+// ── Category bar ────────────────────────────────────────────────────────────
+function buildCatBar() {
+ const counts = {};
+ GAMES.forEach(g => { counts[g.cat] = (counts[g.cat] || 0) + 1; });
+
+ catBar.innerHTML = Object.entries(CAT).map(([id, m]) => {
+ const n = id === 'all' ? GAMES.length : (counts[id] || 0);
+ if (id !== 'all' && !n) return '';
+ return ``;
+ }).join('');
+
+ catBar.addEventListener('click', e => {
+ const btn = e.target.closest('.cat-pill');
+ if (!btn) return;
+ catBar.querySelectorAll('.cat-pill').forEach(b => b.classList.remove('active'));
+ btn.classList.add('active');
+ activeCat = btn.dataset.cat;
+ render();
+ });
+}
+
+// ── Game grid ───────────────────────────────────────────────────────────────
+function render() {
+ const lower = searchTerm.toLowerCase();
+ const list = GAMES.filter(g =>
+ (activeCat === 'all' || g.cat === activeCat) &&
+ (!lower || g.name.toLowerCase().includes(lower))
+ );
+
+ const n = list.length;
+ $('header-count').textContent = `${n} game${n === 1 ? '' : 's'}`;
+
+ if (!n) {
+ grid.innerHTML = '';
+ empty.classList.remove('hidden');
+ return;
+ }
+
+ empty.classList.add('hidden');
+
+ grid.innerHTML = list.map(g => {
+ const m = CAT[g.cat];
+ const idx = GAMES.indexOf(g);
+ const bg = `linear-gradient(145deg, ${m.color}2e 0%, ${m.color}0a 100%)`;
+ return `
+
+ ${g.thumb
+ ? `

`
+ : `
${m.emoji}`
+ }
+
+
+
+
${g.name}
+
${m.label}
+
+
`;
+ }).join('');
+}
+
+// Delegated click — attached once
+grid.addEventListener('click', e => {
+ const card = e.target.closest('.card');
+ if (card) openGame(+card.dataset.idx);
+});
+
+// ── Game loading ─────────────────────────────────────────────────────────────
+function openGame(idx) {
+ const g = GAMES[idx];
+ const m = CAT[g.cat];
+
+ $('overlay-name').textContent = g.name;
+ const badge = $('overlay-badge');
+ badge.textContent = m.label;
+ badge.style.background = m.color + '22';
+ badge.style.color = m.color;
+
+ overlay.classList.remove('hidden');
+ loader.style.display = 'flex';
+ frame.style.opacity = '0';
+ frame.src = '';
+
+ // Load directly — iframe runs in the game's own origin so same-origin
+ // fetches (Unity data files, Construct 2 assets, etc.) are never blocked by CORS
+ frame.onload = () => {
+ loader.style.display = 'none';
+ frame.style.opacity = '1';
+ };
+ frame.src = g.url;
+}
+
+function closeGame() {
+ overlay.classList.add('hidden');
+ frame.src = '';
+ loader.style.display = 'none';
+ frame.style.opacity = '0';
+}
+
+function goFullscreen() {
+ const el = frame;
+ (el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen
+ || function(){}).call(el);
+}
+
+// ── Search ──────────────────────────────────────────────────────────────────
+searchEl.addEventListener('input', e => {
+ searchTerm = e.target.value;
+ clearBtn.classList.toggle('hidden', !searchTerm);
+ render();
+});
+
+clearBtn.addEventListener('click', () => {
+ searchEl.value = '';
+ searchTerm = '';
+ clearBtn.classList.add('hidden');
+ searchEl.focus();
+ render();
+});
+
+// ── Controls ────────────────────────────────────────────────────────────────
+$('close-btn').addEventListener('click', closeGame);
+$('fs-btn').addEventListener('click', goFullscreen);
+
+document.addEventListener('keydown', e => {
+ if (!overlay.classList.contains('hidden')) {
+ if (e.key === 'Escape') closeGame();
+ if (e.key === 'f' || e.key === 'F') goFullscreen();
+ }
+});
+
+// ── Boot ────────────────────────────────────────────────────────────────────
+buildCatBar();
+render();
diff --git a/games.js b/games.js
new file mode 100644
index 0000000..ad1f8e9
--- /dev/null
+++ b/games.js
@@ -0,0 +1,206 @@
+// URL helpers — GitHub Pages URLs (game runs in its own origin, CORS-safe)
+const UGS = n => `https://bubbls.github.io/UGS-Assets/${encodeURIComponent(n)}/`;
+const NG = n => `https://neruvy.github.io/neruvy-games/games/${n}/`;
+const NP = n => `https://neruvy.github.io/web-port/${n}/`;
+const GP = n => `https://genizy.github.io/web-port/${n}/`;
+const MT = n => `https://mathtut0r1ng.github.io/gamespage/games/${n}/`;
+
+const GAMES = [
+
+ // ── UGS-ASSETS (bubbls/UGS-Assets) ───────────────────────────────────────
+ { name: "1 Date Danger", url: UGS("1-date-danger"), cat: "horror" },
+ { name: "10 Minutes Till Dawn", url: UGS("10minutestilldawn"), cat: "shooter" },
+ { name: "2 Minute Football", url: UGS("2 minute football"), cat: "sports" },
+ { name: "2-3-4 Player Games", url: UGS("2-3-4-player-game"), cat: "multiplayer" },
+ { name: "2 DOOM", url: UGS("2doom"), cat: "action" },
+ { name: "3Dash", url: UGS("3dash"), cat: "platformer" },
+ { name: "5B", url: UGS("5b"), cat: "other" },
+ { name: "Antimatter Dimensions", url: UGS("Antimatter Dimensions"), cat: "idle" },
+ { name: "Bumper Cars Soccer", url: UGS("BUMPER CARS SOCCER"), cat: "sports" },
+ { name: "Blightborne", url: UGS("Blightborne"), cat: "rpg" },
+ { name: "Burrito Bison", url: UGS("BurritoBison-main"), cat: "action" },
+ { name: "Endacopia", url: UGS("Endacopia"), cat: "horror" },
+ { name: "Five Nights at Wario's", url: UGS("FNAW-main"), cat: "horror" },
+ { name: "Five Nights at Osaka's", url: UGS("Five Nights at Osaka's"), cat: "horror" },
+ { name: "Insomniary", url: UGS("Insomniary"), cat: "horror" },
+ { name: "Stickman GTA", url: UGS("STICKMAN GTA"), cat: "action" },
+ { name: "Stickman Clash", url: UGS("Stickman Clash"), cat: "action" },
+ { name: "A Day in the Office", url: UGS("a day in the office"), cat: "other" },
+ { name: "Adventure Capitalist", url: UGS("adventure-capitalist"), cat: "idle" },
+ { name: "Ages of Conflict", url: UGS("ages of conflict"), cat: "strategy" },
+ { name: "Airline Tycoon Idle", url: UGS("airline-tycoon-idle"), cat: "idle" },
+ { name: "Alien Sky Invasion", url: UGS("alien sky invasion"), cat: "shooter" },
+ { name: "Amazing Rope Police", url: UGS("amazing-strange-rope-police-vice-spider"), cat: "action" },
+ { name: "Amidst the Sky", url: UGS("amidst the sky"), cat: "platformer" },
+ { name: "Angry Birds", url: UGS("angry-bird"), cat: "puzzle" },
+ { name: "Apes vs Helium", url: UGS("apesvshelium"), cat: "action" },
+ { name: "Arcade Volley", url: UGS("arcade-volley"), cat: "sports" },
+ { name: "Archesspalago", url: UGS("archesspalago"), cat: "puzzle" },
+ { name: "Astro Survivors", url: UGS("astro survivors"), cat: "shooter" },
+ { name: "Aviamaster", url: UGS("aviamaster"), cat: "strategy" },
+ { name: "Babel Tower", url: UGS("babel tower"), cat: "puzzle" },
+ { name: "Backrooms 2D", url: UGS("backrooms 2D"), cat: "horror" },
+ { name: "Bacon May Die", url: UGS("bacon may die"), cat: "action" },
+ { name: "Bad Parenting", url: UGS("bad-parenting"), cat: "platformer" },
+ { name: "Baldi's Basics", url: UGS("baldis-basics"), cat: "horror" },
+ { name: "Baldi's Decomp", url: UGS("baldi decomp"), cat: "horror" },
+ { name: "Ballistic", url: UGS("ballistic"), cat: "shooter" },
+ { name: "Banana Poker", url: UGS("banana poker"), cat: "other" },
+ { name: "Barry Has a Secret", url: UGS("barry has a secret"), cat: "horror" },
+ { name: "Baseball Bros", url: UGS("baseball bros"), cat: "sports" },
+ { name: "Basket Stars", url: UGS("basket stars"), cat: "sports" },
+ { name: "Basketball Superstars", url: UGS("basketball-superstars"), cat: "sports" },
+ { name: "Beach Boxing Sim", url: UGS("beach-boxing-sim"), cat: "sports" },
+ { name: "Bearsus", url: UGS("bearsus"), cat: "action" },
+ { name: "Ben 10 Super Slammer", url: UGS("ben 10 super slammer"), cat: "action" },
+ { name: "BFNSU", url: UGS("bfnsu"), cat: "horror" },
+ { name: "Big 2048", url: UGS("big 2048"), cat: "puzzle" },
+ { name: "Big Flappy Tower", url: UGS("big flappy tower"), cat: "platformer" },
+ { name: "Block Miner", url: UGS("block-miner"), cat: "idle" },
+ { name: "BlockPost", url: UGS("blockpost"), cat: "shooter" },
+ { name: "Blumgi Racers", url: UGS("blumgi racers"), cat: "racing" },
+ { name: "Blumgi Rocket", url: UGS("blumgi-rocket"), cat: "racing" },
+ { name: "Bounce Back", url: UGS("bounce back"), cat: "puzzle" },
+ { name: "Bouncy Basketball", url: UGS("bouncy basketball"), cat: "sports" },
+ { name: "Bouncy Motors", url: UGS("bouncy motors"), cat: "racing" },
+ { name: "Bounty of One", url: UGS("bounty of one"), cat: "rpg" },
+ { name: "Brawl 3D", url: UGS("brawl-3d"), cat: "multiplayer" },
+ { name: "Bullet Force", url: UGS("bullet-force-multiplayer"), cat: "shooter" },
+ { name: "Capybara Clicker", url: UGS("capybara clicker"), cat: "idle" },
+ { name: "Cat Mario", url: UGS("cat mario"), cat: "platformer" },
+ { name: "Cats Love Cake 2", url: UGS("cats love cake 2"), cat: "puzzle" },
+ { name: "Cave Chaos 2", url: UGS("cave chaos 2"), cat: "platformer" },
+ { name: "Cheese Chompers 3", url: UGS("cheese chompers 3"), cat: "action" },
+ { name: "Chicken Gun", url: UGS("chicken-gun"), cat: "shooter" },
+ { name: "Choppy Orc", url: UGS("choppy orc"), cat: "platformer" },
+ { name: "CircloO 2", url: UGS("circlo02"), cat: "puzzle" },
+ { name: "Clash of Vikings", url: UGS("clashofvikings"), cat: "strategy" },
+ { name: "Cookie Clicker", url: UGS("cookieclicker"), cat: "idle" },
+ { name: "Crazy Cars", url: UGS("crazy cars"), cat: "racing" },
+ { name: "Crazy Chicken 3D", url: UGS("crazy chicken 3D"), cat: "shooter" },
+ { name: "Creature Card Idle", url: UGS("creature-card-idle"), cat: "idle" },
+ { name: "CS:GO Surf", url: UGS("csgo surf"), cat: "action" },
+ { name: "Dandy's World Clicker", url: UGS("dandys-world-clicker"), cat: "idle" },
+ { name: "D-Blox", url: UGS("dblox"), cat: "puzzle" },
+ { name: "Deepest Sword", url: UGS("deepest sword"), cat: "rpg" },
+ { name: "Demon Bluff", url: UGS("demon-bluff"), cat: "horror" },
+ { name: "Die in the Dungeon", url: UGS("die in the dungeon"), cat: "rpg" },
+ { name: "Dimension Incident", url: UGS("dimension-incident"), cat: "horror" },
+ { name: "Doge Miner 2", url: UGS("doge miner 2"), cat: "idle" },
+ { name: "Doodle Jump", url: UGS("doodle jump"), cat: "platformer" },
+ { name: "Down the Mountain", url: UGS("down the mountain"), cat: "action" },
+ { name: "Dragon", url: UGS("dragon"), cat: "action" },
+ { name: "Drift Hunters", url: UGS("drift-hunters"), cat: "racing" },
+ { name: "Drunken Duel", url: UGS("drunken duel"), cat: "multiplayer" },
+ { name: "Duck Life 6", url: UGS("duck life 6"), cat: "rpg" },
+ { name: "Duck Life Battle", url: UGS("duck life battle"), cat: "rpg" },
+ { name: "Dungeon Deck", url: UGS("dungeondeck"), cat: "strategy" },
+ { name: "Eagle Ride", url: UGS("eagle ride"), cat: "racing" },
+ { name: "Edy's Car Simulator", url: UGS("edys car simulator"), cat: "racing" },
+ { name: "Eggy Car", url: UGS("eggy car"), cat: "racing" },
+ { name: "Elastic Man", url: UGS("elasticman"), cat: "other" },
+ { name: "Escalating Duel", url: UGS("escalating-duel"), cat: "action" },
+ { name: "Escape Road 2", url: UGS("escaperoad2city"), cat: "racing" },
+
+ // ── NERUVY GAMES (Neruvy/neruvy-games) ───────────────────────────────────
+ { name: "1v1.LOL", url: NG("1v1lol"), cat: "shooter" },
+ { name: "2048", url: NG("2048"), cat: "puzzle" },
+ { name: "ARC", url: NG("ARC"), cat: "action" },
+ { name: "Bob the Robber 2", url: NG("bob-the-robber-2"), cat: "adventure" },
+ { name: "Drive Mad", url: NG("drive-mad"), cat: "racing" },
+ { name: "Granny", url: NG("granny"), cat: "horror" },
+ { name: "Moto X3M", url: NG("moto-x3m"), cat: "racing" },
+ { name: "Moto X3M 2", url: NG("motox3m2"), cat: "racing" },
+ { name: "Poly Track", url: NG("poly-track"), cat: "racing" },
+ { name: "Run 3", url: NG("run-3"), cat: "platformer" },
+ { name: "Slope", url: NG("slope"), cat: "action" },
+ { name: "Smash Karts", url: NG("smash-karts"), cat: "racing" },
+ { name: "Snow Rider 3D", url: NG("snow-rider"), cat: "racing" },
+ { name: "Survival Race", url: NG("survival-race"), cat: "racing" },
+ { name: "Time Shooter 3: SWAT", url: NG("time-shooter-3-swat"), cat: "shooter" },
+ { name: "Vex 3", url: NG("vex3"), cat: "platformer" },
+ { name: "Vex 4", url: NG("vex4"), cat: "platformer" },
+ { name: "Vex 5", url: NG("vex5"), cat: "platformer" },
+ { name: "Vex 6", url: NG("vex6"), cat: "platformer" },
+ { name: "Vex 7", url: NG("vex7"), cat: "platformer" },
+
+ // ── WEB PORTS — Neruvy (Neruvy/web-port) ─────────────────────────────────
+ { name: "Amanda the Adventurer", url: NP("amanda-the-adventurer"), cat: "horror" },
+ { name: "Andy's Apple Farm", url: NP("andys-apple-farm"), cat: "adventure" },
+ { name: "Baldi's Basics Plus", url: NP("baldi-plus"), cat: "horror" },
+ { name: "Baldi's Basics Remastered", url: NP("baldi-remaster"), cat: "horror" },
+ { name: "Bendy and the Ink Machine", url: NP("bendy"), cat: "horror" },
+ { name: "BERGENTRUCK", url: NP("bergentruck"), cat: "adventure" },
+ { name: "BLOODMONEY!", url: NP("bloodmoney"), cat: "action" },
+ { name: "Buckshot Roulette", url: NP("buckshot-roulette"), cat: "horror" },
+ { name: "Class of '09", url: NP("class-of-09"), cat: "adventure" },
+ { name: "Cuphead", url: NP("cuphead"), cat: "action" },
+ { name: "Dead Plate", url: NP("dead-plate"), cat: "horror" },
+ { name: "The Deadseat", url: NP("deadseat"), cat: "horror" },
+ { name: "Deltarune", url: NP("deltatraveler"), cat: "rpg" },
+ { name: "Do Not Take This Cat Home", url: NP("donottakethiscathome"), cat: "horror" },
+ { name: "Fears to Fathom", url: NP("fears-to-fathom"), cat: "horror" },
+ { name: "Getting Over It", url: NP("getting-over-it"), cat: "platformer" },
+ { name: "Happy Sheepies", url: NP("happy-sheepies"), cat: "puzzle" },
+ { name: "Hotline Miami", url: NP("hotline-miami"), cat: "action" },
+ { name: "Human Expenditure Program", url: NP("human-expenditure-program"), cat: "horror" },
+ { name: "Jelly Drift", url: NP("jelly-drift"), cat: "racing" },
+ { name: "Karlson", url: NP("karlson"), cat: "action" },
+ { name: "Kindergarten", url: NP("kindergarten"), cat: "adventure" },
+ { name: "Lacy's Flash Games", url: NP("lacysflashgames"), cat: "other" },
+ { name: "Milkman Karlson", url: NP("milkman-karlson"), cat: "action" },
+ { name: "OMORI", url: NP("omori-fixed"), cat: "rpg" },
+ { name: "People Playground", url: NP("people-playground"), cat: "other" },
+ { name: "Pizza Tower", url: NP("pizza-tower"), cat: "platformer" },
+ { name: "Raft", url: NP("raft"), cat: "adventure" },
+ { name: "Slender: The 8 Pages", url: NP("slender"), cat: "horror" },
+ { name: "Speed Stars", url: NP("speed-stars"), cat: "racing" },
+ { name: "That's Not My Neighbor", url: NP("thats-not-my-neighbor"), cat: "horror" },
+ { name: "The Man in the Window", url: NP("the-man-in-the-window"), cat: "horror" },
+ { name: "ULTRAKILL", url: NP("ultrakill"), cat: "action" },
+ { name: "Undertale Yellow", url: NP("undertale-yellow"), cat: "rpg" },
+ { name: "WebFishing", url: NP("web-fishing"), cat: "other" },
+ { name: "Yandere Simulator", url: NP("yandere-simulator"), cat: "action" },
+ { name: "Yume Nikki", url: NP("yume-nikki"), cat: "rpg" },
+
+ // ── WEB PORTS — Genizy exclusives (genizy/web-port) ──────────────────────
+ { name: "Minesweeper Plus", url: GP("minesweeperplus"), cat: "puzzle" },
+ { name: "Schoolboy Runaway", url: GP("schoolboy-runaway"), cat: "action" },
+ { name: "Sonic.exe", url: GP("sonic.exe"), cat: "horror" },
+ { name: "Tattletail", url: GP("tattletail"), cat: "horror" },
+ { name: "Witch Heart", url: GP("witch-heart"), cat: "rpg" },
+
+ // ── MATHTUT0R1NG (mathtut0r1ng.github.io) ────────────────────────────────
+ { name: "A Dance of Fire and Ice", url: MT("a-dance-of-fire-and-ice"), cat: "music" },
+ { name: "Amaze", url: MT("amaze"), cat: "puzzle" },
+ { name: "Aquapark.io", url: MT("aquapark.io"), cat: "sports" },
+ { name: "Basket Random", url: MT("basket-random"), cat: "sports" },
+ { name: "Basketball Stars", url: MT("basketball-stars"), cat: "sports" },
+ { name: "Block Blast", url: MT("block-blast"), cat: "puzzle" },
+ { name: "Bouncemasters", url: MT("bouncemasters"), cat: "action" },
+ { name: "Bowmasters", url: MT("bowmasters"), cat: "action" },
+ { name: "Bridge Race", url: MT("bridge-race"), cat: "racing" },
+ { name: "Clash Royale", url: MT("clash"), cat: "strategy" },
+ { name: "Crossy Road", url: MT("crossy-road"), cat: "platformer" },
+ { name: "Eaglercraft 1.12.2", url: MT("eaglercraft-1.12.2"), cat: "other" },
+ { name: "Five Nights at Freddy's", url: MT("fnaf"), cat: "horror" },
+ { name: "Five Nights at Freddy's 2", url: MT("fnaf2"), cat: "horror" },
+ { name: "Five Nights at Freddy's 3", url: MT("fnaf3"), cat: "horror" },
+ { name: "Five Nights at Freddy's 4", url: MT("fnaf4"), cat: "horror" },
+ { name: "Friday Night Funkin'", url: MT("friday-night-funkin"), cat: "music" },
+ { name: "Hill Climb Racing Lite", url: MT("hill-climb-racing-lite"), cat: "racing" },
+ { name: "Hollow Knight", url: MT("hollow-knight"), cat: "platformer" },
+ { name: "Paper.io 2", url: MT("paper.io-2"), cat: "multiplayer" },
+ { name: "Pixel Gun Survival", url: MT("pixel-gun-survival"), cat: "shooter" },
+ { name: "R.E.P.O.", url: MT("repo"), cat: "other" },
+ { name: "RE:RUN", url: MT("re-run"), cat: "action" },
+ { name: "Slither.io", url: MT("slither.io"), cat: "multiplayer" },
+ { name: "Solar Smash", url: MT("solar-smash"), cat: "other" },
+ { name: "Spiral Roll", url: MT("spiral-roll"), cat: "puzzle" },
+ { name: "Sprunki", url: MT("sprunki"), cat: "music" },
+ { name: "Super Mario 64", url: MT("super-mario-64"), cat: "platformer" },
+ { name: "The Impossible Quiz", url: MT("the-impossible-quiz"), cat: "puzzle" },
+ { name: "The World's Hardest Game", url: MT("the-worlds-hardest-game"), cat: "platformer" },
+ { name: "They Are Coming", url: MT("they-are-coming"), cat: "shooter" },
+
+];
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..0a44770
--- /dev/null
+++ b/index.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+ OMG Games
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
🎮
+
No games found
+
Try a different search or category
+
+
+
+
+
+
+
+
+
+
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..955dc26
--- /dev/null
+++ b/style.css
@@ -0,0 +1,431 @@
+/* ── Variables ─────────────────────────────────────────────────────────── */
+:root {
+ --bg: #07070e;
+ --surface: #0d0d1a;
+ --surface2: #121224;
+ --surface3: #16162c;
+ --border: #1a1a30;
+ --border2: #22223a;
+ --primary: #7c3aed;
+ --primary2: #6d28d9;
+ --accent: #a78bfa;
+ --glow: #7c3aed28;
+ --text: #ededf8;
+ --text-dim: #8888b0;
+ --text-muted: #444468;
+
+ --header-h: 58px;
+ --catbar-h: 52px;
+ --radius: 10px;
+ --card-min: 190px;
+}
+
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+
+html { height: 100%; }
+
+body {
+ min-height: 100%;
+ background: var(--bg);
+ color: var(--text);
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', system-ui, sans-serif;
+ font-size: 14px;
+ overflow-x: hidden;
+}
+
+button { font-family: inherit; }
+
+/* ── Header ────────────────────────────────────────────────────────────── */
+#header {
+ position: fixed;
+ top: 0; left: 0; right: 0;
+ height: var(--header-h);
+ background: var(--surface);
+ border-bottom: 1px solid var(--border);
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 0 16px;
+ z-index: 50;
+}
+
+.header-left { display: flex; align-items: center; flex-shrink: 0; }
+.header-center { flex: 1; max-width: 520px; margin: 0 auto; }
+.header-right { flex-shrink: 0; }
+
+/* Logo */
+.logo {
+ display: flex;
+ align-items: center;
+ gap: 9px;
+ user-select: none;
+}
+
+.logo-badge {
+ background: var(--primary);
+ color: #fff;
+ font-size: 11px;
+ font-weight: 900;
+ letter-spacing: 1.5px;
+ padding: 4px 9px;
+ border-radius: 6px;
+}
+
+.logo-text {
+ font-size: 18px;
+ font-weight: 700;
+ color: var(--text);
+ letter-spacing: -0.2px;
+}
+
+/* Search */
+.search-wrap {
+ position: relative;
+ width: 100%;
+}
+
+.search-icon {
+ position: absolute;
+ left: 11px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 16px;
+ height: 16px;
+ color: var(--text-muted);
+ pointer-events: none;
+}
+
+#search {
+ width: 100%;
+ background: var(--surface2);
+ border: 1px solid var(--border2);
+ color: var(--text);
+ padding: 8px 34px 8px 34px;
+ border-radius: 8px;
+ font-size: 13.5px;
+ outline: none;
+ transition: border-color 0.15s, background 0.15s;
+ font-family: inherit;
+}
+
+#search::placeholder { color: var(--text-muted); }
+#search:focus { border-color: var(--primary); background: var(--surface3); }
+
+#search-clear {
+ position: absolute;
+ right: 8px;
+ top: 50%;
+ transform: translateY(-50%);
+ background: none;
+ border: none;
+ color: var(--text-muted);
+ cursor: pointer;
+ padding: 4px;
+ display: flex;
+ border-radius: 4px;
+}
+#search-clear svg { width: 13px; height: 13px; }
+#search-clear:hover { color: var(--text); }
+
+/* Count badge */
+#header-count {
+ font-size: 12px;
+ color: var(--text-muted);
+ white-space: nowrap;
+}
+
+/* ── Category Bar ──────────────────────────────────────────────────────── */
+#cat-bar {
+ position: fixed;
+ top: var(--header-h);
+ left: 0; right: 0;
+ height: var(--catbar-h);
+ background: var(--surface);
+ border-bottom: 1px solid var(--border);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 0 16px;
+ overflow-x: auto;
+ overflow-y: hidden;
+ z-index: 49;
+ scrollbar-width: none;
+}
+#cat-bar::-webkit-scrollbar { display: none; }
+
+.cat-pill {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 14px;
+ border-radius: 20px;
+ font-size: 13px;
+ font-weight: 500;
+ white-space: nowrap;
+ cursor: pointer;
+ border: 1px solid var(--border2);
+ background: var(--surface2);
+ color: var(--text-dim);
+ transition: all 0.15s;
+ user-select: none;
+}
+
+.cat-pill:hover {
+ background: var(--surface3);
+ color: var(--text);
+ border-color: var(--border2);
+}
+
+.cat-pill.active {
+ background: var(--primary);
+ border-color: var(--primary);
+ color: #fff;
+}
+
+.cat-pill-emoji { font-size: 14px; line-height: 1; }
+.cat-pill-count {
+ font-size: 11px;
+ opacity: 0.7;
+ font-variant-numeric: tabular-nums;
+}
+
+/* ── Main / Grid ───────────────────────────────────────────────────────── */
+#main {
+ margin-top: calc(var(--header-h) + var(--catbar-h));
+ padding: 20px 16px 32px;
+ min-height: calc(100vh - var(--header-h) - var(--catbar-h));
+}
+
+#grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
+ gap: 10px;
+}
+
+/* ── Game Card ─────────────────────────────────────────────────────────── */
+.card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ overflow: hidden;
+ cursor: pointer;
+ transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
+ position: relative;
+}
+
+.card:hover {
+ transform: translateY(-3px);
+ border-color: var(--primary);
+ box-shadow: 0 8px 28px var(--glow);
+}
+
+.card-thumb {
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ overflow: hidden;
+}
+
+.card-thumb img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.2s;
+}
+
+.card:hover .card-thumb img { transform: scale(1.04); }
+
+.card-emoji {
+ font-size: 2.2rem;
+ line-height: 1;
+ filter: drop-shadow(0 2px 10px #0008);
+ user-select: none;
+ pointer-events: none;
+}
+
+/* Play button overlay */
+.card-play {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(0, 0, 0, 0.38);
+ opacity: 0;
+ transition: opacity 0.15s;
+}
+
+.card:hover .card-play { opacity: 1; }
+
+.card-play svg {
+ width: 36px;
+ height: 36px;
+ color: #fff;
+ filter: drop-shadow(0 2px 8px #0006);
+}
+
+.card-body {
+ padding: 9px 11px 11px;
+}
+
+.card-name {
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--text);
+ line-height: 1.35;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin-bottom: 5px;
+}
+
+.cat-badge {
+ display: inline-block;
+ font-size: 10px;
+ font-weight: 600;
+ padding: 2px 8px;
+ border-radius: 5px;
+ letter-spacing: 0.2px;
+}
+
+/* ── Empty State ───────────────────────────────────────────────────────── */
+#empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ padding: 100px 20px;
+}
+.empty-icon { font-size: 3.5rem; }
+.empty-msg { font-size: 18px; font-weight: 600; color: var(--text-dim); }
+.empty-sub { font-size: 13px; color: var(--text-muted); }
+
+/* ── Game Overlay ──────────────────────────────────────────────────────── */
+#overlay {
+ position: fixed;
+ inset: 0;
+ background: var(--bg);
+ z-index: 200;
+ display: flex;
+ flex-direction: column;
+}
+
+#overlay.hidden { display: none; }
+
+#overlay-bar {
+ height: 50px;
+ background: var(--surface);
+ border-bottom: 1px solid var(--border);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 14px;
+ gap: 10px;
+ flex-shrink: 0;
+}
+
+#overlay-left {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-width: 0;
+ flex: 1;
+}
+
+#overlay-right { display: flex; gap: 6px; flex-shrink: 0; }
+
+#close-btn, #fs-btn {
+ background: var(--surface2);
+ border: 1px solid var(--border2);
+ color: var(--text-dim);
+ border-radius: 7px;
+ cursor: pointer;
+ width: 34px;
+ height: 34px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ transition: background 0.12s, color 0.12s, border-color 0.12s;
+}
+#close-btn svg, #fs-btn svg { width: 15px; height: 15px; }
+#close-btn:hover, #fs-btn:hover {
+ background: var(--surface3);
+ border-color: var(--border2);
+ color: var(--text);
+}
+
+#overlay-name {
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--text);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+#overlay-badge {
+ font-size: 10.5px;
+ font-weight: 600;
+ padding: 2px 8px;
+ border-radius: 5px;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+#frame-wrap {
+ flex: 1;
+ position: relative;
+ overflow: hidden;
+}
+
+#game-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+ transition: opacity 0.2s;
+}
+
+/* Loading state */
+#loader {
+ position: absolute;
+ inset: 0;
+ display: none;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 16px;
+ background: var(--bg);
+ z-index: 2;
+}
+
+.spinner {
+ width: 40px;
+ height: 40px;
+ border: 3px solid var(--border2);
+ border-top-color: var(--primary);
+ border-radius: 50%;
+ animation: spin 0.75s linear infinite;
+}
+
+.loader-text {
+ font-size: 13px;
+ color: var(--text-muted);
+}
+
+@keyframes spin { to { transform: rotate(360deg); } }
+
+/* ── Scrollbar ─────────────────────────────────────────────────────────── */
+::-webkit-scrollbar { width: 5px; height: 5px; }
+::-webkit-scrollbar-track { background: transparent; }
+::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 3px; }
+::-webkit-scrollbar-thumb:hover { background: var(--primary); }
+
+/* ── Utilities ─────────────────────────────────────────────────────────── */
+.hidden { display: none !important; }