-
Scale to 500M users \u2192 weekly
-
${escHtml(globalT)} tonnes CO\u2082
-
\u2248 ${escHtml(globalCars)} cars driven for a week
+
+
WANTED
+
For Environmental Crimes Against the Atmosphere
+
+
+
COUNT I: Consuming ${escHtml(formatTokenCount(fp.weeklyTokens))} tokens per week — enough to power ${escHtml(phoneCharges.toLocaleString())} smartphone charges.
+
COUNT II: Emitting ${escHtml(co2g)} g CO\u2082 weekly — equivalent to driving ${escHtml(kmDriven)} km a year.
+
COUNT III: Evaporating ${escHtml(String(waterMlW))} mL of cooling water per week without remorse.
+
COUNT IV: Projecting annual emissions of ${escHtml(String(co2gA))} g CO\u2082 — sustained and premeditated.
+
+
⚖️ BAIL: Plant ${escHtml(String(treeBail))} tree${treeBail !== 1 ? 's' : ''} or delete your ChatGPT account.
+
If all 500M AI users matched this profile: ${escHtml(globalT)} tonnes CO\u2082/week — equiv. ${escHtml(globalCars)} cars driven.
`;
}
@@ -2166,6 +2165,7 @@
updateAcceleratorUI();
checkAcceleratorAchievements();
updateChallengeProgress();
+ updateVillainLeaderboard();
}
// ---- Challenge progress ----------------------------------
@@ -2409,6 +2409,7 @@
valueEl.className = 'new-record';
setTimeout(() => { valueEl.className = ''; }, 2000);
}
+ updateVillainLeaderboard();
} else {
const valueEl = document.getElementById('bestScoreValue');
if (valueEl && valueEl.textContent === '\u2014') {
@@ -2668,6 +2669,7 @@
renderAgentShop();
updateCompanyStage();
updateAcceleratorUI();
+ updateVillainLeaderboard();
// Show best score from storage
const valueEl = document.getElementById('bestScoreValue');
if (valueEl) {
@@ -2847,6 +2849,438 @@
}
}
+ // ============================================================
+ // SCARY & SATIRICAL FEATURES — PRDs 1–7
+ // ============================================================
+
+ // ── PRD 1: Doomsday Clock ────────────────────────────────────
+
+ const shownEmergencyBroadcasts = new Set();
+
+ // Cache milestone doom thresholds (static — computed once at init)
+ const DOOM_FIRST_THRESHOLD = MILESTONES.length ? MILESTONES[0].tokens : 1e15;
+ const DOOM_LAST_THRESHOLD = MILESTONES.length ? MILESTONES[MILESTONES.length - 1].tokens : 1e18;
+ const DOOM_RANGE = DOOM_LAST_THRESHOLD - DOOM_FIRST_THRESHOLD;
+
+ function updateDoomsdayClock(tokens) {
+ const doomPercent = Math.min(1, Math.max(0,
+ (tokens - DOOM_FIRST_THRESHOLD) / DOOM_RANGE
+ ));
+
+ // Rotate minute hand from 330° (11 o'clock, 5 min before midnight) to 360°/0° (midnight)
+ const angle = 330 + doomPercent * 30;
+ const hand = document.getElementById('doomMinHand');
+ if (hand) hand.setAttribute('transform', `rotate(${angle}, 50, 50)`);
+
+ // Text display
+ const minsLeft = Math.max(0, (1 - doomPercent) * 5);
+ const timeEl = document.getElementById('doomTimeText');
+ if (timeEl) {
+ if (minsLeft < 0.05) {
+ timeEl.textContent = '☠️ MIDNIGHT';
+ } else {
+ timeEl.textContent = minsLeft.toFixed(1) + ' MIN TO MIDNIGHT';
+ }
+ }
+
+ // Percentage text
+ const pctEl = document.getElementById('doomTokenPct');
+ if (pctEl) pctEl.textContent = (doomPercent * 100).toFixed(1) + '%';
+
+ // Progress bar
+ const barFill = document.getElementById('doomBarFill');
+ if (barFill) barFill.style.width = (doomPercent * 100).toFixed(2) + '%';
+ }
+
+ function showEmergencyBroadcast(milestone) {
+ const el = document.getElementById('emergency-broadcast');
+ const msgEl = document.getElementById('ebMsg');
+ if (!el || !msgEl) return;
+
+ msgEl.textContent =
+ '\u26A0\uFE0F AI just crossed the \u201C' + milestone.name + '\u201D threshold \u2014 ' +
+ milestone.shortDesc + '.';
+
+ el.hidden = false;
+ // Auto-dismiss after 6 seconds
+ clearTimeout(el._dismissTimer);
+ el._dismissTimer = setTimeout(() => { el.hidden = true; }, 6000);
+ }
+
+ function initDoomsdayClock() {
+ updateDoomsdayClock(getCurrentTokens());
+ const dismissBtn = document.getElementById('ebDismissBtn');
+ if (dismissBtn) {
+ dismissBtn.addEventListener('click', () => {
+ const el = document.getElementById('emergency-broadcast');
+ if (el) { clearTimeout(el._dismissTimer); el.hidden = true; }
+ });
+ }
+ }
+
+ // ── PRD 2: Apology Generator ─────────────────────────────────
+
+ const APOLOGY_STATEMENTS = [
+ 'We deeply regret that in the time it took you to read this sentence, AI emitted 47 kg of CO\u2082. We remain committed to sustainability. Here is our 200-slide deck.',
+ 'We have engaged a third-party auditor to assess the environmental impact of generating the report about our environmental impact.',
+ 'Reducing our carbon footprint is a core strategic priority. We are on track to be net-zero by 2050, pending board approval and the invention of cold fusion.',
+ 'We acknowledge that AI training requires significant computational resources. We are actively exploring the use of AI to identify ways to use less AI.',
+ 'Following careful review, we have determined that the environmental cost of our sustainability report exceeded the impact of the initiatives it described. We are preparing a report on this finding.',
+ 'Our models are trained on green energy\u2014 sourced from the grid, which is mostly green, in the regions where it isn\u2019t mostly coal.',
+ 'We are proud to announce our \u201CTokens for Trees\u201D programme, in which we plant one sapling for every 10 billion tokens generated. The trees will mature by 2091.',
+ 'We take the climate crisis extremely seriously. That is why we have hired an AI to draft our climate commitments.',
+ 'In response to concerns about data centre water usage, we have begun cooling servers with water sourced from drought-resistant regions. These regions have since requested that we stop.',
+ 'We have reduced our per-token carbon footprint by 0.0003% year-on-year, which the UN has described as \u201Ctechnically measurable.\u201D',
+ 'Our latest sustainability framework represents a 47-page commitment to a future in which AI and the planet coexist. It was generated by an AI in 11 seconds.',
+ 'We appreciate your concern about AI\u2019s environmental impact. Please refer to our FAQ, which was produced using GPT-4 and is 14,000 words long.',
+ 'Rest assured: for every GPU we add, we plant a potted succulent in our San Francisco headquarters. The lobby is thriving.',
+ 'We are proud to say that our data centres run 24 hours a day, 7 days a week, 365 days a year, regardless of whether there is renewable energy available.',
+ 'We have commissioned independent research into the environmental cost of commissioning independent research into our environmental cost. Results pending.',
+ 'Our carbon offset programme involves investing in future carbon capture technology that does not yet exist, at a date to be determined.',
+ 'We remain committed to reducing emissions intensity per unit of compute, which is a different metric from total emissions, and the one we choose to report.',
+ 'We are thrilled to share that this apology consumed approximately 800 tokens to generate. We regret nothing.',
+ 'After extensive consultation, we have concluded that the most sustainable action is to continue exactly as we are while commissioning further consultations.',
+ 'Thank you for your feedback. It has been logged, summarised by an AI, and forwarded to a committee that meets quarterly.',
+ ];
+
+ let apologyIdx = 0;
+ let apologyText = '';
+
+ function updateApology() {
+ apologyIdx = (apologyIdx + 1) % APOLOGY_STATEMENTS.length;
+ apologyText = APOLOGY_STATEMENTS[apologyIdx];
+ const el = document.getElementById('apologyQuote');
+ if (el) {
+ el.style.opacity = '0';
+ setTimeout(() => {
+ el.textContent = apologyText;
+ el.style.opacity = '1';
+ }, 300);
+ }
+ }
+
+ function initApologies() {
+ apologyIdx = Math.floor(Math.random() * APOLOGY_STATEMENTS.length);
+ apologyText = APOLOGY_STATEMENTS[apologyIdx];
+ const el = document.getElementById('apologyQuote');
+ if (el) el.textContent = apologyText;
+
+ setInterval(updateApology, 30000);
+
+ const copyBtn = document.getElementById('apologyCopyBtn');
+ if (copyBtn) {
+ copyBtn.addEventListener('click', () => {
+ const text = apologyText + '\n— The AI Industry, collectively\n\n\u2192 ' + SITE_URL;
+ copyToClipboard(copyBtn, text, '\uD83D\uDCCB Copy & Send to Your AI Vendor');
+ });
+ }
+
+ const nextBtn = document.getElementById('apologyNextBtn');
+ if (nextBtn) nextBtn.addEventListener('click', updateApology);
+ }
+
+ // ── PRD 3: Wanted Poster (modifies updateCalcResults) ────────
+ // Overrides the output of the calculator section — handled in-place below.
+
+ // ── PRD 4: Your Tab (Running) strip ──────────────────────────
+
+ function updateSessionTabStrip() {
+ const now = Date.now();
+ const elapsed = Math.max(1, (now - pageLoadTime) / 1000);
+ const rate = getRateAtDate(new Date(now));
+ const tokens = elapsed * rate;
+ const impact = calculateEnvironmentalImpact(tokens);
+
+ // Cups of coffee (200 mL per cup, water use)
+ const coffees = Math.max(0, impact.waterL / 0.2);
+ // Trees needed for a year
+ const trees = Math.max(0, impact.treesEquivalent);
+ // Smartphone charges (0.015 kWh per charge)
+ const charges = Math.max(0, impact.kWh / 0.015);
+ // Metres driven (171 g CO2/km = 0.000171 kg/m)
+ const metres = Math.max(0, impact.co2Kg / 0.000171);
+
+ function fmtSmall(n) {
+ if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
+ if (n >= 10) return Math.round(n).toLocaleString();
+ if (n >= 1) return n.toFixed(1);
+ if (n >= 0.01) return n.toFixed(3);
+ return '< 0.01';
+ }
+
+ const waterEl = document.getElementById('stiWater');
+ const treesEl = document.getElementById('stiTrees');
+ const chargeEl = document.getElementById('stiCharges');
+ const metresEl = document.getElementById('stiMetres');
+
+ if (waterEl) waterEl.textContent = fmtSmall(coffees);
+ if (treesEl) treesEl.textContent = fmtSmall(trees);
+ if (chargeEl) chargeEl.textContent = fmtSmall(charges);
+ if (metresEl) metresEl.textContent = fmtSmall(metres);
+ }
+
+ function initSessionTabStrip() {
+ updateSessionTabStrip();
+ setInterval(updateSessionTabStrip, 1000);
+ }
+
+ // ── PRD 5: Prompt Hall of Shame ──────────────────────────────
+
+ const SHAME_PROMPTS = [
+ { tokens: 3500, icon: '🌍', text: 'Write me a 5,000-word essay about why AI is bad for the environment' },
+ { tokens: 200, icon: '✉️', text: 'Rewrite this 3-word email in a professional tone' },
+ { tokens: 1500, icon: '📊', text: 'Generate 40 variations of the word "synergy" for my deck' },
+ { tokens: 800, icon: '🔗', text: 'Explain blockchain to my mum (14th attempt)' },
+ { tokens: 2500, icon: '♻️', text: 'Help me write a sustainability report for our AI company' },
+ { tokens: 300, icon: '💼', text: 'Make this 4-word subject line more "impactful"' },
+ { tokens: 1200, icon: '📱', text: 'Turn my grocery list into a LinkedIn thought leadership post' },
+ { tokens: 600, icon: '😤', text: 'Write a passive-aggressive "thanks for your feedback" reply' },
+ { tokens: 3000, icon: '📄', text: 'Summarise this 2-page document I have not read' },
+ { tokens: 400, icon: '🐔', text: 'Explain the philosophical implications of a chicken crossing a road' },
+ { tokens: 250, icon: '🌮', text: 'Is a hot dog a sandwich? 2,000 words. Both sides.' },
+ { tokens: 100, icon: '🦀', text: 'Hello world in Rust (variation #47)' },
+ { tokens: 700, icon: '😺', text: 'Describe this cat picture in 600 words' },
+ { tokens: 900, icon: '🧘', text: 'Motivational speech about the importance of not using AI so much' },
+ { tokens: 1800, icon: '📜', text: 'Generate terms of service for my AI startup (that no one will read)' },
+ { tokens: 450, icon: '🌅', text: 'Write a haiku about productivity, but make it really long' },
+ { tokens: 1100, icon: '🤖', text: 'Ask the AI if it is conscious (session 1 of 200)' },
+ { tokens: 650, icon: '🍕', text: 'Add cheese to this recipe that should not have cheese' },
+ { tokens: 2200, icon: '💰', text: 'Explain why my AI startup is worth $2 billion' },
+ { tokens: 380, icon: '📣', text: 'Rewrite this tweet so it sounds spontaneous' },
+ ];
+
+ let shameAutoIdx = 0;
+
+ function shameEnergyCost(tokens) {
+ const kWh = (tokens / 1000) * 0.0003;
+ const co2g = (kWh * 0.4 * 1000).toFixed(1);
+ return '~' + (kWh < 0.001 ? kWh.toFixed(5) : kWh.toFixed(4)) + ' kWh \u2022 ' + co2g + ' g CO\u2082';
+ }
+
+ function appendShameEntry(promptObj, isUserSubmitted) {
+ const feed = document.getElementById('shameFeed');
+ if (!feed) return;
+
+ const entry = document.createElement('div');
+ entry.className = 'shame-entry' + (isUserSubmitted ? ' user-submitted' : '');
+
+ const icon = document.createElement('span');
+ icon.className = 'shame-entry-icon';
+ icon.setAttribute('aria-hidden', 'true');
+ icon.textContent = isUserSubmitted ? '👤' : promptObj.icon;
+
+ const content = document.createElement('div');
+ content.className = 'shame-entry-content';
+
+ const textSpan = document.createElement('div');
+ textSpan.className = 'shame-entry-text';
+ textSpan.textContent = '\u201C' + promptObj.text + '\u201D';
+
+ const costSpan = document.createElement('div');
+ costSpan.className = 'shame-entry-cost';
+ costSpan.textContent = shameEnergyCost(promptObj.tokens);
+
+ content.appendChild(textSpan);
+ content.appendChild(costSpan);
+
+ if (isUserSubmitted) {
+ const tag = document.createElement('div');
+ tag.className = 'shame-entry-user-tag';
+ tag.textContent = '\u2B06 Submitted by you';
+ content.appendChild(tag);
+ }
+
+ entry.appendChild(icon);
+ entry.appendChild(content);
+
+ // Prepend (newest at top)
+ feed.insertBefore(entry, feed.firstChild);
+
+ // Cap at 15 entries
+ while (feed.children.length > 15) {
+ feed.removeChild(feed.lastChild);
+ }
+ }
+
+ function initShame() {
+ // Seed with 5 initial entries
+ const seed = [...SHAME_PROMPTS].sort(() => 0.5 - Math.random()).slice(0, 5);
+ seed.forEach((p) => appendShameEntry(p, false));
+
+ // Auto-add a new one every 7 seconds
+ setInterval(() => {
+ shameAutoIdx = (shameAutoIdx + 1) % SHAME_PROMPTS.length;
+ appendShameEntry(SHAME_PROMPTS[shameAutoIdx], false);
+ }, 7000);
+
+ // Submit button
+ const submitBtn = document.getElementById('shameSubmitBtn');
+ const input = document.getElementById('shameInput');
+ if (submitBtn && input) {
+ function doSubmit() {
+ const raw = input.value.trim();
+ if (!raw) return;
+ // Sanitise user input — textContent assignment handles escaping below
+ const randomTokens = 200 + Math.floor(Math.random() * 3000);
+ const userPrompt = { tokens: randomTokens, icon: '👤', text: raw };
+ appendShameEntry(userPrompt, true);
+ input.value = '';
+ awardBadge('spreading_doom');
+ }
+ submitBtn.addEventListener('click', doSubmit);
+ input.addEventListener('keydown', (e) => { if (e.key === 'Enter') doSubmit(); });
+ }
+ }
+
+ // ── PRD 6: Villain Arc Leaderboard ───────────────────────────
+
+ const VILLAIN_FAKE_LEADERBOARD = [
+ { name: 'Elon M.', dp: 847_293_847, note: 'Inference is just efficiency' },
+ { name: 'Sam A.', dp: 294_847_203, note: 'Negligible at scale' },
+ { name: 'Jensen H.', dp: 184_293_840, note: 'GPU go brrr' },
+ { name: 'Marc B.', dp: 93_847_203, note: 'The metaverse needed training data' },
+ { name: 'Sundar P.', dp: 48_293_040, note: 'AI for good (primarily)' },
+ ];
+
+ const VILLAIN_RANK_TITLES = [
+ { min: 0, title: 'Innocent Bystander' },
+ { min: 10, title: 'Accidental Accomplice' },
+ { min: 100, title: 'Carbon Enabler' },
+ { min: 1_000, title: 'Climate Criminal' },
+ { min: 10_000, title: 'Carbon Baron' },
+ { min: 100_000, title: 'The Accelerationist' },
+ { min: 1_000_000, title: 'Extinction Level Event' },
+ ];
+
+ let villainCongratsShown = false;
+
+ function getVillainRankTitle(dp) {
+ let title = VILLAIN_RANK_TITLES[0].title;
+ for (const tier of VILLAIN_RANK_TITLES) {
+ if (dp >= tier.min) title = tier.title;
+ }
+ return title;
+ }
+
+ function updateVillainLeaderboard() {
+ const userDp = acc.doomPoints;
+ const userBest = acc.bestScore > 0 ? acc.bestScore * (1 / 1_000_000) : 0;
+ const userTitle = getVillainRankTitle(userDp);
+
+ // Update rank banner
+ const rankTitleEl = document.getElementById('villainRankTitle');
+ const rankScoreEl = document.getElementById('villainRankScore');
+ if (rankTitleEl) rankTitleEl.textContent = userTitle;
+ if (rankScoreEl) rankScoreEl.textContent = formatDoomPoints(userDp) + ' this session';
+
+ // Build leaderboard rows (insert user at correct position)
+ const tbody = document.getElementById('villainTableBody');
+ if (!tbody) return;
+
+ const entries = [
+ ...VILLAIN_FAKE_LEADERBOARD.map((e) => ({ ...e, isUser: false })),
+ { name: 'You', dp: userDp, note: userTitle, isUser: true },
+ ].sort((a, b) => b.dp - a.dp);
+
+ tbody.innerHTML = '';
+ entries.forEach((entry, idx) => {
+ const tr = document.createElement('tr');
+ if (entry.isUser) tr.className = 'villain-row-you';
+ tr.innerHTML =
+ '
' + (idx + 1) + ' | ' +
+ '
' + escHtml(entry.name) + (entry.isUser ? ' 👈' : '') + ' | ' +
+ '
' + (entry.dp >= 1_000_000
+ ? (entry.dp / 1_000_000).toFixed(1) + 'M DP'
+ : entry.dp >= 1000
+ ? (entry.dp / 1000).toFixed(1) + 'K DP'
+ : Math.round(entry.dp) + ' DP') + ' | ' +
+ '
' + escHtml(entry.note) + ' | ';
+ tbody.appendChild(tr);
+ });
+
+ // Congratulations if user has broken into the top position ahead of a fake entry
+ if (!villainCongratsShown && userDp > VILLAIN_FAKE_LEADERBOARD[4].dp) {
+ villainCongratsShown = true;
+ const congrats = document.getElementById('villainCongrats');
+ if (congrats) {
+ congrats.hidden = false;
+ setTimeout(() => { congrats.hidden = true; }, 5000);
+ }
+ }
+ }
+
+ function initVillainLeaderboard() {
+ updateVillainLeaderboard();
+ }
+
+ // ── PRD 7: The Intervention ───────────────────────────────────
+
+ let interventionFired = false;
+
+ function showIntervention() {
+ if (interventionFired) return;
+ if (sessionStorage.getItem('interventionSeen')) return;
+ interventionFired = true;
+
+ const modal = document.getElementById('intervention-modal');
+ if (!modal) return;
+
+ const elapsed = Math.floor((Date.now() - pageLoadTime) / 1000);
+ const rate = getRateAtDate(new Date());
+ const sessionTokens = Math.max(1, elapsed * rate);
+ const impact = calculateEnvironmentalImpact(sessionTokens);
+ const co2g = (impact.co2Kg * 1000).toFixed(1);
+
+ const m = Math.floor(elapsed / 60);
+ const s = elapsed % 60;
+ const timeStr = m > 0 ? `${m} min ${s} sec` : `${s} seconds`;
+
+ const msgEl = document.getElementById('intervention-msg');
+ if (msgEl) {
+ msgEl.textContent =
+ `You\u2019ve been here for ${timeStr}. In that time, AI emitted ` +
+ `${co2g}\u202Fg of CO\u2082 globally. Just so you know.`;
+ }
+
+ modal.hidden = false;
+ const stayBtn = document.getElementById('intervention-stay');
+ if (stayBtn) stayBtn.focus();
+ }
+
+ function initIntervention() {
+ if (sessionStorage.getItem('interventionSeen')) return;
+
+ document.addEventListener('mouseleave', (e) => {
+ if (e.clientY <= 0 && !interventionFired) {
+ showIntervention();
+ }
+ });
+
+ const modal = document.getElementById('intervention-modal');
+ if (!modal) return;
+
+ const stayBtn = document.getElementById('intervention-stay');
+ if (stayBtn) {
+ stayBtn.addEventListener('click', () => { modal.hidden = true; });
+ }
+
+ const leaveBtn = document.getElementById('intervention-leave');
+ if (leaveBtn) {
+ leaveBtn.addEventListener('click', () => {
+ sessionStorage.setItem('interventionSeen', '1');
+ modal.hidden = true;
+ });
+ }
+
+ modal.addEventListener('click', (e) => {
+ if (e.target === modal) {
+ sessionStorage.setItem('interventionSeen', '1');
+ modal.hidden = true;
+ }
+ });
+ }
+
// ============================================================
// FEATURE: "Wait for It" — Milestone Countdown Alert
// ============================================================
@@ -3007,6 +3441,13 @@
// Engagement features
initPresenceStrip();
initEventLog();
+ // Scary & satirical features (PRDs 1–7)
+ initDoomsdayClock();
+ initSessionTabStrip();
+ initApologies();
+ initShame();
+ initVillainLeaderboard();
+ initIntervention();
// Persist accelerator game state every 30 seconds and on page hide
setInterval(saveAcceleratorState, 30000);
diff --git a/styles.css b/styles.css
index 7ff69a0..fbc83e0 100644
--- a/styles.css
+++ b/styles.css
@@ -3100,6 +3100,832 @@ footer a:hover {
.milestone-flash-content { animation: none; }
}
+/* =============================================================
+ SCARY & SATIRICAL FEATURES — PRDs 1–7
+ ============================================================= */
+
+/* ── PRD 1: Doomsday Clock Strip ──────────────────────────── */
+
+.doomsday-strip {
+ background: #0d0000;
+ border-bottom: 2px solid var(--accent);
+ display: flex;
+ align-items: center;
+ gap: 1.25rem;
+ padding: 0.65rem 1.5rem;
+ flex-wrap: wrap;
+ position: sticky;
+ top: 0;
+ z-index: 850;
+ box-shadow: 0 2px 20px rgba(255,51,51,0.25);
+}
+
+:root[data-theme="light"] .doomsday-strip {
+ background: #1a0000;
+}
+
+.doomsday-clock-wrap {
+ flex-shrink: 0;
+}
+
+.doom-clock-svg {
+ width: 56px;
+ height: 56px;
+ overflow: visible;
+}
+
+.doom-clock-face {
+ fill: #0d0000;
+ stroke: var(--accent);
+ stroke-width: 2;
+}
+
+.doom-tick {
+ stroke: rgba(255, 51, 51, 0.5);
+ stroke-width: 1.5;
+ stroke-linecap: round;
+}
+
+.doom-tick-major {
+ stroke: var(--accent);
+ stroke-width: 2.5;
+}
+
+.doom-tick-sm {
+ stroke-width: 1;
+}
+
+.doom-tick-warn {
+ stroke: var(--accent);
+ stroke-width: 2;
+}
+
+.doom-clock-hand {
+ stroke: var(--accent);
+ stroke-width: 3;
+ stroke-linecap: round;
+ filter: drop-shadow(0 0 4px var(--accent));
+ transition: none;
+}
+
+.doom-clock-dot {
+ fill: #fff;
+ filter: drop-shadow(0 0 3px var(--accent));
+}
+
+.doomsday-text-wrap {
+ flex: 1;
+ min-width: 160px;
+}
+
+.doomsday-time {
+ font-family: 'Orbitron', monospace;
+ font-size: clamp(0.75rem, 2.5vw, 1.1rem);
+ font-weight: 900;
+ color: var(--accent);
+ text-shadow: 0 0 10px var(--accent-glow);
+ letter-spacing: 0.08em;
+}
+
+.doomsday-sub {
+ font-size: 0.68rem;
+ color: rgba(255,255,255,0.45);
+ margin-top: 0.2rem;
+ letter-spacing: 0.04em;
+}
+
+.doomsday-bar-wrap {
+ flex: 1;
+ min-width: 120px;
+ max-width: 260px;
+}
+
+.doomsday-bar-track {
+ height: 8px;
+ background: rgba(255,51,51,0.12);
+ border-radius: 4px;
+ overflow: hidden;
+ border: 1px solid rgba(255,51,51,0.25);
+}
+
+.doomsday-bar-fill {
+ height: 100%;
+ background: linear-gradient(90deg, #330000, var(--accent));
+ border-radius: 4px;
+ transition: width 1s linear;
+ box-shadow: 0 0 6px var(--accent-glow);
+}
+
+.doomsday-bar-labels {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.58rem;
+ color: rgba(255,255,255,0.3);
+ letter-spacing: 0.08em;
+ margin-top: 0.2rem;
+ text-transform: uppercase;
+}
+
+/* ── PRD 1: Emergency Broadcast Overlay ───────────────────── */
+
+.emergency-broadcast {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 3000;
+ background: #8b0000;
+ border-bottom: 3px solid #ff0000;
+ padding: 0.75rem 1.5rem;
+ animation: eb-slidein 0.3s ease-out, eb-pulse 0.6s ease-in-out infinite alternate;
+ box-shadow: 0 4px 32px rgba(255,0,0,0.7);
+}
+
+@keyframes eb-slidein {
+ from { transform: translateY(-100%); opacity: 0; }
+ to { transform: translateY(0); opacity: 1; }
+}
+
+@keyframes eb-pulse {
+ from { background: #8b0000; }
+ to { background: #aa0000; }
+}
+
+.eb-inner {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+.eb-icon {
+ font-size: 1.3rem;
+ animation: eb-icon-flash 0.5s step-start infinite;
+ flex-shrink: 0;
+}
+
+@keyframes eb-icon-flash {
+ 50% { opacity: 0; }
+}
+
+.eb-label {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.7rem;
+ font-weight: 900;
+ color: #fff;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ background: #ff0000;
+ padding: 0.1rem 0.5rem;
+ border-radius: 2px;
+ flex-shrink: 0;
+}
+
+.eb-msg {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.78rem;
+ font-weight: 700;
+ color: #fff;
+ flex: 1;
+}
+
+.eb-sign-off {
+ font-size: 0.68rem;
+ color: rgba(255,255,255,0.7);
+ font-style: italic;
+ flex-basis: 100%;
+ padding-left: 2.8rem;
+}
+
+/* ── PRD 4: Your Tab (Running) ────────────────────────────── */
+
+.session-tab-strip {
+ background: var(--surface);
+ border: 1px solid rgba(255,51,51,0.3);
+ border-radius: 0.75rem;
+ padding: 1rem 1.25rem;
+ margin-top: 1.5rem;
+ position: relative;
+ overflow: hidden;
+}
+
+.session-tab-strip::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(135deg, rgba(255,51,51,0.03) 0%, transparent 60%);
+ pointer-events: none;
+}
+
+.session-tab-header {
+ display: flex;
+ align-items: baseline;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+ margin-bottom: 0.85rem;
+}
+
+.session-tab-title {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.8rem;
+ font-weight: 700;
+ color: var(--accent);
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+}
+
+.session-tab-sub {
+ font-size: 0.72rem;
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+.session-tab-items {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 0.6rem;
+}
+
+.session-tab-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ background: var(--surface-2);
+ border: 1px solid var(--border);
+ border-radius: 0.4rem;
+ padding: 0.5rem 0.75rem;
+ font-size: 0.78rem;
+ color: var(--text-dim);
+}
+
+.sti-icon { font-size: 1.1rem; flex-shrink: 0; }
+
+.sti-val {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.82rem;
+ font-weight: 700;
+ color: var(--accent-2);
+ min-width: 3.5rem;
+ text-align: right;
+ flex-shrink: 0;
+}
+
+.sti-label {
+ font-size: 0.72rem;
+ color: var(--text-muted);
+ line-height: 1.3;
+}
+
+/* ── PRD 2: Apology Generator ─────────────────────────────── */
+
+#apology-section { background: var(--bg); }
+
+.apology-card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-left: 4px solid var(--accent-2);
+ border-radius: 0.75rem;
+ padding: 1.5rem;
+ margin-top: 1rem;
+ position: relative;
+ min-height: 6rem;
+}
+
+.apology-card::before {
+ content: '❝';
+ font-size: 3rem;
+ color: rgba(255,136,0,0.12);
+ position: absolute;
+ top: 0.5rem;
+ left: 0.75rem;
+ font-family: Georgia, serif;
+ line-height: 1;
+ pointer-events: none;
+}
+
+.apology-quote {
+ font-size: 0.95rem;
+ color: var(--text);
+ line-height: 1.7;
+ font-style: italic;
+ padding-left: 1.5rem;
+ animation: apology-fade 0.5s ease-out;
+}
+
+@keyframes apology-fade {
+ from { opacity: 0; transform: translateY(4px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+.apology-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 1rem;
+ padding-top: 0.75rem;
+ border-top: 1px solid var(--border);
+ flex-wrap: wrap;
+ gap: 0.5rem;
+}
+
+.apology-signoff {
+ font-size: 0.78rem;
+ color: var(--accent-2);
+ font-style: normal;
+}
+
+.apology-note {
+ font-size: 0.68rem;
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+.apology-actions {
+ display: flex;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+ margin-top: 1rem;
+}
+
+/* ── PRD 3: Wanted Poster ──────────────────────────────────── */
+
+.wanted-poster {
+ background: #1a0f00;
+ border: 3px solid #8b5a00;
+ border-radius: 0.5rem;
+ padding: 1.5rem;
+ text-align: center;
+ font-family: 'Share Tech Mono', 'Courier New', monospace;
+ position: relative;
+ overflow: hidden;
+ box-shadow: inset 0 0 40px rgba(0,0,0,0.5), 0 0 20px rgba(139,90,0,0.3);
+}
+
+.wanted-poster::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: repeating-linear-gradient(
+ 0deg, transparent, transparent 4px,
+ rgba(0,0,0,0.04) 4px, rgba(0,0,0,0.04) 5px
+ );
+ pointer-events: none;
+}
+
+:root[data-theme="light"] .wanted-poster {
+ background: #f5e6c8;
+ border-color: #8b5a00;
+ box-shadow: inset 0 0 40px rgba(0,0,0,0.1);
+}
+
+.wanted-title {
+ font-family: 'Orbitron', monospace;
+ font-size: clamp(2rem, 8vw, 3.5rem);
+ font-weight: 900;
+ color: #cc3300;
+ letter-spacing: 0.15em;
+ text-shadow: 3px 3px 0 #660000;
+ margin-bottom: 0.25rem;
+ line-height: 1;
+}
+
+.wanted-subtitle {
+ font-size: 0.75rem;
+ color: #cc9900;
+ letter-spacing: 0.3em;
+ text-transform: uppercase;
+ margin-bottom: 1rem;
+}
+
+.wanted-divider {
+ height: 3px;
+ background: linear-gradient(90deg, transparent, #8b5a00, transparent);
+ margin: 0.75rem 0;
+}
+
+.wanted-charges {
+ text-align: left;
+ margin: 1rem 0;
+}
+
+.wanted-charge {
+ font-size: 0.8rem;
+ color: #d4a843;
+ padding: 0.4rem 0;
+ border-bottom: 1px dashed rgba(139,90,0,0.3);
+ line-height: 1.5;
+}
+
+:root[data-theme="light"] .wanted-charge {
+ color: #5a3500;
+}
+
+.wanted-charge strong {
+ color: #ff6600;
+ font-family: 'Orbitron', monospace;
+ font-size: 0.72rem;
+}
+
+:root[data-theme="light"] .wanted-charge strong {
+ color: #cc3300;
+}
+
+.wanted-bail {
+ font-size: 0.78rem;
+ color: #ff9900;
+ margin-top: 1rem;
+ padding: 0.6rem 1rem;
+ background: rgba(139,90,0,0.2);
+ border: 1px solid rgba(139,90,0,0.4);
+ border-radius: 0.3rem;
+}
+
+:root[data-theme="light"] .wanted-bail {
+ color: #7a3d00;
+ background: rgba(139,90,0,0.1);
+}
+
+.wanted-global {
+ font-size: 0.68rem;
+ color: rgba(204,153,0,0.6);
+ margin-top: 0.75rem;
+ font-style: italic;
+}
+
+:root[data-theme="light"] .wanted-global {
+ color: rgba(90,53,0,0.6);
+}
+
+/* ── PRD 5: Prompt Hall of Shame ──────────────────────────── */
+
+#shame-section { background: var(--bg-alt); }
+
+.shame-feed {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: 0.5rem;
+ padding: 0.5rem;
+ max-height: 320px;
+ overflow-y: auto;
+ margin-top: 1rem;
+ font-family: 'Share Tech Mono', monospace;
+ scroll-behavior: smooth;
+}
+
+.shame-entry {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.6rem;
+ padding: 0.6rem 0.75rem;
+ border-bottom: 1px solid var(--border);
+ animation: shame-slide 0.4s ease-out;
+ font-size: 0.8rem;
+}
+
+.shame-entry:last-child { border-bottom: none; }
+
+@keyframes shame-slide {
+ from { opacity: 0; transform: translateX(-10px); }
+ to { opacity: 1; transform: translateX(0); }
+}
+
+.shame-entry.user-submitted {
+ border-left: 3px solid var(--accent-2);
+ background: var(--surface-2);
+}
+
+.shame-entry-icon {
+ font-size: 1rem;
+ flex-shrink: 0;
+ margin-top: 0.05rem;
+}
+
+.shame-entry-content { flex: 1; min-width: 0; }
+
+.shame-entry-text {
+ color: var(--text);
+ line-height: 1.5;
+ word-break: break-word;
+}
+
+.shame-entry-cost {
+ font-size: 0.65rem;
+ color: var(--accent);
+ margin-top: 0.2rem;
+ font-family: 'Orbitron', monospace;
+}
+
+.shame-entry-user-tag {
+ font-size: 0.6rem;
+ color: var(--accent-2);
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ margin-top: 0.15rem;
+}
+
+.shame-submit-wrap {
+ margin-top: 1.25rem;
+}
+
+.shame-submit-label {
+ display: block;
+ font-size: 0.82rem;
+ color: var(--text-dim);
+ margin-bottom: 0.5rem;
+}
+
+.shame-input-row {
+ display: flex;
+ gap: 0.6rem;
+ flex-wrap: wrap;
+}
+
+.shame-input {
+ flex: 1;
+ min-width: 200px;
+ background: var(--surface-2);
+ border: 1px solid var(--border);
+ border-radius: 0.4rem;
+ padding: 0.55rem 0.85rem;
+ font-family: inherit;
+ font-size: 0.85rem;
+ color: var(--text);
+ outline: none;
+ transition: border-color 0.2s;
+}
+
+.shame-input:focus { border-color: var(--accent-2); }
+.shame-input::placeholder { color: var(--text-muted); }
+
+/* ── PRD 6: Villain Leaderboard ───────────────────────────── */
+
+.villain-leaderboard-wrap {
+ margin-top: 1.5rem;
+ padding-top: 1.5rem;
+ border-top: 1px solid var(--border);
+}
+
+.villain-rank-banner {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: 0.5rem;
+ padding: 0.75rem 1.1rem;
+ margin-bottom: 1rem;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+}
+
+.villain-rank-title {
+ font-family: 'Orbitron', monospace;
+ font-size: clamp(0.75rem, 2.5vw, 0.95rem);
+ font-weight: 700;
+ color: var(--accent-2);
+ letter-spacing: 0.06em;
+}
+
+.villain-rank-score {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.82rem;
+ color: var(--text-dim);
+}
+
+.villain-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.8rem;
+ margin-bottom: 0.75rem;
+}
+
+.villain-table th {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.62rem;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: var(--text-muted);
+ padding: 0.5rem 0.75rem;
+ border-bottom: 1px solid var(--border);
+ text-align: left;
+ background: var(--surface-2);
+}
+
+.villain-table td {
+ padding: 0.55rem 0.75rem;
+ border-bottom: 1px solid var(--border);
+ color: var(--text-dim);
+}
+
+.villain-table tr:last-child td { border-bottom: none; }
+
+.villain-table .villain-row-you {
+ background: rgba(255,51,51,0.06);
+}
+
+.villain-table .villain-row-you td {
+ color: var(--accent-2);
+ font-weight: 700;
+}
+
+.villain-table .villain-pos {
+ width: 2rem;
+ text-align: center;
+ color: var(--text-muted);
+ font-family: 'Orbitron', monospace;
+ font-size: 0.7rem;
+}
+
+.villain-table .villain-name { font-weight: 700; }
+
+.villain-table .villain-score {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.75rem;
+ color: var(--accent-2);
+}
+
+.villain-table .villain-rank-cell {
+ font-size: 0.68rem;
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+.villain-congratulations {
+ background: var(--accent);
+ color: #fff;
+ font-family: 'Orbitron', monospace;
+ font-size: 0.8rem;
+ font-weight: 700;
+ letter-spacing: 0.05em;
+ padding: 0.75rem 1rem;
+ border-radius: 0.4rem;
+ text-align: center;
+ animation: villain-congrats-flash 0.4s ease-out;
+}
+
+@keyframes villain-congrats-flash {
+ 0% { transform: scale(1); box-shadow: 0 0 0 rgba(255,51,51,0); }
+ 40% { transform: scale(1.03); box-shadow: 0 0 24px rgba(255,51,51,0.6); }
+ 100% { transform: scale(1); box-shadow: 0 0 8px rgba(255,51,51,0.3); }
+}
+
+/* ── PRD 7: The Intervention ──────────────────────────────── */
+
+.intervention-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 3500;
+ background: rgba(0,0,0,0.7);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+ animation: fade-in 0.25s ease-out;
+}
+
+.intervention-card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: 1rem;
+ padding: 1.5rem;
+ max-width: 420px;
+ width: 100%;
+ box-shadow: 0 20px 64px var(--shadow);
+ animation: slide-up 0.25s ease-out;
+}
+
+.intervention-header {
+ display: flex;
+ align-items: center;
+ gap: 0.6rem;
+ margin-bottom: 0.85rem;
+}
+
+.intervention-avatar {
+ font-size: 1.6rem;
+}
+
+.intervention-sender {
+ font-family: 'Orbitron', monospace;
+ font-size: 0.78rem;
+ font-weight: 700;
+ color: var(--accent-3);
+}
+
+.intervention-time {
+ font-size: 0.65rem;
+ color: var(--text-muted);
+ margin-left: auto;
+}
+
+.intervention-bubble {
+ background: var(--surface-2);
+ border: 1px solid var(--border);
+ border-radius: 0 1rem 1rem 1rem;
+ padding: 1rem 1.1rem;
+ margin-bottom: 1.25rem;
+}
+
+.intervention-greeting {
+ font-size: 0.95rem;
+ color: var(--text);
+ font-weight: 700;
+ margin-bottom: 0.6rem;
+}
+
+.intervention-msg {
+ font-size: 0.85rem;
+ color: var(--text-dim);
+ line-height: 1.65;
+ margin-bottom: 0.6rem;
+}
+
+.intervention-coda {
+ font-size: 0.78rem;
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+.intervention-actions {
+ display: flex;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+}
+
+.intervention-btn-stay {
+ flex: 1;
+ background: var(--accent-3);
+ border: none;
+ border-radius: 0.4rem;
+ padding: 0.65rem 1rem;
+ font-family: inherit;
+ font-size: 0.85rem;
+ color: #fff;
+ cursor: pointer;
+ font-weight: 700;
+ transition: background 0.2s;
+}
+
+.intervention-btn-stay:hover { background: #00a35e; }
+
+.intervention-btn-leave {
+ flex: 1;
+ background: var(--surface-3);
+ border: 1px solid var(--border);
+ border-radius: 0.4rem;
+ padding: 0.65rem 1rem;
+ font-family: inherit;
+ font-size: 0.85rem;
+ color: var(--text-dim);
+ cursor: pointer;
+ transition: background 0.2s, color 0.2s;
+}
+
+.intervention-btn-leave:hover { background: var(--surface-2); color: var(--accent); }
+
+/* ── Responsive ──────────────────────────────────────────── */
+
+@media (max-width: 600px) {
+ .doomsday-strip { padding: 0.5rem 1rem; gap: 0.75rem; }
+ .doomsday-bar-wrap { display: none; }
+ .doom-clock-svg { width: 44px; height: 44px; }
+ .session-tab-items { grid-template-columns: 1fr 1fr; }
+ .villain-table .villain-rank-cell { display: none; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .emergency-broadcast { animation: none; }
+ .eb-icon { animation: none; }
+ .apology-quote { animation: none; }
+ .shame-entry { animation: none; }
+ .villain-congratulations { animation: none; }
+ .doomsday-bar-fill { transition: none; }
+ .doom-clock-hand { transition: none; }
+ .intervention-overlay, .intervention-card { animation: none; }
+}
+
+.eb-dismiss {
+ background: transparent;
+ border: 1px solid rgba(255,255,255,0.3);
+ border-radius: 50%;
+ width: 1.75rem;
+ height: 1.75rem;
+ color: rgba(255,255,255,0.8);
+ font-size: 0.8rem;
+ cursor: pointer;
+ flex-shrink: 0;
+ align-self: center;
+ margin-left: auto;
+ transition: background 0.15s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.eb-dismiss:hover { background: rgba(255,255,255,0.15); }
+
/* ---- Grim Reaper ---- */
.grim-reaper {
position: fixed;