From 06f9dbf78667edb76503b2c11695b0f1feac3ca8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:35:33 +0000 Subject: [PATCH 1/2] chore: exclude generated files from git to eliminate merge conflicts Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/e59e531c-78e8-4c77-806a-43871027c9b9 Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> --- .github/workflows/e2e-tests.yml | 3 + .github/workflows/preview.yml | 4 +- .gitignore | 9 + AGENTS.md | 25 +- changelog-data.js | 46 ---- milestones-data.js | 448 -------------------------------- project-stats-data.js | 13 - script.js | 129 --------- styles.css | 1 - 9 files changed, 27 insertions(+), 651 deletions(-) delete mode 100644 changelog-data.js delete mode 100644 milestones-data.js delete mode 100644 project-stats-data.js delete mode 100644 script.js delete mode 100644 styles.css diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index db8ff6b..450d97b 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -51,6 +51,9 @@ jobs: - name: Install Playwright browsers run: npx playwright install --with-deps chromium + - name: Build generated files + run: npm run build + - name: Run E2E tests run: npm run test:e2e diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index ffe0234..1596bfb 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -24,8 +24,8 @@ jobs: - name: Install dependencies run: npm ci - - name: Regenerate milestones-data.js from YAML - run: npm run build:milestones + - name: Build all generated files + run: npm run build - name: Deploy PR preview to gh-pages branch uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 diff --git a/.gitignore b/.gitignore index 309f28e..533c99b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,12 @@ coverage/ .DS_Store test-results/ screenshots/ + +# Auto-generated build artefacts — rebuilt by `npm run build` and by CI before deploy/preview. +# Do not commit these; editing the source files in src/js/, styles/, milestones.yaml, +# CHANGELOG.md, or project-stats.yaml is sufficient. +script.js +styles.css +changelog-data.js +milestones-data.js +project-stats-data.js diff --git a/AGENTS.md b/AGENTS.md index bd10ac7..e3d7b60 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,12 +20,12 @@ a Chart.js growth chart with projections, and a prompt/PR quality scoring sectio ``` . ├── index.html ← GitHub Pages entry point (static HTML shell) -├── styles.css ← AUTO-GENERATED from styles/ — do not edit directly -├── script.js ← AUTO-GENERATED from src/js/ — do not edit directly +├── styles.css ← AUTO-GENERATED — not committed; built by `npm run build:css` +├── script.js ← AUTO-GENERATED — not committed; built by `npm run build:js` ├── death-clock-core.js ← Pure functions only — no DOM, safe to unit-test -├── changelog-data.js ← AUTO-GENERATED from CHANGELOG.md — do not edit -├── milestones-data.js ← AUTO-GENERATED from milestones.yaml — do not edit -├── project-stats-data.js ← AUTO-GENERATED from project-stats.yaml — do not edit +├── changelog-data.js ← AUTO-GENERATED — not committed; built by `npm run build:changelog` +├── milestones-data.js ← AUTO-GENERATED — not committed; built by `npm run build:milestones` +├── project-stats-data.js ← AUTO-GENERATED — not committed; built by `npm run build:project-stats` ├── project-stats.yaml ← Edit this to update footer PR count + token total ├── CLAUDE.md ← symlink → AGENTS.md (read by Claude AI agents) ├── package.json ← version, Jest config & devDependencies (no runtime deps) @@ -91,7 +91,7 @@ a Chart.js growth chart with projections, and a prompt/PR quality scoring sectio | **CommonJS + browser dual export** | `death-clock-core.js` exports via `module.exports` for Jest and via `window.DeathClockCore` for the browser. Do not change this pattern without updating both consumers. | | **HTML escaping** | All dynamic strings rendered into `innerHTML` must pass through `escHtml()` in `src/js/05-security.js`. Never assign untrusted data directly to `innerHTML`. | | **Counter anchor** | `getCurrentTokens()` in `src/js/00-state.js` computes elapsed time from `BASE_DATE_ISO` (exported by the core module), **not** from page-load time. `pageLoadTime` is reserved for the session counter only. | -| **Build before commit** | After editing any file in `src/js/`, run `npm run build:js`. After editing any file in `styles/`, run `npm run build:css`. Commit both the source file and the rebuilt output file. The CI deploy step also rebuilds automatically. | +| **Build before commit** | After editing any file in `src/js/`, run `npm run build:js`. After editing any file in `styles/`, run `npm run build:css`. The generated output files (`script.js`, `styles.css`, etc.) are **not committed** — CI rebuilds them automatically at deploy and preview time. Run `npm run build` locally before running E2E tests. | --- @@ -131,7 +131,7 @@ The current measured coverage is ≈ 96 % statements / 88 % branches — do not Every time an agent makes changes to this repository it **must**: 1. Run `npm run test:ci` and confirm all unit tests pass before finishing. -2. Run `npm run test:e2e` and confirm all E2E tests pass before finishing. +2. Run `npm run build && npm run test:e2e` and confirm all E2E tests pass before finishing. (`npm run build` is required first because the generated files are not committed.) 3. Ensure coverage does **not** decrease — the Codecov status check enforces this on PRs (any negative delta fails the check). When adding or modifying code, agents **must** write matching tests: @@ -169,10 +169,10 @@ generated file will always reflect the latest YAML values. 4. Import it in `src/js/00-state.js` via the destructuring at the top, then run `npm run build:js`. ### Adding or modifying DOM behaviour -Edit the relevant file in `src/js/` (see the repository layout for which file covers which feature), then run `npm run build:js` to regenerate `script.js`. +Edit the relevant file in `src/js/` (see the repository layout for which file covers which feature), then run `npm run build:js` to regenerate `script.js` locally (needed for E2E tests). Do **not** commit `script.js` — it is in `.gitignore`. ### Changing the visual theme -Edit `styles/variables.css` for colour tokens, or the relevant component file in `styles/` for layout. CSS custom properties for colours live in `:root[data-theme="dark"]` and `:root[data-theme="light"]` inside `styles/variables.css`. The theme toggle is managed by `applyTheme()` in `src/js/01-theme.js`. After any CSS change, run `npm run build:css` to regenerate `styles.css`. +Edit `styles/variables.css` for colour tokens, or the relevant component file in `styles/` for layout. CSS custom properties for colours live in `:root[data-theme="dark"]` and `:root[data-theme="light"]` inside `styles/variables.css`. The theme toggle is managed by `applyTheme()` in `src/js/01-theme.js`. After any CSS change, run `npm run build:css` to regenerate `styles.css` locally (needed for E2E tests). Do **not** commit `styles.css` — it is in `.gitignore`. ### Running a full build The `npm run build` convenience script runs all five build steps in sequence: @@ -329,8 +329,9 @@ feat!: redesign anchor hash scheme (removes legacy ?tab= param) - Do **not** use mutable tags (e.g. `@v6`) in `uses:` — always pin to a commit SHA with a full semver comment (e.g. `@abc1234... # v6.0.2`). - Do **not** finish a session without running `npm run test:ci` and `npm run test:e2e` to confirm both suites pass. - Do **not** let coverage decrease — a negative coverage delta on any PR fails the Codecov status check. -- Do **not** edit `changelog-data.js`, `milestones-data.js`, or `project-stats-data.js` directly — they are auto-generated; edit `CHANGELOG.md` / `milestones.yaml` / `project-stats.yaml` and run the corresponding build script. -- Do **not** edit `script.js` directly — it is auto-generated from `src/js/` source files; edit the relevant file in `src/js/` and run `npm run build:js`. -- Do **not** edit `styles.css` directly — it is auto-generated from `styles/` source files; edit the relevant file in `styles/` and run `npm run build:css`. +- Do **not** edit `changelog-data.js`, `milestones-data.js`, or `project-stats-data.js` directly — they are auto-generated and in `.gitignore`; edit `CHANGELOG.md` / `milestones.yaml` / `project-stats.yaml` and run the corresponding build script. +- Do **not** edit `script.js` directly — it is auto-generated from `src/js/` source files, is in `.gitignore`, and must not be committed; edit the relevant file in `src/js/` and run `npm run build:js` to regenerate it locally. +- Do **not** edit `styles.css` directly — it is auto-generated from `styles/` source files, is in `.gitignore`, and must not be committed; edit the relevant file in `styles/` and run `npm run build:css` to regenerate it locally. +- Do **not** commit `script.js`, `styles.css`, `changelog-data.js`, `milestones-data.js`, or `project-stats-data.js` — these are all in `.gitignore` and are rebuilt by CI automatically. - Do **not** bump the version in `package.json` manually — let release-please handle it via Conventional Commits. - Do **not** use free-form commit or PR title messages — always follow the Conventional Commits format described above. diff --git a/changelog-data.js b/changelog-data.js deleted file mode 100644 index ae0cf10..0000000 --- a/changelog-data.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -// AUTO-GENERATED from CHANGELOG.md — do not edit directly. -// Run `npm run build:changelog` to regenerate from CHANGELOG.md. - -const SITE_VERSION = "1.0.0"; - -const CHANGELOG_RELEASES = [ - { - version: "Unreleased", - date: null, - sections: [ - { heading: "Added", items: [ - "`.nvmrc` to pin Node.js version to 20 LTS (matching CI)", - "`.editorconfig` for consistent editor formatting across contributors", - "`\"homepage\"` field in `package.json` pointing to the live GitHub Pages site", - "`CHANGELOG.md` to track releases going forward", - ] } - ], - }, - { - version: "1.0.0", - date: "2025-04-14", - sections: [ - { heading: "Added", items: [ - "Live global AI token counter anchored to `BASE_DATE_ISO` (not page-load time)", - "Session counter showing tokens consumed since the page was opened", - "7 environmental milestone cards (trees → bees → water → coral → glaciers → ocean → extinction)", - "Chart.js growth chart with 18-month log-scale projection", - "Predictions table with estimated dates for each milestone", - "Dark / light theme toggle (dark default)", - "Prompt & PR scoring section with collapsible rubric", - "Jest test suite with 75 tests and ≥ 80 % coverage thresholds", - "GitHub Actions CI workflow (`test.yml`) running on every push and PR", - "GitHub Actions deploy workflow (`deploy.yml`) publishing to GitHub Pages on merge to `main`", - "`AGENTS.md` with architecture rules and contributor guidance", - ] } - ], - }, -]; - -/* istanbul ignore next */ -if (typeof module !== 'undefined' && module.exports) { - module.exports = { SITE_VERSION, CHANGELOG_RELEASES }; -} else if (typeof window !== 'undefined') { - window.ChangelogData = { SITE_VERSION, CHANGELOG_RELEASES }; -} diff --git a/milestones-data.js b/milestones-data.js deleted file mode 100644 index 7769a7e..0000000 --- a/milestones-data.js +++ /dev/null @@ -1,448 +0,0 @@ -'use strict'; -// AUTO-GENERATED from milestones.yaml — do not edit directly. -// Run `npm run build:milestones` to regenerate from milestones.yaml. - -const MILESTONES = [ - { - id: "first_forest", - name: "First Forest Felled", - icon: "🌲", - tokens: 1000000000000, - shortDesc: "1 Trillion Tokens", - description: "CO₂ equivalent of 50,000 mature trees cut down", - consequence: "A single trillion tokens generates CO₂ equal to the annual absorption of 50,000 mature trees. The Amazon loses 4.3 million acres per year — AI energy demands accelerate this.", - followingEvent: "🔥 Regional droughts intensify. Species lose habitat. The carbon feedback loop begins.", - color: "#2D9B27", - darkColor: "#1a6b15", - reference: "https://www.iea.org/reports/electricity-2024", - }, - { - id: "power_grid_strain", - name: "Power Grid Strain", - icon: "⚡", - tokens: 2000000000000, - shortDesc: "2 Trillion Tokens", - description: "AI data centres claim 1 % of global electricity — equal to all of Argentina", - consequence: "When data centres alone consume 1 % of the world's electricity, every brown-out and rolling blackout hits hospitals, water-treatment plants, and cold-storage food supplies first. Grid operators begin rationing power to residential users.", - followingEvent: "💡 Planned blackouts become routine. Industrial production slows. Energy poverty spikes.", - color: "#FFAA00", - darkColor: "#cc7700", - reference: "https://www.iea.org/reports/electricity-2024", - }, - { - id: "arctic_ice", - name: "First Ice-Free Arctic Summer", - icon: "🧊", - tokens: 5000000000000, - shortDesc: "5 Trillion Tokens", - description: "The Arctic Ocean is ice-free for the first time in recorded history", - consequence: "Sea ice reflects 80 % of incoming sunlight back into space. Without it, the dark Arctic Ocean absorbs that heat, accelerating warming by 2–3 × above the global average. Polar vortex destabilisation sends extreme weather to temperate regions.", - followingEvent: "❄️ Polar vortex collapses. Record cold snaps devastate agriculture at lower latitudes.", - color: "#B0E0FF", - darkColor: "#5aabdd", - reference: "https://www.nature.com/articles/s41586-022-05185-z", - }, - { - id: "bee_colony", - name: "Bee Colony Collapse", - icon: "🐝", - tokens: 10000000000000, - shortDesc: "10 Trillion Tokens", - description: "1 billion bees lost to energy-driven habitat destruction", - consequence: "Bees pollinate 35 % of human food crops. AI's growing energy demands accelerate pesticide use and destroy wildflower habitats that bee colonies depend on.", - followingEvent: "🌾 1-in-3 food items vanish from shelves. Crop yields drop 35 %. Food prices triple globally.", - color: "#FFD700", - darkColor: "#b39800", - reference: "https://www.science.org/doi/10.1126/science.1253124", - }, - { - id: "wildfire_crisis", - name: "Permanent Wildfire Season", - icon: "🔥", - tokens: 20000000000000, - shortDesc: "20 Trillion Tokens", - description: "Wildfire season becomes year-round across three continents", - consequence: "Warmer, drier conditions sustained by AI's CO₂ load eliminate the concept of a fire season. Forests in Australia, the American West, and Southern Europe burn continuously. Smoke blankets cities for months, pushing respiratory illness to epidemic levels.", - followingEvent: "🌫️ Air-quality emergencies declared in 40+ cities. Outdoor workers face daily health orders.", - color: "#FF5500", - darkColor: "#cc3300", - reference: "https://www.pnas.org/doi/10.1073/pnas.2011048117", - }, - { - id: "silent_species", - name: "Silent Spring: 100 Species Gone", - icon: "🐦", - tokens: 50000000000000, - shortDesc: "50 Trillion Tokens", - description: "100 vertebrate species driven to extinction by AI-linked habitat destruction", - consequence: "Habitat loss and climate change driven by AI energy demands erase entire branches of the tree of life. Each lost species unravels the web of interdependence — pest explosions, crop failures, and disease outbreaks follow as predator-prey balances collapse.", - followingEvent: "🌿 Ecosystems destabilise. Invasive species surge. Crop pests breed unchecked.", - color: "#66BB6A", - darkColor: "#3d7a40", - reference: "https://www.pnas.org/doi/10.1073/pnas.2306987120", - }, - { - id: "great_lakes", - name: "Great Lakes Drained", - icon: "💧", - tokens: 100000000000000, - shortDesc: "100 Trillion Tokens", - description: "Data-centre cooling drains freshwater equal to Lake Erie", - consequence: "AI data centres consume billions of litres of water annually for cooling. This draws down aquifers and surface supplies that took millennia to accumulate.", - followingEvent: "🚰 2 billion people face water scarcity. Water wars erupt between nations. Agriculture fails.", - color: "#0077BE", - darkColor: "#005490", - reference: "https://www.nature.com/articles/d41586-024-00278-9", - }, - { - id: "water_table_collapse", - name: "Global Water Table Collapse", - icon: "🌵", - tokens: 200000000000000, - shortDesc: "200 Trillion Tokens", - description: "Major aquifers — Ogallala, Indo-Gangetic, North China Plain — drop below recovery", - consequence: "Underground aquifers that supply half of all irrigation water worldwide have been drawn down past their natural recharge rates. AI data-centre demand pushes many past the point of no return. Regions that once fed nations face permanent desertification.", - followingEvent: "🏜️ Breadbasket nations become dust bowls. 1 billion people face famine. Food nationalism spikes.", - color: "#C8A96E", - darkColor: "#8a6e3e", - reference: "https://www.science.org/doi/10.1126/science.aaf3776", - }, - { - id: "amazon_tipping", - name: "Amazon Tipping Point", - icon: "🌳", - tokens: 300000000000000, - shortDesc: "300 Trillion Tokens", - description: "The Amazon rainforest begins converting to savannah — irreversibly", - consequence: "Scientists have long warned that 20–25 % deforestation would tip the Amazon into a self-drying feedback loop. AI's cumulative carbon contribution delivers the final increment of warming. The world's largest carbon sink becomes a carbon source.", - followingEvent: "🌪️ Global rainfall patterns shift. Monsoons fail. 3 billion people face drought.", - color: "#1B5E20", - darkColor: "#0d3b12", - reference: "https://www.science.org/doi/10.1126/sciadv.abi4517", - }, - { - id: "coral_reef", - name: "Great Barrier Reef Lost", - icon: "🪸", - tokens: 500000000000000, - shortDesc: "500 Trillion Tokens", - description: "CO₂ triggers mass bleaching — the Great Barrier Reef is gone", - consequence: "Coral reefs support 25 % of all marine species. Ocean acidification from CO₂ emissions destroys these ecosystems, removing the foundation of oceanic food chains.", - followingEvent: "🐠 500 million people lose their primary food source. Fisheries collapse. Ocean deserts expand.", - color: "#FF6B6B", - darkColor: "#cc3333", - reference: "https://www.nature.com/articles/s41558-017-0012-x", - }, - { - id: "permafrost_bomb", - name: "Permafrost Methane Bomb", - icon: "💨", - tokens: 750000000000000, - shortDesc: "750 Trillion Tokens", - description: "Siberian and Alaskan permafrost releases stored methane at runaway rates", - consequence: "Permafrost locks away an estimated 1.5 trillion tonnes of carbon — twice the amount currently in the atmosphere. Thawing driven by AI energy emissions triggers methane release that is 84× more potent than CO₂ over 20 years, creating a self-reinforcing feedback loop.", - followingEvent: "🌡️ Global temperature rises accelerate beyond all IPCC models. Climate targets become fiction.", - color: "#9E9E9E", - darkColor: "#616161", - reference: "https://www.nature.com/articles/s41586-018-0807-z", - }, - { - id: "glacier", - name: "Glacier Collapse", - icon: "🏔️", - tokens: 1000000000000000, - shortDesc: "1 Quadrillion Tokens", - description: "Warming equivalent destabilises the West Antarctic Ice Sheet", - consequence: "Glaciers are the world's largest freshwater reservoirs. Their loss permanently eliminates drinking water for billions and raises sea levels catastrophically.", - followingEvent: "🌊 Coastal cities begin flooding. 600 million people displaced. Sea level rises 3 metres.", - color: "#A8D8EA", - darkColor: "#6ba8c4", - reference: "https://www.nature.com/articles/s41558-023-01682-9", - }, - { - id: "ocean_acidification", - name: "Ocean Acidification Threshold", - icon: "🐟", - tokens: 2000000000000000, - shortDesc: "2 Quadrillion Tokens", - description: "Ocean pH drops to 7.95 — shellfish and coral larvae can no longer form shells", - consequence: "The ocean has absorbed 30 % of all human CO₂ emissions. As pH drops, the carbonate ions that marine organisms use to build shells and skeletons dissolve. Oysters, mussels, krill, and pteropods — the base of polar food webs — begin failing to reproduce.", - followingEvent: "🦐 Krill populations crash. Whales, penguins, and polar bears follow into starvation.", - color: "#0D47A1", - darkColor: "#082e6a", - reference: "https://www.nature.com/articles/s41561-023-01163-y", - }, - { - id: "sahel_collapse", - name: "Sahel Collapse", - icon: "☀️", - tokens: 5000000000000000, - shortDesc: "5 Quadrillion Tokens", - description: "The Sahel belt becomes uninhabitable — 300 million climate refugees displaced", - consequence: "The Sahel region, already at the edge of habitability, tips past the point where subsistence farming is possible. A belt of uninhabitable land stretches across Africa from Senegal to Somalia. Tens of millions of climate refugees overwhelm neighbouring regions.", - followingEvent: "🌍 Regional governments collapse. Conflict over water and arable land escalates to warfare.", - color: "#E65100", - darkColor: "#b33d00", - }, - { - id: "ocean_dead_zone", - name: "Ocean Dead Zone", - icon: "🌊", - tokens: 10000000000000000, - shortDesc: "10 Quadrillion Tokens", - description: "Ocean acidification creates a dead zone larger than the Pacific garbage patch", - consequence: "CO₂ absorbed by oceans shifts their pH — catastrophic for marine life. Phytoplankton, which produces 50 % of Earth's oxygen, begins dying off.", - followingEvent: "😮‍💨 Atmospheric oxygen concentration drops. Human cognitive function declines. Extinction accelerates.", - color: "#1A237E", - darkColor: "#0d1466", - reference: "https://www.science.org/doi/10.1126/science.aam6321", - }, - { - id: "jet_stream_collapse", - name: "Jet Stream Destabilised", - icon: "🌪️", - tokens: 30000000000000000, - shortDesc: "30 Quadrillion Tokens", - description: "Arctic amplification breaks the polar jet stream into chaotic loops", - consequence: "The jet stream normally separates cold Arctic air from warm temperate air. As the Arctic warms 4× faster than the rest of the planet, the temperature gradient that drives the jet stream weakens. It buckles into extreme meanders, locking weather patterns in place for weeks.", - followingEvent: "❄️🌡️ Europe freezes in July. Texas floods. Monsoons arrive months late. Harvests fail continent-wide.", - color: "#7E57C2", - darkColor: "#4a2d8a", - reference: "https://www.nature.com/articles/s41561-021-00848-8", - }, - { - id: "food_system_stress", - name: "Global Food System Under Siege", - icon: "🌾", - tokens: 50000000000000000, - shortDesc: "50 Quadrillion Tokens", - description: "Simultaneous crop failures on three continents push 1 billion into food insecurity", - consequence: "Extreme heat waves, erratic monsoons, and drought driven by AI's cumulative emissions hit major grain-producing regions simultaneously. Global food reserves drop below 60 days. Price spikes trigger social unrest across 40+ countries.", - followingEvent: "🍞 Food nationalism spreads. Export bans fracture global trade. Humanitarian crisis escalates.", - color: "#8D6E63", - darkColor: "#5d4037", - }, - { - id: "ai_thirst_today", - name: "AI Thirst Today", - icon: "💧", - tokens: 65075000000000000, - shortDesc: "65.075 Quadrillion Tokens", - description: "Data centres consume 4.3 billion litres of water — today's share of AI cooling", - consequence: "Each day, global AI inference consumes water equivalent to the daily supply of a city of 1.5 million people. Cooling systems in hyperscale data centres draw on local aquifers and municipal water supplies, competing directly with residential and agricultural demand.", - followingEvent: "🚰 Water stress alerts issued in tech-hub regions. Residents face hosepipe bans during heatwaves.", - color: "#29B6F6", - darkColor: "#0277bd", - reference: "https://www.nature.com/articles/d41586-024-00278-9", - }, - { - id: "daily_energy_reckoning", - name: "Daily Energy Reckoning", - icon: "⚡", - tokens: 65080000000000000, - shortDesc: "65.08 Quadrillion Tokens", - description: "Today’s AI inference consumes enough energy to power 25,000 homes for a year", - consequence: "The global AI industry now processes tokens at a rate that demands roughly 8.6 trillion tokens worth of energy every day. At current efficiency rates that equates to 2.6 million kWh — enough to power a small town for a year, consumed in 24 hours.", - followingEvent: "🏭 Industrial electricity tariffs rise as data-centre demand crowds out manufacturing.", - color: "#FFA726", - darkColor: "#e65100", - reference: "https://www.iea.org/energy-system/technology/data-centres-and-data-transmission-networks", - }, - { - id: "carbon_checkpoint", - name: "Carbon Checkpoint", - icon: "🌡️", - tokens: 65100000000000000, - shortDesc: "65.1 Quadrillion Tokens", - description: "Cumulative AI emissions now exceed the annual CO₂ output of a mid-sized nation", - consequence: "In just a few days, global AI systems will add token counts equivalent to the annual carbon footprint of a country of 10 million people. The rate is accelerating: what took years to accumulate early in AI's history now happens in weeks.", - followingEvent: "📊 Emissions trackers begin flagging AI as a discrete industrial sector in national inventories.", - color: "#EF5350", - darkColor: "#b71c1c", - }, - { - id: "fortnight_forest_impact", - name: "Fortnight Forest Impact", - icon: "🌳", - tokens: 65200000000000000, - shortDesc: "65.2 Quadrillion Tokens", - description: "Two weeks of AI token growth equals the carbon sequestration of 100,000 acres of forest", - consequence: "In the time it takes to grow two weeks' worth of tokens, AI systems generate CO₂ that would take 100,000 acres of mature forest a full year to reabsorb. Global deforestation is already outpacing replanting; AI adds a growing supplementary load.", - followingEvent: "🌳 Forest carbon credits tighten. Offsetting schemes struggle to keep pace with AI emissions.", - color: "#66BB6A", - darkColor: "#2e7d32", - }, - { - id: "city_power_month", - name: "City Power Month", - icon: "🏙️", - tokens: 65500000000000000, - shortDesc: "65.5 Quadrillion Tokens", - description: "Seven weeks of AI inference draws the same electricity as powering London for a month", - consequence: "Over the past seven weeks, global AI has consumed tokens generating electricity demand equivalent to powering a city the size of London for an entire month. Grid operators in high-density tech corridors now model AI load as a primary planning variable, alongside industrial and residential demand.", - followingEvent: "💡 Power utilities begin curtailment schedules for non-critical AI workloads during peak demand.", - color: "#AB47BC", - darkColor: "#6a1b9a", - reference: "https://www.iea.org/reports/electricity-2024", - }, - { - id: "quarterly_climate_cost", - name: "Quarterly Climate Cost", - icon: "🌊", - tokens: 66000000000000000, - shortDesc: "66 Quadrillion Tokens", - description: "AI’s quarterly token growth adds CO₂ equivalent to burning 5 billion kilograms of coal", - consequence: "In less than four months, the world's AI systems will process another quadrillion tokens. The energy bill: carbon equivalent to 5 billion kg of coal burned. Regulators in the EU and US begin mandating AI energy disclosures in quarterly corporate reports.", - followingEvent: "📋 Mandatory AI carbon audits proposed in 40 countries. Data-centre planning approvals stall.", - color: "#26A69A", - darkColor: "#00695c", - }, - { - id: "monsoon_disruption_warning", - name: "Monsoon Disruption Warning", - icon: "🌧️", - tokens: 67000000000000000, - shortDesc: "67 Quadrillion Tokens", - description: "Climate scientists flag AI energy heat-islands as a measurable monsoon disruptor", - consequence: "Concentrated heat output from mega-data-centre clusters alters local atmospheric moisture patterns. Research links the density of data-centre heat plumes in South and Southeast Asia to measurable shifts in pre-monsoon cloud formation. Delayed monsoons reduce crop yields for hundreds of millions of subsistence farmers.", - followingEvent: "💧 Monsoon onset delayed by 10–14 days in three major agricultural regions. Rice harvest forecasts cut.", - color: "#42A5F5", - darkColor: "#1565c0", - reference: "https://www.nature.com/articles/s41612-023-00387-4", - }, - { - id: "annual_energy_audit", - name: "Annual Energy Audit", - icon: "🏭", - tokens: 68000000000000000, - shortDesc: "68 Quadrillion Tokens", - description: "One year of AI growth consumes electricity equivalent to all of India for six months", - consequence: "A full year of AI token production adds 3+ quadrillion tokens to the cumulative total. The electricity bill for that year rivals the annual consumption of a G20 nation's residential sector. Power grids in major tech hubs routinely operate above 95 % capacity, leaving no margin for unexpected demand spikes.", - followingEvent: "🚨 Grid fragility incidents rise. Rolling brownouts reported in data-centre-dense regions.", - color: "#FF7043", - darkColor: "#bf360c", - reference: "https://www.iea.org/reports/electricity-2024", - }, - { - id: "two_year_carbon_budget", - name: "Two-Year Carbon Budget Warning", - icon: "🌱", - tokens: 72000000000000000, - shortDesc: "72 Quadrillion Tokens", - description: "Two years of AI compound growth consumes a measurable slice of the 1.5°C carbon budget", - consequence: "Scientists tracking the remaining carbon budget for 1.5°C identify AI infrastructure as one of the fastest-growing emission categories. Compound growth in token production means each passing year adds proportionally more CO₂, not less. The window for course correction narrows with every billion tokens.", - followingEvent: "🚨 IPCC emergency review triggered. AI emissions added to national carbon accounting frameworks.", - color: "#8BC34A", - darkColor: "#33691e", - reference: "https://www.ipcc.ch/report/ar6/syr/", - }, - { - id: "human_extinction", - name: "Human Extinction Horizon", - icon: "💀", - tokens: 77000000000000000, - shortDesc: "77 Quadrillion Tokens", - description: "Climate tipping points cascade simultaneously — the window for human survival closes", - consequence: "By 77 quadrillion tokens, multiple simultaneous tipping points have been crossed: the West Antarctic Ice Sheet enters irreversible collapse, the Amazon transitions to savanna, and Arctic summer sea ice disappears permanently. These feedbacks amplify each other. Global temperature is locked in at +3°C — a level incompatible with large-scale organised human society. Food systems fail. Mass displacement begins. Modern civilisation loses its ability to function.", - followingEvent: "🌡️ The last generation to know a stable climate is alive today. Their children inherit a planet in permanent crisis.", - color: "#1a0000", - darkColor: "#0d0000", - reference: "https://www.science.org/doi/10.1126/science.abn7950", - extinctionMarker: true, - }, - { - id: "grid_breaking_point", - name: "Grid Infrastructure Breaking Point", - icon: "🔋", - tokens: 80000000000000000, - shortDesc: "80 Quadrillion Tokens", - description: "AI now consumes more electricity than the entire global residential sector did in 2020", - consequence: "At 80 quadrillion tokens, AI's cumulative energy demand has grown to rival the residential electricity consumption of the entire planet circa 2020. Existing transmission infrastructure was not designed for this load. Brownouts, grid faults, and demand-rationing become normalised in regions without proactive investment.", - followingEvent: "💥 Major grid failures reported in three continents. Hospitals and data centres compete for backup power.", - color: "#F57F17", - darkColor: "#e65100", - reference: "https://www.iea.org/energy-system/technology/data-centres-and-data-transmission-networks", - }, - { - id: "decade_of_damage", - name: "Decade of Damage", - icon: "🌎", - tokens: 90000000000000000, - shortDesc: "90 Quadrillion Tokens", - description: "Eight years of unchecked AI growth locks in 0.1°C of additional warming", - consequence: "Climate models incorporating AI's compound energy trajectory show that eight years of growth at historical rates locks in an additional 0.1°C of warming above already-committed levels. That fraction of a degree translates into millions more people exposed to extreme heat, rising seas, and failing harvests.", - followingEvent: "📊 Climate departure dates brought forward by 3–5 years in tropical regions. Adaptation plans rewritten.", - color: "#D32F2F", - darkColor: "#7f0000", - reference: "https://www.nature.com/articles/s41558-022-01533-z", - }, - { - id: "mass_extinction", - name: "Sixth Mass Extinction", - icon: "💀", - tokens: 100000000000000000, - shortDesc: "100 Quadrillion Tokens", - description: "AI energy demands push 10,000+ species to irreversible extinction", - consequence: "We are already in the sixth mass extinction. AI's insatiable energy hunger accelerates species loss beyond any recovery. Biodiversity collapses irreversibly.", - followingEvent: "🌑 Ecosystem services fail. Agriculture collapses. Civilisation as we know it ends. The clock reaches zero.", - color: "#4A0000", - darkColor: "#2a0000", - reference: "https://www.pnas.org/doi/10.1073/pnas.2306987120", - }, - { - id: "permafrost_feedback", - name: "Permafrost Runaway Feedback", - icon: "🌡️", - tokens: 200000000000000000, - shortDesc: "200 Quadrillion Tokens", - description: "Permafrost thaw becomes self-sustaining — no longer stoppable by human action", - consequence: "With 200 quadrillion tokens of AI compute behind us, the permafrost feedback loop is irreversible. Methane and CO₂ now self-release regardless of human emissions reductions. Temperatures rise beyond every modelled scenario.", - followingEvent: "🌋 Feedback accelerates. Even zero human emissions cannot stop the warming now.", - color: "#BF360C", - darkColor: "#7f240a", - reference: "https://www.nature.com/articles/s41586-018-0807-z", - }, - { - id: "monsoon_failure", - name: "Asian Monsoon Failure", - icon: "🌧️", - tokens: 500000000000000000, - shortDesc: "500 Quadrillion Tokens", - description: "The Asian monsoon system fails — 3 billion people lose their primary water source", - consequence: "The Asian monsoon delivers 70–90 % of annual rainfall to South and East Asia. Disrupted atmospheric circulation patterns caused by AI's energy emissions collapse this ancient weather system. India, China, and Southeast Asia enter permanent drought.", - followingEvent: "💧 3 billion people face water crisis. Nuclear-armed states clash over rivers. Mass migrations begin.", - color: "#1565C0", - darkColor: "#0d3d7a", - }, - { - id: "civilization_collapse", - name: "Civilisation’s Last Stand", - icon: "🏙️", - tokens: 1000000000000000000, - shortDesc: "1 Quintillion Tokens", - description: "Cascading system failures end industrial civilisation as we know it", - consequence: "At one quintillion tokens, the cumulative environmental debt has come due. Power grids fail. Supply chains dissolve. Nation-states lose the ability to maintain basic services. The infrastructure that sustains 8 billion human lives begins to collapse.", - followingEvent: "🌑 Lights go out across continents. The age of AI ends not with intelligence, but with silence.", - color: "#212121", - darkColor: "#0a0a0a", - }, - { - id: "biosphere_collapse", - name: "Biosphere Collapse", - icon: "🌑", - tokens: 10000000000000000000, - shortDesc: "10 Quintillion Tokens", - description: "Earth’s life-support systems fail — the biosphere can no longer sustain complex life", - consequence: "The biosphere — the thin living layer that maintains Earth's temperature, atmosphere, and water cycles — has been pushed past all tipping points. Complex multicellular life can no longer be sustained. Earth enters a new geological epoch defined by absence.", - followingEvent: "🕳️ The experiment of intelligence on Earth concludes. The planet heals — in 10 million years.", - color: "#000000", - darkColor: "#000000", - }, -]; - -/* istanbul ignore next */ -if (typeof module !== 'undefined' && module.exports) { - module.exports = { MILESTONES }; -} else if (typeof window !== 'undefined') { - window.MilestonesData = { MILESTONES }; -} diff --git a/project-stats-data.js b/project-stats-data.js deleted file mode 100644 index b4b6253..0000000 --- a/project-stats-data.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; -// AUTO-GENERATED from project-stats.yaml — do not edit directly. -// Run `npm run build:project-stats` to regenerate from project-stats.yaml. - -const PROJECT_PR_COUNT = 48; -const PROJECT_TOTAL_TOKENS = 7200000; - -/* istanbul ignore next */ -if (typeof module !== 'undefined' && module.exports) { - module.exports = { PROJECT_PR_COUNT, PROJECT_TOTAL_TOKENS }; -} else if (typeof window !== 'undefined') { - window.ProjectStatsData = { PROJECT_PR_COUNT, PROJECT_TOTAL_TOKENS }; -} diff --git a/script.js b/script.js deleted file mode 100644 index f499b73..0000000 --- a/script.js +++ /dev/null @@ -1,129 +0,0 @@ -/* AI DEATH CLOCK — browser/DOM layer (minified) */ -"use strict";(function(){const{BASE_TOKENS:Kt,TOKENS_PER_SECOND:O,BASE_DATE_ISO:Gt,HISTORICAL_DATA:Yt,MILESTONES:I,RATE_SCHEDULE:Vt,SESSION_CHALLENGE_DEFS:$o,TOKEN_TIPS:jt,COMPANY_ROLES:ge,AI_AGENTS:pe,formatTokenCount:S,formatTokenCountShort:_,getTriggeredMilestones:Jt,getNextMilestone:zt,predictMilestoneDate:Re,calculateEnvironmentalImpact:A,generateProjectionData:Qt,formatDate:Pe,getTimeDelta:Oe,milestoneProgress:he,getRateAtDate:L,calculateTipImpact:Xt,generateEquivalences:Ne,calculatePersonalFootprint:He,sessionEquivalences:Zt,getNextMilestoneForPlayer:We,computeComboMultiplier:en,getSessionChallenges:tn,formatDoomPoints:X,computePassiveRate:fe,getCompanyStage:nn,getSimulatedViewerCount:on}=window.DeathClockCore,{SITE_VERSION:ye="",CHANGELOG_RELEASES:Ee=[]}=typeof window!="undefined"&&window.ChangelogData||{},{PROJECT_PR_COUNT:Ue=0,PROJECT_TOTAL_TOKENS:qe=0}=typeof window!="undefined"&&window.ProjectStatsData||{},sn=new Date(Gt).getTime(),x=Date.now();let be="dark",B=null;const Ke="tokenDeathclockFirstArrival",Ge="tokenDeathclockTheme";let Z=x;try{const e=parseInt(localStorage.getItem(Ke)||"0",10);e>0&&e<=x?Z=e:localStorage.setItem(Ke,String(x))}catch(e){}function $(){const e=(Date.now()-sn)/1e3;return Kt+O*e}function an(e){return e>=1e15?(e/1e15).toFixed(3)+" Quadrillion":e>=1e12?(e/1e12).toFixed(3)+" Trillion":S(e)}function Ye(e){document.documentElement.setAttribute("data-theme",e);const t=document.getElementById("themeToggle");t&&(t.textContent=e==="dark"?"\u2600\uFE0F":"\u{1F319}"),be=e,B&&mn()}function rn(){const e=be==="dark"?"light":"dark";Ye(e);try{localStorage.setItem(Ge,e)}catch(t){}e==="light"&&k("optimist")}function Ve(){const e=Date.now(),t=$(),n=L(new Date(e)),o=Math.round((e-Z)/1e3*n),s=Math.floor((e-Z)/1e3),i=document.getElementById("totalCounter"),r=document.getElementById("sessionCounter"),c=document.getElementById("sessionTime"),d=document.getElementById("rateCounter"),m=document.getElementById("rateEvent");if(i&&(i.textContent=an(t)),r&&(r.textContent=S(o)),c){const g=Math.floor(s/60),f=s%60,p=Z!==x?"since first visit":"on page";c.textContent=g>0?`${g}m ${f}s ${p}`:`${f}s ${p}`}if(d&&(d.textContent=S(n)),m){const g=[...Vt].reverse().find(f=>e>=new Date(f.date).getTime());g&&(m.textContent=g.event+" \xB7 tokens/sec")}const h=A(t);ee("statKwh",_(h.kWh)),ee("statCo2",_(h.co2Kg)),ee("statWater",_(h.waterL)),ee("statTrees",_(h.treesEquivalent)),Ft(t);const b=Jt(t,I);I.forEach((g,f)=>{const p=document.getElementById("milestone-"+g.id);if(!p)return;const T=p.classList.contains("triggered");t>=g.tokens&&!T&&(p.classList.add("triggered"),$t.has(g.id)||($t.add(g.id),yo(g)));const D=p.querySelector(".progress-fill");if(D){const y=f===0?0:I[f-1].tokens,v=he(t,y,g.tokens);D.style.width=v+"%";const C=p.querySelector(".progress-pct");C&&(C.textContent=v.toFixed(1)+"%")}}),requestAnimationFrame(Ve)}function ee(e,t){const n=document.getElementById(e);n&&(n.textContent=t)}function cn(){const e=document.getElementById("milestonesGrid");if(!e)return;const t=$();e.innerHTML="",I.forEach((n,o)=>{const s=t>=n.tokens,i=o===0?0:I[o-1].tokens,r=he(t,i,n.tokens),c=Re(t,O,n.tokens),d=document.createElement("div");d.className="milestone-card"+(s?" triggered":""),d.id="milestone-"+n.id,d.innerHTML=` -
- -
-
${u(n.name)}
-
${u(n.shortDesc)}
-
-
-

${u(n.description)}

-

${u(n.consequence)}

-
${u(n.followingEvent)}
-
-
- Progress - ${r.toFixed(1)}% -
-
-
-
-
- ${c?`
\u23F1 Predicted: ${u(Pe(c))} (${u(Oe(c))})
`:""} - ${n.reference?`\u{1F4CE} Source`:""} - `,e.appendChild(d)})}function ln(){const e=document.getElementById("predictionsBody");if(!e)return;const t=$();e.innerHTML="",I.forEach(n=>{const o=t>=n.tokens,s=o?null:Re(t,O,n.tokens),i=document.createElement("tr");i.innerHTML=` - ${u(n.icon)} ${u(n.name)} - ${u(n.shortDesc)} - ${o?'PASSED':"\u23F3 Pending"} - ${o?"\u2014":u(Pe(s))} - ${o?'Already triggered':u(Oe(s))} - `,e.appendChild(i)})}function dn(){const e=$(),t=Yt.map(o=>({x:o.date,y:o.tokensT})),n=Qt(e,O,60,void 0,.5).map(o=>({x:o.date,y:+o.tokensT.toFixed(2)}));return{historical:t,projection:n}}function je(){const e=be==="dark";return{histLine:e?"#ff3333":"#cc0000",projLine:e?"#ff8800":"#cc6600",gridColor:e?"rgba(255,255,255,0.07)":"rgba(0,0,0,0.08)",tickColor:e?"#888":"#555",bg:e?"#161616":"#ffffff"}}function un(){const e=document.getElementById("tokenChart");if(!e||typeof Chart=="undefined")return;const{historical:t,projection:n}=dn(),o=je(),s={};I.forEach((i,r)=>{s["milestone_"+r]={type:"line",yMin:i.tokens/1e12,yMax:i.tokens/1e12,borderColor:"rgba(0,204,119,0.4)",borderWidth:1,borderDash:[4,4],label:{content:i.icon+" "+i.shortDesc,display:!1}}}),B=new Chart(e,{type:"line",data:{datasets:[{label:"Historical (estimated)",data:t,borderColor:o.histLine,backgroundColor:"transparent",borderWidth:2,pointRadius:3,pointHoverRadius:5,tension:.35,fill:!1},{label:"Projected",data:n,borderColor:o.projLine,backgroundColor:"transparent",borderWidth:2,borderDash:[6,4],pointRadius:0,tension:.35,fill:!1}]},options:{responsive:!0,maintainAspectRatio:!1,interaction:{mode:"index",intersect:!1},scales:{x:{type:"time",time:{tooltipFormat:"MMM yyyy",displayFormats:{month:"MMM yy",year:"yyyy",quarter:"MMM yy"}},grid:{color:o.gridColor},ticks:{color:o.tickColor,maxRotation:45}},y:{type:"logarithmic",title:{display:!0,text:"Cumulative Tokens (Trillions, log scale)",color:o.tickColor,font:{size:11}},grid:{color:o.gridColor},ticks:{color:o.tickColor,callback:i=>_(i*1e12)}}},plugins:{legend:{labels:{color:o.tickColor,boxWidth:20,padding:16,font:{size:12}}},tooltip:{callbacks:{label:i=>" "+S(i.parsed.y*1e12)+" tokens"}}}}})}function mn(){if(!B)return;const e=je();B.data.datasets[0].borderColor=e.histLine,B.data.datasets[1].borderColor=e.projLine,B.options.scales.x.grid.color=e.gridColor,B.options.scales.y.grid.color=e.gridColor,B.options.scales.x.ticks.color=e.tickColor,B.options.scales.y.ticks.color=e.tickColor,B.options.scales.y.title.color=e.tickColor,B.options.plugins.legend.labels.color=e.tickColor,B.update("none")}function u(e){return typeof e!="string"?"":e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}const Je=I.find(e=>e.extinctionMarker)||I[I.length-1],l={level:"days",day:null,hour:null,minute:null,rafId:null,lastSec:-1,lastMin:-1,lastHr:-1,lastDayMs:0,exploding:!1};function ve(){const e=$();if(e>=Je.tokens)return Date.now();const t=(Je.tokens-e)/O;return Date.now()+t*1e3}function gn(){const e=ve()-Date.now();return Math.max(0,Math.ceil(e/864e5))}function F(e){const t=new Date(e);return t.setHours(0,0,0,0),t.getTime()}function ke(e,t,n){const o=e+t;return n>=o?"dead":n>=e?"dying":"future"}function N(e,t){return F(t)+e*864e5}function te(e,t,n,o){return`
${o}
`}function ne(e,t,n,o){return`
${o}
`}const q=3650;function pn(e,t){const n=gn(),o=Math.min(n,q),s=F(t),i=(t-s)/864e5*100,c=new Date(ve()).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"});let d=`
`;d+=te('data-day="0"',i,"Today \u2014 burning away","");for(let m=1;m<=o;m++)d+=ne("future",`data-day="${m}"`,`Day ${m} from now`,"");n>q&&(d+=`
- +${Math.round((n-q)/365)}y
`),d+="
",e.innerHTML=d,document.getElementById("lb-info").textContent=`${n.toLocaleString()} days until extinction \xB7 predicted ${c}`}function hn(e,t,n){const o=N(t,n),s=t===0;let i='
';for(let c=0;c<24;c++){const d=o+c*36e5,m=s?ke(d,36e5,n):"future",h=`${String(c).padStart(2,"0")}:00`,b=`${String(c).padStart(2,"0")}`;if(m==="dying"){const g=(n-d)/36e5*100;i+=te(`data-hour="${c}"`,g,h,b)}else i+=ne(m,`data-hour="${c}"`,h,b)}i+="
",e.innerHTML=i;const r=t===0?"Today":`Day +${t}`;document.getElementById("lb-info").textContent=`${r} \u2014 select an hour`}function fn(e,t,n,o){const i=N(t,o)+n*36e5,r=t===0&&o>=i&&o${String(d).padStart(2,"0")}`;if(h==="dying"){const f=(o-m)/6e4*100;c+=te(`data-minute="${d}"`,f,b,g)}else c+=ne(h,`data-minute="${d}"`,b,g)}c+="",e.innerHTML=c,document.getElementById("lb-info").textContent=`${String(n).padStart(2,"0")}:xx \u2014 select a minute`}function yn(e,t,n,o,s){const r=N(t,s)+n*36e5+o*6e4,c=t===0&&s>=r&&s${String(m).padStart(2,"0")}`;if(b==="dying"){const p=(s-h)/1e3*100;d+=te(`data-second="${m}"`,p,g,f)}else d+=ne(b,`data-second="${m}"`,g,f)}d+="",e.innerHTML=d,document.getElementById("lb-info").textContent=`${String(n).padStart(2,"0")}:${String(o).padStart(2,"0")}:xx`}function En(){const e=document.getElementById("lb-breadcrumb");if(!e)return;const t=[{label:"\u{1F480} Days",level:"days"}];l.level!=="days"&&t.push({label:`Day ${l.day===0?"Today":"+"+l.day}`,level:"hours"}),(l.level==="minutes"||l.level==="seconds")&&t.push({label:`Hour ${String(l.hour).padStart(2,"0")}`,level:"minutes"}),l.level==="seconds"&&t.push({label:`Min ${String(l.minute).padStart(2,"0")}`,level:"seconds"}),e.innerHTML=t.map((n,o)=>o===t.length-1?`${u(n.label)}`:`${u(n.label)} - `).join(""),e.querySelectorAll("[data-nav]").forEach(n=>{const o=n.getAttribute("data-nav");n.addEventListener("click",()=>ze(o)),n.addEventListener("keydown",s=>{(s.key==="Enter"||s.key===" ")&&ze(o)})})}function ze(e){l.level=e,e==="days"?(l.day=null,l.hour=null,l.minute=null):e==="hours"?(l.hour=null,l.minute=null):e==="minutes"&&(l.minute=null),K()}function K(){const e=document.getElementById("lb-container");if(!e)return;const t=Date.now(),n=new Date(t);l.lastSec=n.getSeconds(),l.lastMin=n.getMinutes(),l.lastHr=n.getHours(),l.lastDayMs=F(n),l.exploding=!1,l.level==="days"?pn(e,t):l.level==="hours"?hn(e,l.day,t):l.level==="minutes"?fn(e,l.day,l.hour,t):l.level==="seconds"&&yn(e,l.day,l.hour,l.minute,t),En(),bn(e)}function bn(e){e.querySelectorAll(".lb-block:not(.lb-dead)").forEach(t=>{t.addEventListener("click",Qe),t.addEventListener("keydown",n=>{(n.key==="Enter"||n.key===" ")&&Qe.call(t,n)})})}function Qe(e){const t=e.currentTarget||this;if(l.level==="days")l.day=parseInt(t.getAttribute("data-day"),10),l.level="hours";else if(l.level==="hours")l.hour=parseInt(t.getAttribute("data-hour"),10),l.level="minutes";else if(l.level==="minutes")l.minute=parseInt(t.getAttribute("data-minute"),10),l.level="seconds";else return;K()}function vn(e){if(l.exploding){e();return}const t=document.querySelector("#lb-container .lb-dying");if(!t){e();return}l.exploding=!0,t.classList.add("lb-exploding"),setTimeout(e,560)}function Xe(){const e=Date.now(),t=new Date(e);if(!l.exploding){const h=document.querySelector("#lb-container .lb-dying");if(h){let b,g;if(l.level==="days")b=F(t),g=864e5;else if(l.level==="hours"){const p=t.getHours();b=N(l.day,e)+p*36e5,g=36e5}else if(l.level==="minutes"){const p=t.getMinutes();b=N(l.day,e)+l.hour*36e5+p*6e4,g=6e4}else{const p=t.getSeconds();b=N(l.day,e)+l.hour*36e5+l.minute*6e4+p*1e3,g=1e3}const f=Math.min(100,(e-b)/g*100);h.style.setProperty("--progress",f.toFixed(2)+"%")}}const n=t.getSeconds(),o=t.getMinutes(),s=t.getHours(),i=F(t),r=l.level==="seconds"&&n!==l.lastSec,c=l.level==="minutes"&&o!==l.lastMin,d=l.level==="hours"&&s!==l.lastHr,m=l.level==="days"&&i!==l.lastDayMs;(r||c||d||m)&&!l.exploding&&(l.lastSec=n,l.lastMin=o,l.lastHr=s,l.lastDayMs=i,vn(()=>K())),l.rafId=requestAnimationFrame(Xe)}function kn(){K(),l.rafId=requestAnimationFrame(Xe),wn()}const Sn={seconds:"sec",minutes:"min",hours:"hr",days:"day",months:"month",years:"year"},E={rafId:null,active:!1,initialized:!1,lastSec:-1,lastMin:-1,lastHr:-1,lastDay:-1,lastMonth:-1,lastYear:-1,pendingCascade:!1,exploding:{sec:!1,min:!1,hr:!1,day:!1,month:!1,year:!1}};function Ze(e,t,n){const o=new Date(n),s=o.getFullYear(),i=o.getMonth(),r=o.getDate(),c=o.getHours(),d=o.getMinutes(),m=o.getSeconds(),h={years:"YEARS",months:"MONTHS",days:"DAYS",hours:"HOURS",minutes:"MINS",seconds:"SECS"},b=["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"];let g,f,p,T=null,w;switch(t){case"seconds":g=60,f=m,p=(n-Math.floor(n/1e3)*1e3)/1e3*100,w=y=>yy{const v=String(y).padStart(2,"0")+":00";return y{const C=v+1;return v{const me=b[C];return C30&&(T=`+${C-30}y`),w=Lo=>{const Q=v+Lo;return Q