commit 062f2690677442dda634f2d1b0bbe8687d507a62
Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 03:56:32 +0000
chore: auto-update maintainer activity
Diffstat:
15 files changed, 1461 insertions(+), 0 deletions(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @notamitgamer
diff --git a/.github/scripts/update_commits.py b/.github/scripts/update_commits.py
@@ -0,0 +1,91 @@
+import urllib.request
+import json
+import re
+import os
+from datetime import datetime
+
+USERNAME = "notamitgamer"
+
+def fetch_recent_commits():
+ commits_data = []
+ try:
+ search_url = f"https://api.github.com/search/commits?q=author:{USERNAME}&sort=author-date&order=desc&per_page=15"
+ req = urllib.request.Request(search_url)
+ req.add_header('User-Agent', f'{USERNAME}-readme-updater')
+ req.add_header('Accept', 'application/vnd.github+json')
+
+ # Use GITHUB_TOKEN if available to avoid rate limits
+ token = os.environ.get('GITHUB_TOKEN')
+ if token:
+ req.add_header('Authorization', f'token {token}')
+
+ with urllib.request.urlopen(req) as response:
+ data = json.loads(response.read().decode())
+
+ items = data.get('items', [])
+ print(f"๐ Search API returned {len(items)} commits.")
+
+ for item in items:
+ date_str = item['commit']['author']['date']
+ date_obj = datetime.fromisoformat(date_str)
+
+ msg = item['commit']['message'].split('\n')[0]
+ commit_url = item['html_url']
+
+ # Extract repo name from the commit URL
+ # e.g. https://github.com/owner/repo/commit/sha
+ parts = commit_url.split('/')
+ repo_name = f"{parts[3]}/{parts[4]}"
+ repo_url = f"https://github.com/{repo_name}"
+
+ commits_data.append({
+ 'date': date_obj,
+ 'markdown': f"- [{msg}]({commit_url}) in [{repo_name}]({repo_url})"
+ })
+
+ # Sort by date descending
+ commits_data.sort(key=lambda x: x['date'], reverse=True)
+
+ # Deduplicate (search can return same commit across multiple branches)
+ seen = set()
+ unique_commits = []
+ for c in commits_data:
+ if c['markdown'] not in seen:
+ seen.add(c['markdown'])
+ unique_commits.append(c)
+
+ final_commits = [c['markdown'] for c in unique_commits[:5]]
+ print(f"โ
Found {len(final_commits)} recent commits.")
+ return final_commits
+
+ except Exception as e:
+ print(f"Error fetching data: {e}")
+ return []
+
+
+def update_readme(commits):
+ if not commits:
+ print("No commits found to update.")
+ return
+
+ commit_list_md = "\n".join(commits)
+
+ with open('README.md', 'r', encoding='utf-8') as f:
+ readme = f.read()
+
+ updated_readme = re.sub(
+ r"<!-- START_RECENT_COMMITS -->.*?<!-- END_RECENT_COMMITS -->",
+ f"<!-- START_RECENT_COMMITS -->\n{commit_list_md}\n<!-- END_RECENT_COMMITS -->",
+ readme,
+ flags=re.DOTALL
+ )
+
+ with open('README.md', 'w', encoding='utf-8') as f:
+ f.write(updated_readme)
+
+ print("โ
README.md successfully updated!")
+
+
+if __name__ == "__main__":
+ recent_commits = fetch_recent_commits()
+ update_readme(recent_commits)
diff --git a/.github/scripts/update_maintainers.py b/.github/scripts/update_maintainers.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+
+import json
+import os
+import time
+from datetime import datetime, timezone, timedelta
+
+import requests
+
+# โโ Config โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+REPO = "is-a-dev/register"
+CACHE_FILE = "pr_cache.json"
+OUTPUT_FILE = "maintainers.json"
+
+MAINTAINERS = [
+ "Yunexiz", "wdhdev", "STICKnoLOGIC", "Stef-00012",
+ "satr14washere", "orangci", "omsenjalia", "notamitgamer",
+ "iostpa", "dragsbruh", "DEV-DIBSTER",
+]
+
+GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "")
+HEADERS = {
+ "Accept": "application/vnd.github+json",
+ "X-GitHub-Api-Version": "2022-11-28",
+ "Authorization": f"Bearer {GITHUB_TOKEN}",
+}
+
+# โโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+def now_utc() -> datetime:
+ return datetime.now(timezone.utc)
+
+
+def next_update_utc(now: datetime) -> datetime:
+ """
+ Cron is '0 */1 * * *' โ fires at the top of every hour.
+ Next update = start of the next hour.
+ """
+ next_hour = now.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
+ return next_hour
+
+
+def fetch_contributor_stats() -> list:
+ """
+ Fetch /stats/contributors. GitHub computes this asynchronously โ
+ if it returns 202, we wait and retry until we get 200.
+ """
+ url = f"https://api.github.com/repos/{REPO}/stats/contributors"
+ for attempt in range(10):
+ r = requests.get(url, headers=HEADERS, timeout=30)
+ if r.status_code == 202:
+ print(f" GitHub is computing stats, waiting 5s โฆ (attempt {attempt+1})", flush=True)
+ time.sleep(5)
+ continue
+ if r.status_code == 204:
+ print(" No stats available yet.", flush=True)
+ return []
+ r.raise_for_status()
+ return r.json()
+ raise RuntimeError("GitHub stats endpoint kept returning 202 after 10 attempts")
+
+
+def week_to_month_key(ts: int) -> str:
+ """Convert a Unix week timestamp to YYYY-MM key of the month it falls in."""
+ dt = datetime.fromtimestamp(ts, tz=timezone.utc)
+ return f"{dt.year}-{dt.month:02d}"
+
+
+def this_month_key() -> str:
+ now = now_utc()
+ return f"{now.year}-{now.month:02d}"
+
+
+def last_month_key() -> str:
+ now = now_utc()
+ y, m = now.year, now.month
+ if m == 1:
+ y, m = y - 1, 12
+ else:
+ m -= 1
+ return f"{y}-{m:02d}"
+
+# โโ Cache โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+def load_cache() -> dict:
+ if os.path.exists(CACHE_FILE):
+ with open(CACHE_FILE) as f:
+ return json.load(f)
+ return {}
+
+
+def save_cache(cache: dict):
+ with open(CACHE_FILE, "w") as f:
+ json.dump(cache, f, indent=2)
+
+# โโ Main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+def main():
+ if not GITHUB_TOKEN:
+ raise RuntimeError("GITHUB_TOKEN not set")
+
+ cache = load_cache()
+ print("Fetching contributor stats (single API call) โฆ", flush=True)
+ stats = fetch_contributor_stats()
+
+ if not stats:
+ print("No stats returned, aborting.", flush=True)
+ return
+
+ maintainers_lower = {m.lower(): m for m in MAINTAINERS}
+ this_key = this_month_key()
+ last_key = last_month_key()
+
+ # Build monthly totals per maintainer from the weekly data
+ # weekly_data: { "username": { "YYYY-MM": total_commits } }
+ weekly_data = {}
+ for contributor in stats:
+ login = (contributor.get("author") or {}).get("login", "")
+ if not login or login.lower() not in maintainers_lower:
+ continue
+
+ canonical = maintainers_lower[login.lower()]
+ monthly = {}
+ for week in contributor.get("weeks", []):
+ commits = week.get("c", 0)
+ if commits == 0:
+ continue
+ mk = week_to_month_key(week["w"])
+ monthly[mk] = monthly.get(mk, 0) + commits
+
+ weekly_data[canonical] = monthly
+ print(f" {canonical}: {sum(monthly.values())} total commits across {len(monthly)} active months", flush=True)
+
+ # Merge into cache โ update only months that changed
+ for username, monthly in weekly_data.items():
+ user_cache = cache.get(username, {})
+ for mk, count in monthly.items():
+ user_cache[mk] = count # overwrite (stats endpoint is authoritative)
+ cache[username] = user_cache
+
+ save_cache(cache)
+ print(f"\nโ Cache saved to {CACHE_FILE}", flush=True)
+
+ # Build output
+ now = now_utc()
+ maintainers_output = []
+ for username in MAINTAINERS:
+ user_cache = cache.get(username, {})
+ all_time = sum(user_cache.values())
+ this_month = user_cache.get(this_key, 0)
+ last_month = user_cache.get(last_key, 0)
+
+ print(f" {username}: all={all_time} this_month={this_month} last_month={last_month}", flush=True)
+ maintainers_output.append({
+ "username": username,
+ "stats": {
+ "all_time": all_time,
+ "this_month": this_month,
+ "last_month": last_month,
+ },
+ })
+
+ output = {
+ "meta": {
+ "last_updated": now.isoformat(),
+ "next_update": next_update_utc(now).isoformat(),
+ },
+ "maintainers": maintainers_output,
+ }
+
+ with open(OUTPUT_FILE, "w") as f:
+ json.dump(output, f, indent=2)
+
+ print(f"โ Written to {OUTPUT_FILE}", flush=True)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/job.yml b/.github/workflows/job.yml
@@ -0,0 +1,37 @@
+name: Auto-Update Maintainer Activity
+
+on:
+ schedule:
+ - cron: '0 0 * * *'
+ workflow_dispatch:
+
+jobs:
+ update-maintainers:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v4
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.x'
+
+ - name: Install Dependencies
+ run: pip install requests
+
+ - name: Run Maintainer Activity Script
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: python .github/scripts/update_maintainers.py
+
+ - name: Commit and Push maintainers.json
+ run: |
+ git config --global user.name "github-actions[bot]"
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git add maintainers.json
+ git diff --quiet && git diff --staged --quiet || \
+ (git commit -m "chore: auto-update maintainer activity" && git push)
diff --git a/.github/workflows/update_readme.yml b/.github/workflows/update_readme.yml
@@ -0,0 +1,33 @@
+name: Auto-Update Recent Commits
+
+on:
+ schedule:
+ - cron: '0 */1 * * *' # every hour
+ workflow_dispatch:
+
+jobs:
+ update-readme:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v4
+
+ - name: Setup Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.x'
+
+ - name: Run Python Script to update README
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: python .github/scripts/update_commits.py
+
+ - name: Commit and Push Changes
+ run: |
+ git config --global user.name "github-actions[bot]"
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git add README.md
+ git diff --quiet && git diff --staged --quiet || (git commit -m "docs: auto-update recent commits" && git push)
diff --git a/README.md b/README.md
@@ -0,0 +1,92 @@
+<div align="center">
+
+```
+ โโโโโโ โโโโ โโโโโโโโโโโโโโโโ
+โโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
+โโโโโโโโโโโโโโโโโโโโโโ โโโ
+โโโโโโโโโโโโโโโโโโโโโโ โโโ
+โโโ โโโโโโ โโโ โโโโโโ โโโ
+โโโ โโโโโโ โโโโโโ โโโ
+```
+
+**CS Undergrad ยท Full Stack Developer (Maybe)**<br>
+**Reviewer at <a href="https://github.com/is-a-dev">is-a.dev</a> and <a href="https://github.com/free-domains">free-domains</a> organization** โ *professional button-clicker*
+<br><br>***Status: 404 - Girlfriend Not Found***
+
+[](https://amit.is-a.dev)
+[](mailto:amitdutta4255@gmail.com)
+[](mailto:mail@amit.is-a.dev)
+[](https://linkedin.com/in/notamitgamer)
+[](https://x.com/notamitgamer)
+[](https://instagram.com/notamitgamer)
+[](https://orcid.org/0009-0006-8834-9881)
+[](https://www.crunchbase.com/person/amit-dutta-d32d)
+<br><br>
+[](https://discord.com/users/1274721760088166495)
+
+</div>
+
+- **visit [git.amit.is-a.dev](https://git.amit.is-a.dev) instead of surfing through github, because it's better and faster.**
+- **also visit [forgejo.amit.is-a.dev](https://forgejo.amit.is-a.dev) to visit my self-hosted git.**
+---
+
+### About
+
+B.Sc. Hons Computer Science student at **Acharya Prafulla Chandra College, Kolkata**, currently in semester 2 and still googling things I "*learned*" in semester 1. I build tools, libraries, and web utilities โ mostly things I wish existed, occasionally things nobody asked for.
+
+- 1st year ยท Semester 2 ยท *professional deadline-approacher*
+- Currently working on โ **Sem 2 Prep** (a.k.a. panic)
+- Freelance โ **Unavailable** *(see: Sem 2 Prep)*
+- Status โ probably debugging something that worked five minutes ago
+- [My website โ](https://amit.is-a.dev) ยท [More about me โ](https://amit.is-a.dev/about) ยท [Google Knowledge Graph โ](https://www.google.com/search?kgmid=/g/11yzcqs5ff)
+
+---
+
+### Stack
+
+* **Primary:** `Python` โ my one true love (when coding, obviously), no jealousy issues
+* **Web & Systems:** `HTML5`, `CSS3`, `JavaScript`, `Java`, `C`, `C++`, `Kotlin`, `Google Apps Script` โ mostly friendly, occasionally at war
+* **Services:** `Firebase`, `Firestore`, `Gemini API`, `Render` โ the free-tier survival kit
+* **Tooling:** `Git` โ my time machine and my regret log
+
+---
+
+### Projects
+
+- [WhatsApp Logger โ](https://amit.is-a.dev/logger) ยท [GitHub โ](https://github.com/notamitgamer/WhatsApp-Logger-Self-Hosted-) โ Self-hosted archiver. Not spying, just... very thorough remembering.
+
+- [Veyrix IDE โ](https://veyrix.amit.is-a.dev) ยท [Docs โ](https://veyrix.amit.is-a.dev/docs) โ Lightweight, browser-based code editor. Built after one too many "*I forgot to bring the assignment*" moments โ write the code, download it in any extension, print, done.
+
+- [Githrun โ](https://amit.is-a.dev/githrun) ยท [PyPI โ](https://pypi.org/project/githrun) โ Run GitHub scripts without cloning, for people (me) too impatient to `git clone`.
+
+- [BSC Repository โ](https://code.amit.is-a.dev) ยท [GitHub โ](https://github.com/notamitgamer/bsc) โ Every B.Sc. practical I've ever suffered through, preserved for posterity.
+
+---
+
+### Recent Commits
+*(Or: what I was procrastinating on instead of Sem 2 Prep)*
+<!-- START_RECENT_COMMITS -->
+- [Merge pull request #31 from YOCRRZ224/patch-1](https://github.com/notamitgamer/cdnV2/commit/e93ad33e1df77d90d69ecbad41d345d8148b4bc1) in [notamitgamer/cdnV2](https://github.com/notamitgamer/cdnV2)
+- [Merge pull request #29 from notamitgamer/migration](https://github.com/notamitgamer/cdnV2/commit/f5afc3459d8f26fe2a23df9421fb1229f25af35a) in [notamitgamer/cdnV2](https://github.com/notamitgamer/cdnV2)
+- [Update upload guard to use bucket URL and auth headers](https://github.com/notamitgamer/cdnV2/commit/62321f14a3aade5cb5fbb73a417b753296b9a918) in [notamitgamer/cdnV2](https://github.com/notamitgamer/cdnV2)
+- [Refactor URL shortening to use new storage methods](https://github.com/notamitgamer/cdnV2/commit/030954f698e256154339e2c4629261103cc06aa5) in [notamitgamer/cdnV2](https://github.com/notamitgamer/cdnV2)
+- [Refactor Hugging Face URL handling and auth headers](https://github.com/notamitgamer/cdnV2/commit/7fa82dbd011a4379673c2795b4052239cd5945fd) in [notamitgamer/cdnV2](https://github.com/notamitgamer/cdnV2)
+<!-- END_RECENT_COMMITS -->
+
+---
+
+### GitHub Stats
+
+<div align="center">
+
+
+
+
+
+</div>
+
+---
+
+<div align="center">
+ <img src="https://komarev.com/ghpvc/?username=notamitgamer&style=for-the-badge" alt="Profile Views">
+</div>
diff --git a/a.cpp b/a.cpp
@@ -0,0 +1,78 @@
+#include <iostream>
+using namespace std;
+
+template<typename T>
+class BinarySearch {
+private:
+ T *arr;
+ int size;
+
+public:
+ BinarySearch() : arr(nullptr), size(0) {}
+
+ ~BinarySearch() {
+ delete[] arr;
+ }
+
+ T inputArray() {
+ cout << "How many elements do you want to enter: ";
+ cin >> size;
+
+ arr = new T[size];
+
+ for (int i = 0; i < size; i++) {
+ cout << "Enter element for position " << i << ": ";
+ cin >> arr[i];
+ }
+
+ T target;
+ cout << "\nEnter the target element: ";
+ cin >> target;
+
+ return target;
+ }
+
+ void sortArray() {
+ for (int i = 0; i < size - 1; i++) {
+ for (int j = 0; j < size - i - 1; j++) {
+ if (arr[j] > arr[j + 1]) {
+ T temp = arr[j];
+ arr[j] = arr[j + 1];
+ arr[j + 1] = temp;
+ }
+ }
+ }
+ }
+
+ int binarySearch(T target) {
+ int low = 0;
+ int high = size - 1;
+
+ while (low <= high) {
+ int mid = low + ((high - low) / 2);
+ if (arr[mid] == target) {
+ return mid;
+ } else if (arr[mid] > target) {
+ high = mid - 1;
+ } else {
+ low = mid + 1;
+ }
+ }
+ return -1;
+ }
+};
+
+int main() {
+ BinarySearch<int> bs;
+ int target = bs.inputArray();
+ bs.sortArray();
+ int index = bs.binarySearch(target);
+
+ if (index != -1) {
+ cout << "\nElement " << target << " is found at index " << index << ".";
+ } else {
+ cout << "\nElement " << target << " is not found.";
+ }
+
+ return 0;
+}
+\ No newline at end of file
diff --git a/banner-m.png b/banner-m.png
Binary files differ.
diff --git a/discord b/discord
@@ -0,0 +1,166 @@
+{
+ delete window.$;
+ let wpRequire = webpackChunkdiscord_app.push([[Symbol()], {}, r => r]);
+ webpackChunkdiscord_app.pop();
+
+ let ApplicationStreamingStore = Object.values(wpRequire.c).find(x => x?.exports?.A?.__proto__?.getStreamerActiveStreamMetadata).exports.A;
+ let RunningGameStore = Object.values(wpRequire.c).find(x => x?.exports?.Ay?.getRunningGames).exports.Ay;
+ let QuestsStore = Object.values(wpRequire.c).find(x => x?.exports?.A?.__proto__?.getQuest).exports.A;
+ let ChannelStore = Object.values(wpRequire.c).find(x => x?.exports?.A?.__proto__?.getAllThreadsForParent).exports.A;
+ let GuildChannelStore = Object.values(wpRequire.c).find(x => x?.exports?.Ay?.getSFWDefaultChannel).exports.Ay;
+ let FluxDispatcher = Object.values(wpRequire.c).find(x => x?.exports?.h?.__proto__?.flushWaitQueue).exports.h;
+ let api = Object.values(wpRequire.c).find(x => x?.exports?.Bo?.get).exports.Bo;
+
+ const supportedTasks = ["WATCH_VIDEO", "PLAY_ON_DESKTOP", "STREAM_ON_DESKTOP", "PLAY_ACTIVITY", "WATCH_VIDEO_ON_MOBILE"]
+ let quests = [...QuestsStore.quests.values()].filter(x => x.userStatus?.enrolledAt && !x.userStatus?.completedAt && new Date(x.config.expiresAt).getTime() > Date.now() && supportedTasks.find(y => Object.keys((x.config.taskConfig ?? x.config.taskConfigV2).tasks).includes(y)))
+ let isApp = typeof DiscordNative !== "undefined"
+ if(quests.length === 0) {
+ console.log("You don't have any uncompleted quests!")
+ } else {
+ let doJob = function() {
+ const quest = quests.pop()
+ if(!quest) return
+
+ const pid = Math.floor(Math.random() * 30000) + 1000
+
+ const applicationId = quest.config.application.id
+ const applicationName = quest.config.application.name
+ const questName = quest.config.messages.questName
+ const taskConfig = quest.config.taskConfig ?? quest.config.taskConfigV2
+ const taskName = supportedTasks.find(x => taskConfig.tasks[x] != null)
+ const secondsNeeded = taskConfig.tasks[taskName].target
+ let secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0
+
+ if(taskName === "WATCH_VIDEO" || taskName === "WATCH_VIDEO_ON_MOBILE") {
+ const speed = 7
+ const enrolledAt = new Date(quest.userStatus.enrolledAt).getTime()
+ let completed = false
+ let fn = async () => {
+ while(true) {
+ const remaining = Math.min(speed, secondsNeeded - secondsDone)
+ await new Promise(resolve => setTimeout(resolve, remaining * 1000))
+
+ const timestamp = secondsDone + speed
+ const res = await api.post({url: `/quests/${quest.id}/video-progress`, body: {timestamp: Math.min(secondsNeeded, timestamp + Math.random())}})
+ completed = res.body.completed_at != null
+ secondsDone = Math.min(secondsNeeded, timestamp)
+
+ if(timestamp >= secondsNeeded) {
+ break
+ }
+ }
+ if(!completed) {
+ await api.post({url: `/quests/${quest.id}/video-progress`, body: {timestamp: secondsNeeded}})
+ }
+ console.log("Quest completed!")
+ doJob()
+ }
+ fn()
+ console.log(`Spoofing video for ${questName}.`)
+ } else if(taskName === "PLAY_ON_DESKTOP") {
+ if(!isApp) {
+ console.log("This no longer works in browser for non-video quests. Use the discord desktop app to complete the", questName, "quest!")
+ } else {
+ api.get({url: `/applications/public?application_ids=${applicationId}`}).then(res => {
+ const appData = res.body[0]
+ const exeName = appData.executables?.find(x => x.os === "win32")?.name?.replace(">","") ?? appData.name.replace(/[\/\\:*?"<>|]/g, "")
+
+ const fakeGame = {
+ cmdLine: `C:\\Program Files\\${appData.name}\\${exeName}`,
+ exeName,
+ exePath: `c:/program files/${appData.name.toLowerCase()}/${exeName}`,
+ hidden: false,
+ isLauncher: false,
+ id: applicationId,
+ name: appData.name,
+ pid: pid,
+ pidPath: [pid],
+ processName: appData.name,
+ start: Date.now(),
+ }
+ const realGames = RunningGameStore.getRunningGames()
+ const fakeGames = [fakeGame]
+ const realGetRunningGames = RunningGameStore.getRunningGames
+ const realGetGameForPID = RunningGameStore.getGameForPID
+ RunningGameStore.getRunningGames = () => fakeGames
+ RunningGameStore.getGameForPID = (pid) => fakeGames.find(x => x.pid === pid)
+ FluxDispatcher.dispatch({type: "RUNNING_GAMES_CHANGE", removed: realGames, added: [fakeGame], games: fakeGames})
+
+ let fn = data => {
+ let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value)
+ console.log(`Quest progress: ${progress}/${secondsNeeded}`)
+
+ if(progress >= secondsNeeded) {
+ console.log("Quest completed!")
+
+ RunningGameStore.getRunningGames = realGetRunningGames
+ RunningGameStore.getGameForPID = realGetGameForPID
+ FluxDispatcher.dispatch({type: "RUNNING_GAMES_CHANGE", removed: [fakeGame], added: [], games: []})
+ FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
+
+ doJob()
+ }
+ }
+ FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
+
+ console.log(`Spoofed your game to ${applicationName}. Wait for ${Math.ceil((secondsNeeded - secondsDone) / 60)} more minutes.`)
+ })
+ }
+ } else if(taskName === "STREAM_ON_DESKTOP") {
+ if(!isApp) {
+ console.log("This no longer works in browser for non-video quests. Use the discord desktop app to complete the", questName, "quest!")
+ } else {
+ let realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata
+ ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({
+ id: applicationId,
+ pid,
+ sourceName: null
+ })
+
+ let fn = data => {
+ let progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value)
+ console.log(`Quest progress: ${progress}/${secondsNeeded}`)
+
+ if(progress >= secondsNeeded) {
+ console.log("Quest completed!")
+
+ ApplicationStreamingStore.getStreamerActiveStreamMetadata = realFunc
+ FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
+
+ doJob()
+ }
+ }
+ FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn)
+
+ console.log(`Spoofed your stream to ${applicationName}. Stream any window in vc for ${Math.ceil((secondsNeeded - secondsDone) / 60)} more minutes.`)
+ console.log("Remember that you need at least 1 other person to be in the vc!")
+ }
+ } else if(taskName === "PLAY_ACTIVITY") {
+ const channelId = ChannelStore.getSortedPrivateChannels()[0]?.id ?? Object.values(GuildChannelStore.getAllGuilds()).find(x => x != null && x.VOCAL.length > 0).VOCAL[0].channel.id
+ const streamKey = `call:${channelId}:1`
+
+ let fn = async () => {
+ console.log("Completing quest", questName, "-", quest.config.messages.questName)
+
+ while(true) {
+ const res = await api.post({url: `/quests/${quest.id}/heartbeat`, body: {stream_key: streamKey, terminal: false}})
+ const progress = res.body.progress.PLAY_ACTIVITY.value
+ console.log(`Quest progress: ${progress}/${secondsNeeded}`)
+
+ await new Promise(resolve => setTimeout(resolve, 20 * 1000))
+
+ if(progress >= secondsNeeded) {
+ await api.post({url: `/quests/${quest.id}/heartbeat`, body: {stream_key: streamKey, terminal: true}})
+ break
+ }
+ }
+
+ console.log("Quest completed!")
+ doJob()
+ }
+ fn()
+ }
+ }
+ doJob()
+ }
+}
diff --git a/giphy-unscreen.gif b/giphy-unscreen.gif
Binary files differ.
diff --git a/giphy-unscreen2.gif b/giphy-unscreen2.gif
Binary files differ.
diff --git a/maintainers.json b/maintainers.json
@@ -0,0 +1,96 @@
+{
+ "meta": {
+ "last_updated": "2026-10-07T03:56:32.273086+00:00",
+ "next_update": "2026-10-07T04:00:00+00:00"
+ },
+ "maintainers": [
+ {
+ "username": "Yunexiz",
+ "stats": {
+ "all_time": 320,
+ "this_month": 0,
+ "last_month": 0
+ }
+ },
+ {
+ "username": "wdhdev",
+ "stats": {
+ "all_time": 2185,
+ "this_month": 0,
+ "last_month": 5
+ }
+ },
+ {
+ "username": "STICKnoLOGIC",
+ "stats": {
+ "all_time": 4249,
+ "this_month": 0,
+ "last_month": 0
+ }
+ },
+ {
+ "username": "Stef-00012",
+ "stats": {
+ "all_time": 0,
+ "this_month": 0,
+ "last_month": 0
+ }
+ },
+ {
+ "username": "satr14washere",
+ "stats": {
+ "all_time": 287,
+ "this_month": 0,
+ "last_month": 0
+ }
+ },
+ {
+ "username": "orangci",
+ "stats": {
+ "all_time": 2102,
+ "this_month": 1,
+ "last_month": 8
+ }
+ },
+ {
+ "username": "omsenjalia",
+ "stats": {
+ "all_time": 299,
+ "this_month": 0,
+ "last_month": 0
+ }
+ },
+ {
+ "username": "notamitgamer",
+ "stats": {
+ "all_time": 1196,
+ "this_month": 0,
+ "last_month": 85
+ }
+ },
+ {
+ "username": "iostpa",
+ "stats": {
+ "all_time": 4003,
+ "this_month": 3,
+ "last_month": 19
+ }
+ },
+ {
+ "username": "dragsbruh",
+ "stats": {
+ "all_time": 1299,
+ "this_month": 20,
+ "last_month": 2
+ }
+ },
+ {
+ "username": "DEV-DIBSTER",
+ "stats": {
+ "all_time": 5247,
+ "this_month": 0,
+ "last_month": 8
+ }
+ }
+ ]
+}
+\ No newline at end of file
diff --git a/package.json b/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "email-router",
+ "version": "1.0.1",
+ "description": "Custom email routing webhook for Render",
+ "main": "server.js",
+ "scripts": {
+ "start": "node server.js"
+ },
+ "dependencies": {
+ "cors": "^2.8.5",
+ "express": "^4.19.0",
+ "mongoose": "^8.3.0",
+ "resend": "^3.2.0",
+ "svix": "^1.24.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+}
diff --git a/server.js b/server.js
@@ -0,0 +1,257 @@
+const express = require('express');
+const { Resend } = require('resend');
+const { Webhook } = require('svix');
+
+const app = express();
+const port = process.env.PORT || 3000;
+
+const resend = new Resend(process.env.RESEND_API_KEY);
+const webhookSecret = process.env.RESEND_WEBHOOK_SECRET;
+
+app.post('/api/incoming', express.text({ type: 'application/json' }), async (req, res) => {
+ try {
+ const rawBody = req.body;
+ const headers = {
+ 'svix-id': req.headers['svix-id'],
+ 'svix-timestamp': req.headers['svix-timestamp'],
+ 'svix-signature': req.headers['svix-signature'],
+ };
+
+ const wh = new Webhook(webhookSecret);
+ let event;
+
+ try {
+ event = wh.verify(rawBody, headers);
+ } catch (err) {
+ console.error(err.message);
+ return res.status(400).json({ error: 'Invalid signature' });
+ }
+
+ if (event.type !== 'email.received') {
+ return res.status(200).json({ message: 'Not an email event' });
+ }
+
+ const emailData = event.data;
+ const originalSender = emailData.from;
+ const originalRecipient = emailData.to[0].toLowerCase();
+ const subject = emailData.subject || 'No Subject';
+
+ const allowedString = process.env.ALLOWED_ALIASES || '';
+ const allowedAliases = allowedString.split(',').map(alias => alias.trim().toLowerCase());
+
+ if (!allowedAliases.includes(originalRecipient)) {
+ return res.status(200).json({ success: true, message: 'Alias ignored' });
+ }
+
+ const personalGmail = process.env.PERSONAL_GMAIL;
+ const forwardingAddress = process.env.FORWARDING_BOT_ADDRESS;
+
+ // Premium Adaptive Google-style HTML Template
+ const notificationHtml = `
+<!DOCTYPE html>
+<html lang="en" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="color-scheme" content="light dark">
+ <meta name="supported-color-schemes" content="light dark">
+ <title>New Email Notification</title>
+
+ <style>
+ @import url('https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500&family=Roboto+Mono:wght@400;500&family=Roboto:wght@400;500&display=swap');
+
+ body {
+ margin: 0;
+ padding: 0;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+
+ .btn-pill:hover {
+ opacity: 0.9;
+ transform: translateY(-1px);
+ transition: all 0.2s ease;
+ }
+
+ @media (prefers-color-scheme: dark) {
+ .bg-outer { background-color: #131314 !important; }
+ .bg-card { background-color: #1E1F20 !important; }
+ .bg-tint { background-color: #282A2C !important; }
+ .text-primary { color: #E3E3E3 !important; }
+ .text-secondary { color: #C4C7C5 !important; }
+ .text-accent { color: #A8C7FA !important; }
+ .border-card { border-color: #444746 !important; }
+ .divider { background-color: #444746 !important; }
+ .btn-pill {
+ background-color: #A8C7FA !important;
+ color: #000000 !important;
+ }
+ .icon-fill { fill: #8E918F !important; }
+ }
+
+ /* Gmail Dark Mode Fixes */
+ [data-ogsb] .bg-outer { background-color: #131314 !important; }
+ [data-ogsb] .bg-card { background-color: #1E1F20 !important; }
+ [data-ogsb] .bg-tint { background-color: #282A2C !important; }
+ [data-ogsc] .text-primary { color: #E3E3E3 !important; }
+ [data-ogsc] .text-secondary { color: #C4C7C5 !important; }
+ [data-ogsc] .text-accent { color: #A8C7FA !important; }
+ [data-ogsb] .border-card { border-color: #444746 !important; }
+ [data-ogsb] .divider { background-color: #444746 !important; }
+ [data-ogsb] .btn-pill { background-color: #A8C7FA !important; }
+ [data-ogsc] .btn-pill { color: #000000 !important; }
+ [data-ogsc] .icon-fill { fill: #8E918F !important; }
+ </style>
+</head>
+
+<body class="bg-outer" style="margin: 0; padding: 0; background-color: #F8F9FA; font-family: 'Google Sans', Roboto, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased;">
+
+ <table width="100%" border="0" cellspacing="0" cellpadding="0" class="bg-outer" style="background-color: #F8F9FA; width: 100%; height: 100%;">
+ <tr>
+ <td align="center" style="padding: 40px 16px;">
+
+ <table border="0" cellspacing="0" cellpadding="0" class="bg-card border-card" style="background-color: #FFFFFF; border-radius: 28px; max-width: 600px; width: 100%; overflow: hidden; border: 1px solid #C4C7C5;">
+
+ <tr>
+ <td style="padding: 40px 32px 16px 32px;">
+ <h2 class="text-primary" style="margin: 0; font-family: 'Google Sans', Roboto, sans-serif; font-size: 22px; font-weight: 500; color: #1F1F1F; letter-spacing: -0.5px;">Incoming Message</h2>
+ <p class="text-secondary" style="margin: 8px 0 0 0; font-family: Roboto, Arial, sans-serif; font-size: 14px; font-weight: 400; color: #444746; line-height: 1.5;">A new email has been routed to your developer inbox.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td style="padding: 0 32px;">
+ <div class="divider" style="height: 1px; background-color: #E3E3E3; width: 100%; margin: 16px 0;"></div>
+ </td>
+ </tr>
+
+ <tr>
+ <td style="padding: 16px 32px;">
+
+ <div style="margin-bottom: 24px;">
+ <span class="text-accent" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 11px; font-weight: 500; color: #0B57D0; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 6px;">Sender Email ID</span>
+ <span class="text-primary" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 16px; font-weight: 400; color: #1F1F1F; word-break: break-all; line-height: 1.4;">${originalSender}</span>
+ </div>
+
+ <div style="margin-bottom: 24px;">
+ <span class="text-accent" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 11px; font-weight: 500; color: #0B57D0; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 6px;">Subject</span>
+ <span class="text-primary" style="display: block; font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 18px; font-weight: 500; color: #1F1F1F; line-height: 1.4;">${subject}</span>
+ </div>
+
+ <div style="margin-bottom: 32px;">
+ <span class="text-accent" style="display: block; font-family: Roboto, Arial, sans-serif; font-size: 11px; font-weight: 500; color: #0B57D0; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 8px;">Email Tracking ID</span>
+
+ <table border="0" cellspacing="0" cellpadding="0" style="width: 100%;">
+ <tr>
+ <td class="bg-tint" style="background-color: #F0F4F9; border-radius: 8px; padding: 12px 16px;">
+ <span class="text-secondary" style="display: block; font-family: 'Roboto Mono', monospace; font-size: 14px; font-weight: 500; color: #444746; word-break: break-all;">
+ ${emailData.email_id || 'N/A'}
+ </span>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ </td>
+ </tr>
+
+ <tr>
+ <td style="padding: 8px 32px 40px 32px;">
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td align="center" style="border-radius: 100px;">
+ <a href="https://resend.com/emails/${emailData.email_id}" target="_blank" class="btn-pill" style="display: inline-block; padding: 12px 32px; background-color: #0B57D0; font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 14px; font-weight: 500; color: #FFFFFF; text-decoration: none; border-radius: 100px;">
+ Open Resend Dashboard
+ </a>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ </table>
+
+ <table border="0" cellspacing="0" cellpadding="0" style="max-width: 600px; width: 100%; margin-top: 32px;">
+ <tr>
+ <td align="center" style="padding-bottom: 24px;">
+ <p class="text-secondary" style="margin: 0; font-family: Roboto, Arial, sans-serif; font-size: 12px; color: #747775; line-height: 1.6;">Automated alert by Notifier Bot.<br>Please do not reply to this unmonitored email.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="center" style="padding-bottom: 16px;">
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td style="padding: 0 12px;">
+ <a href="https://amit.is-a.dev" target="_blank" style="text-decoration: none;" title="Website">
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="#747775" class="icon-fill" xmlns="http://www.w3.org/2000/svg" style="display: block; border: 0;">
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
+ </svg>
+ </a>
+ </td>
+ <td style="padding: 0 12px;">
+ <a href="https://github.com/notamitgamer" target="_blank" style="text-decoration: none;" title="GitHub">
+ <svg width="20" height="20" viewBox="0 0 16 16" fill="#747775" class="icon-fill" xmlns="http://www.w3.org/2000/svg" style="display: block; border: 0;">
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
+ </svg>
+ </a>
+ </td>
+ <td style="padding: 0 12px;">
+ <a href="mailto:amitdutta4255@gmail.com" style="text-decoration: none;" title="Email">
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="#747775" class="icon-fill" xmlns="http://www.w3.org/2000/svg" style="display: block; border: 0;">
+ <path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
+ </svg>
+ </a>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="center">
+ <p class="text-secondary" style="margin: 0; font-family: Roboto, Arial, sans-serif; font-size: 12px; color: #747775;">
+ © 2025-2026 Amit Dutta • <a href="https://amit.is-a.dev" class="text-secondary" style="color: #747775; text-decoration: none;">amit.is-a.dev</a>
+ </p>
+ </td>
+ </tr>
+ </table>
+
+ </td>
+ </tr>
+ </table>
+
+</body>
+</html>
+ `;
+
+ const payload = {
+ from: `Notifier Bot <${forwardingAddress}>`,
+ to: [personalGmail],
+ reply_to: originalSender,
+ subject: subject,
+ html: notificationHtml
+ };
+
+ const { data, error } = await resend.emails.send(payload);
+
+ if (error) {
+ console.error(error);
+ return res.status(500).json({ error: error.message });
+ }
+
+ return res.status(200).json({ success: true, id: data?.id });
+
+ } catch (error) {
+ console.error(error);
+ return res.status(500).json({ error: 'Internal Server Error' });
+ }
+});
+
+app.get('/ping', (req, res) => {
+ res.status(200).send('Server is awake!');
+});
+
+app.listen(port, () => {
+ console.log(`Email router listening on port ${port}`);
+});
diff --git a/style.css b/style.css
@@ -0,0 +1,407 @@
+/* ===== Archie-style theme, no Hugo ===== */
+
+/* Light theme (default) */
+:root {
+ --primary: #dc143c;
+ --primary-hover: #b91c3c;
+ --on-primary: #ffffff;
+ --border: #663399;
+ --text: #232333;
+ --heading: #232333;
+ --muted: #737373;
+ --meta: #767676;
+ --bg: #ffffff;
+ --code-bg: #f1f1f1;
+ --pre-bg: #ececec;
+
+ --content-max-width: 800px;
+ --content-padding: 1ch;
+ --radius: 5px;
+}
+
+/* Dark theme: follows the system unless the user chose light */
+@media (prefers-color-scheme: dark) {
+ :root:not([data-theme="light"]) {
+ --primary: #50fa7b;
+ --primary-hover: #50fa7b;
+ --on-primary: #000000;
+ --border: #0066ff;
+ --text: #ffffff;
+ --heading: #dddddd;
+ --muted: #dddddd;
+ --meta: #b5b5b5;
+ --bg: #202124;
+ --code-bg: #3a3a3a;
+ --pre-bg: #272822;
+ }
+}
+
+/* Dark theme: chosen manually with the toggle */
+:root[data-theme="dark"] {
+ --primary: #50fa7b;
+ --primary-hover: #50fa7b;
+ --on-primary: #000000;
+ --border: #0066ff;
+ --text: #ffffff;
+ --heading: #dddddd;
+ --muted: #dddddd;
+ --meta: #b5b5b5;
+ --bg: #202124;
+ --code-bg: #3a3a3a;
+ --pre-bg: #272822;
+}
+
+/* ===== Reset / base ===== */
+*, *::before, *::after { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
+
+html {
+ color: var(--text);
+ font-family: 'Roboto Mono', 'Courier New', monospace;
+ font-size: 15px;
+ line-height: 1.6;
+ scroll-behavior: smooth;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ html { scroll-behavior: auto; }
+}
+
+body {
+ margin: 8px;
+ background-color: var(--bg);
+ color: var(--text);
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+::selection { background: var(--primary); color: var(--on-primary); }
+
+p {
+ font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ line-height: 1.5;
+ margin-block: 0.5em;
+}
+
+hr {
+ border: 0;
+ border-block-start: 3px dotted var(--border);
+ margin-block: 1em;
+}
+
+blockquote {
+ border-inline-start: 3px solid var(--border);
+ padding-inline-start: 1em;
+ color: var(--muted);
+ margin: 0;
+ font-style: italic;
+}
+
+/* ===== Links (thick underline, fill on hover) ===== */
+a {
+ border-block-end: 3px solid var(--primary);
+ color: inherit;
+ text-decoration: none;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+a:hover,
+a:focus {
+ background-color: var(--primary-hover);
+ color: var(--on-primary);
+ outline: 2px solid var(--primary);
+ outline-offset: 2px;
+}
+
+/* small arrow on external links */
+a[target="_blank"]::after {
+ content: "โ";
+ display: inline-block;
+ margin-left: 0.2em;
+ font-size: 0.8em;
+}
+/* but not on image/icon-only links or the site name */
+header .main a::after,
+.no-arrow::after,
+.readmore::after { content: none !important; }
+
+/* ===== Lists: "* " markers ===== */
+ul {
+ list-style: none;
+ padding-inline-start: 2ch;
+}
+ul li { text-indent: -2ch; }
+ul > li::before {
+ content: '* ';
+ font-weight: bold;
+ color: var(--primary);
+}
+
+/* ===== Images ===== */
+img {
+ border: 3px solid var(--pre-bg);
+ max-inline-size: 100%;
+ block-size: auto;
+ border-radius: var(--radius);
+}
+
+/* ===== Code ===== */
+code {
+ background-color: var(--code-bg);
+ padding: 0.1em 0.2em;
+ border-radius: 3px;
+ font-size: 0.9em;
+}
+pre {
+ background-color: var(--pre-bg);
+ line-height: 1.4;
+ overflow-x: auto;
+ padding: 1em;
+ border-radius: var(--radius);
+ border: 1px solid var(--border);
+}
+pre code { background: transparent; padding: 0; font-size: 100%; }
+
+/* ===== Layout ===== */
+.content {
+ max-inline-size: var(--content-max-width);
+ margin-inline: auto;
+ margin-block-end: 4em;
+ padding-inline: var(--content-padding);
+ overflow-wrap: break-word;
+}
+
+/* ===== Header ===== */
+header {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ margin-block: 1em;
+ line-height: 2.5em;
+ gap: 1rem;
+}
+
+header .main {
+ font-size: 1.5rem;
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+}
+
+header .main img.avatar {
+ width: 48px;
+ height: 48px;
+ object-fit: cover;
+ border-radius: 50%;
+}
+
+nav {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+/* theme toggle (icon button) */
+.nav-toggle {
+ appearance: none;
+ -webkit-appearance: none;
+ border: none;
+ background: none;
+ margin: 0;
+ font: inherit;
+ cursor: pointer;
+ padding: 0.5rem;
+ border-radius: 4px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text);
+ transition: all 0.2s ease;
+}
+.nav-toggle:hover,
+.nav-toggle:focus {
+ background-color: var(--primary);
+ color: var(--on-primary);
+ outline: 2px solid var(--primary);
+ outline-offset: 2px;
+}
+.nav-toggle:active { transform: scale(0.95); }
+
+.feather {
+ width: 1.5rem;
+ height: 1.5rem;
+ stroke: currentColor;
+ stroke-width: 2;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ fill: none;
+ display: inline-block;
+ vertical-align: middle;
+}
+
+/* ===== Headings: markdown-style prefixes ===== */
+h1, h2, h3, h4, h5, h6 {
+ font-size: 1.2rem;
+ margin-block-start: 2em;
+ margin-block-end: 0.5em;
+ line-height: 1.2;
+ color: var(--heading);
+}
+h1::before { color: var(--primary); content: '# '; }
+h2::before { color: var(--primary); content: '## '; }
+h3::before { color: var(--primary); content: '### '; }
+h4::before { color: var(--primary); content: '#### '; }
+
+/* ===== Home-page pieces ===== */
+.site-description {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 1rem;
+}
+
+.list-item { margin-block-end: 1.5em; }
+.list-item h3 { margin-block-start: 1.25em; margin-block-end: 0.25em; }
+
+.meta, time {
+ color: var(--meta);
+ font-size: 0.9em;
+ letter-spacing: -0.5px;
+}
+
+.readmore { display: inline-block; margin-block-start: 0.25em; }
+
+/* tags (used for stack + project tech) */
+.tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ list-style: none;
+ padding: 0;
+ margin-block: 0.5rem;
+}
+.tags li { text-indent: 0; }
+.tags li::before { content: none; }
+.tag,
+.tags a {
+ display: inline-block;
+ border-block-end: 3px solid var(--primary);
+ padding: 0.25rem 0.5rem;
+ border-radius: 3px;
+ font-size: 0.9em;
+ transition: all 0.2s ease;
+}
+/* non-link tags: no hover fill needed, but keep a subtle one */
+.tags a:hover, .tags a:focus { background-color: var(--primary-hover); color: var(--on-primary); }
+
+/* "Portfolio Graveyard" collapsible */
+details {
+ border: 1px dotted var(--border);
+ border-radius: var(--radius);
+ padding: 0.75rem 1rem;
+ margin-block: 1rem;
+}
+summary {
+ cursor: pointer;
+ font-weight: bold;
+ font-size: 1.2rem;
+ color: var(--heading);
+ list-style: none;
+}
+summary::-webkit-details-marker { display: none; }
+summary::before { content: '## '; color: var(--primary); }
+details[open] summary::after { content: ' โพ'; color: var(--primary); }
+details:not([open]) summary::after { content: ' โธ'; color: var(--primary); }
+
+/* contact / link rows */
+.link-row { display: flex; flex-wrap: wrap; gap: 0.75rem 1.25rem; margin-block: 0.75rem; }
+
+/* 88x31 web badges: wrap to fit the screen */
+.web-badges {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 0.5rem;
+ margin-block: 3rem 1.5rem;
+}
+.web-badges img {
+ width: 88px;
+ height: 31px;
+ border: 0; /* the border was shrinking the image and blurring it */
+ outline: 1px solid var(--border); /* outline doesn't change the size */
+ border-radius: 0;
+ image-rendering: pixelated;
+ transition: transform 150ms ease;
+}
+.web-badges img:hover { transform: scale(1.05); }
+
+.post-scroll {
+ margin-block-start: 1rem;
+ font-size: 0.8rem;
+ color: var(--meta);
+ text-align: center;
+}
+
+/* ===== Footer ===== */
+footer {
+ display: flex;
+ align-items: center;
+ border-block-start: 0.4rem dotted var(--border);
+ padding-block: 2rem;
+ margin-block-start: 2rem;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+.soc {
+ display: inline-flex;
+ align-items: center;
+ border-block-end: none;
+ padding: 0 0.25rem;
+}
+.soc:hover, .soc:focus { color: var(--on-primary); }
+.border {
+ display: inline-block;
+ margin-inline: 0.5rem;
+ border: 1px solid var(--border);
+ block-size: 1.2em;
+ padding: 0;
+}
+.footer-info { margin-inline-start: auto; font-size: 0.9em; }
+
+/* ===== Focus ring for keyboard users ===== */
+:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
+
+/* ===== Journal/component styles ===== */
+table { width:100%; border-collapse:collapse; margin-block:1rem; overflow:hidden; border-radius:var(--radius); }
+th { padding:.75rem; border:1px solid var(--border); background:var(--pre-bg); text-align:start; font-weight:bold; }
+td { padding:.75rem; border:1px solid var(--border); }
+tr:nth-child(even) { background:var(--code-bg); }
+.callout { background:var(--pre-bg); border:1px solid var(--border); border-radius:var(--radius); padding:1em; margin-block:1em; }
+.table-wrapper { overflow-x: auto; }
+
+/* ===== Mobile ===== */
+@media (max-width: 37.4em) {
+ .content { padding-inline: 0.5rem; }
+ header { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
+ .site-description { flex-direction: column; align-items: flex-start; }
+ .footer-info { margin-inline-start: 0; }
+}
+
+/* non-clickable tag chips: label, not link */
+.tag {
+ border-block-end: 0;
+ background: var(--code-bg);
+ color: var(--muted);
+}
+
+/* keep underline only on tags that are real links (Links section) */
+.tags a { border-block-end: 3px solid var(--primary); }
+
+/* slightly lighter underline on project titles */
+.list-item h3 a { border-block-end-width: 2px; }
+
+header .main img.avatar { border-width: 2px; }
+
+/* end */
+\ No newline at end of file