diff --git a/infra/build-server/forgejo.sh b/infra/build-server/forgejo.sh index 71c60983a..a17f52fc1 100644 --- a/infra/build-server/forgejo.sh +++ b/infra/build-server/forgejo.sh @@ -93,7 +93,7 @@ ENABLED = false INI chown 1000:1000 /srv/git/config/app.ini; chmod 600 /srv/git/config/app.ini fi -if ! docker ps -a --format '{{.Names}}' | grep -qx forgejo; then +if [ -z "$(docker ps -a --filter 'name=^forgejo$' -q)" ]; then docker run -d --name forgejo --restart unless-stopped \ -e USER_UID=1000 -e USER_GID=1000 -e FORGEJO_CUSTOM=/data/gitea \ -v /srv/git/data:/data -v /srv/git/config/app.ini:/data/gitea/conf/app.ini \ diff --git a/infra/build-server/remote-run.sh b/infra/build-server/remote-run.sh index dadb4654f..772174f73 100755 --- a/infra/build-server/remote-run.sh +++ b/infra/build-server/remote-run.sh @@ -23,7 +23,7 @@ # 3. Appends one JSON line to /srv/builds/_log/builds.jsonl (the worker dashboard reads it; asked for by main on 6 October # 2026): on success, on failure and on the slot give-up. UTC ISO 8601 Z times, numbers unquoted, unknown fields omitted, # artefacts with bytes and sha256 only when the run succeeded (a failed build would list the previous build's files), -# the line kept under 4 KB. Since the evening of 6 October 2026 (the project lead: "make sure we are fixing and learning from all the +# the line kept under 4 KB. Since the evening of 6 October 2026 (the founder: "make sure we are fixing and learning from all the # errors here") the line also carries "class" and "run_log": # - PRE-FLIGHT before cargo runs: the manifest must parse (cargo metadata --no-deps) and every `-p` package must exist # (a workspace member, else cargo pkgid --offline); a refusal is exit 3, class preflight-manifest or preflight-package, @@ -320,7 +320,7 @@ PY SLOTS_DIR="$IGNEUM_BUILD_SLOTS_DIR" slots=$(cat "$SLOTS_DIR/slots" 2>/dev/null || echo 1); [ "$slots" -ge 1 ] 2>/dev/null || slots=1 -JOBS_ALONE="${JOBS_ALONE:-88}"; JOBS_SHARED="${JOBS_SHARED:-44}" # the project lead, 7 Oct 2026: 88 of 96 cores, 8 reserved for the release builds, the seed and the observers +JOBS_ALONE="${JOBS_ALONE:-88}"; JOBS_SHARED="${JOBS_SHARED:-44}" # the founder, 7 Oct 2026: 88 of 96 cores, 8 reserved for the release builds, the seed and the observers holder_line() { printf 'pid %s since %sZ waited %s s: %s\n' "$BR_PID" "$(date -u +%H:%M:%S)" "$1" "$BR_LABEL"; } give_up() { # echo "build-remote: gave up waiting for $1 after 2 h" >&2 diff --git a/site/app.html b/site/app.html index 6f7d58a7d..3b1de2801 100644 --- a/site/app.html +++ b/site/app.html @@ -218,8 +218,8 @@
Overview
- The Overview page of 0.3.16: an RTX 5090 at 103 MH/s and 317 W, 0.32 MH/W, 62 blocks this run and 91,521 lifetime, the Stop mining button, the chain drawn live with this rig's blocks ringed and locked checkpoints, the node synced with 5 peers, the activity log - The Overview page of 0.3.16 in light mode: an RTX 5090 at 103 MH/s and 317 W, the chain drawn live with this rig's blocks ringed + The Overview page of 0.3.16: an RTX 5090 at 103 MH/s and 317 W, 0.32 MH/W, 62 blocks this run and 91,521 lifetime, the Stop mining button, the chain drawn live with this rig's blocks ringed and locked checkpoints, the node synced with 5 peers, the activity log + The Overview page of 0.3.16 in light mode: an RTX 5090 at 103 MH/s and 317 W, the chain drawn live with this rig's blocks ringed
0.3.16, rendered from the RTX 5090 Windows rig’s live state at 23:33 UK, 6 October 2026. No electricity price is set on that rig, so the pounds cell asks for one.
@@ -230,8 +230,8 @@
Overview · Mac
- The Overview page on an Apple M5 Max: 18.3 MH/s, 6,789 blocks this run, the chain drawn live with this Mac's blocks in the lane marked you, locked checkpoints at 71% of weight, the node synced with 4 peers - The Overview page in light mode: 511 MH/s from one of three cards mining, 629 W, £4.23 a day of electricity, 6,784 blocks this run, the chain drawn live with this rig's blocks marked you, the node line and the activity log + The Overview page on an Apple M5 Max: 18.3 MH/s, 6,789 blocks this run, the chain drawn live with this Mac's blocks in the lane marked you, locked checkpoints at 71% of weight, the node synced with 4 peers + The Overview page in light mode: 511 MH/s from one of three cards mining, 629 W, £4.23 a day of electricity, 6,784 blocks this run, the chain drawn live with this rig's blocks marked you, the node line and the activity log
An Apple M5 Max mining at 18.3 MH/s, from the app in development.A three-card rig at 511 MH/s, from the app in development.
@@ -253,8 +253,8 @@
Cards
- The Cards page: Ember Tune with Efficiency, Balanced and Maximum goals and the watts it saves; one row per card with its rate, watts, hashes per watt, cost a day and temperature; the RTX 5090's details open with its power cap, goal, Retune and the tune curve of hash rate against power - The Cards page of 0.3.16 in light mode: Ember Tune, the RTX 5090 at 103 MH/s, 322 to 317 W, 68 degrees, its tune line and Retune button; the integrated AMD graphics off + The Cards page: Ember Tune with Efficiency, Balanced and Maximum goals and the watts it saves; one row per card with its rate, watts, hashes per watt, cost a day and temperature; the RTX 5090's details open with its power cap, goal, Retune and the tune curve of hash rate against power + The Cards page of 0.3.16 in light mode: Ember Tune, the RTX 5090 at 103 MH/s, 322 to 317 W, 68 degrees, its tune line and Retune button; the integrated AMD graphics off
The Cards page with a card’s details open, from the app in development.0.3.16, rendered from the RTX 5090 Windows rig’s live state at 23:33 UK, 6 October 2026.
@@ -310,8 +310,8 @@
Earnings
- The Earnings page of 0.3.16: pounds earned with the devnet reason, IGN from proofs, 23,056 blocks lifetime, electricity with no card reporting its draw, the dev fee switch, the rewards address with Copy, Change address, Show my key and Open the wallet - The Earnings page of 0.3.16 in light mode + The Earnings page of 0.3.16: pounds earned with the devnet reason, IGN from proofs, 23,056 blocks lifetime, electricity with no card reporting its draw, the dev fee switch, the rewards address with Copy, Change address, Show my key and Open the wallet + The Earnings page of 0.3.16 in light mode
0.3.16 on the team’s Apple M5 Max, paused, 6 October 2026. Pounds earned reads 0.00 on devnet and says why.
@@ -333,8 +333,8 @@
Prove
- The Prove page of 0.3.16: the Prove on this machine switch, one sentence per card on what it can prove, one line of counts, assigned, proven, paid and IGN, and Details - The Prove page of 0.3.16 in light mode + The Prove page of 0.3.16: the Prove on this machine switch, one sentence per card on what it can prove, one line of counts, assigned, proven, paid and IGN, and Details + The Prove page of 0.3.16 in light mode
0.3.16 on the team’s Apple M5 Max, 6 October 2026. Apple silicon proves on the CPU, slowly; a 24 GB NVIDIA card proves the full shard.
@@ -358,8 +358,8 @@
Settings · Tuning
- The Tuning card of Settings in 0.3.16: the goal at Balanced, the Ember Tune, Power control and Fine tuning switches, each with one sentence, and the electricity price in pence per kWh - The Tuning card of Settings in 0.3.16, light mode + The Tuning card of Settings in 0.3.16: the goal at Balanced, the Ember Tune, Power control and Fine tuning switches, each with one sentence, and the electricity price in pence per kWh + The Tuning card of Settings in 0.3.16, light mode
0.3.16 on the team’s Apple M5 Max, 6 October 2026.
    diff --git a/site/download.html b/site/download.html index 959aa08ee..82228296d 100644 --- a/site/download.html +++ b/site/download.html @@ -235,16 +235,16 @@

    Ember for Linux

    one tarball, the miner and the node inside

    Unpack it, run igneum with your payout address. The same signed manifest as the desktop apps. NVIDIA through CUDA, AMD through OpenCL.

    - Download the tarball v0.3.20 · 27.3 MB -
    sha256 d9dd12dfe900bf9f603995a6877e1758ae9b75a85ad899bf180aa86e72b2e57c
    + Download the tarball v0.3.22 · 28.8 MB +
    sha256 8ad6dcef9edc57dcd33e8d5a97cbef5cdda0e384a6e56d3f62f8903029c4c764

    Ember on HiveOS

    for the rig people, the same tarball
    -
    Flight Sheet. Miner: Custom. Installation URL: https://dl.igneum.network/dl/public/igneum-hive-0.3.20.tar.gz. Miner name igneum, wallet and worker 0x<your 40-hex payout address>.%WORKER_NAME%. Hive itself is untested on our side: tell us what breaks.
    - Download the tarball v0.3.20 · 27.3 MB +
    Flight Sheet. Miner: Custom. Installation URL: https://dl.igneum.network/dl/public/igneum-hive-0.3.22.tar.gz. Miner name igneum, wallet and worker 0x<your 40-hex payout address>.%WORKER_NAME%. Hive itself is untested on our side: tell us what breaks.
    + Download the tarball v0.3.22 · 28.8 MB
diff --git a/site/img/app-cards-dark.webp b/site/img/app-cards-dark.webp index 84646a9bd..a8e3cd83a 100644 Binary files a/site/img/app-cards-dark.webp and b/site/img/app-cards-dark.webp differ diff --git a/site/img/app-cards-light.webp b/site/img/app-cards-light.webp index c5c9c841f..11af849cb 100644 Binary files a/site/img/app-cards-light.webp and b/site/img/app-cards-light.webp differ diff --git a/site/img/app-earnings-dark.webp b/site/img/app-earnings-dark.webp index 9dd8e7087..85c9b3f14 100644 Binary files a/site/img/app-earnings-dark.webp and b/site/img/app-earnings-dark.webp differ diff --git a/site/img/app-earnings-light.webp b/site/img/app-earnings-light.webp index 34ad7b5f5..f70be2c6c 100644 Binary files a/site/img/app-earnings-light.webp and b/site/img/app-earnings-light.webp differ diff --git a/site/img/app-overview-dark.webp b/site/img/app-overview-dark.webp index ed4623526..e60b4e848 100644 Binary files a/site/img/app-overview-dark.webp and b/site/img/app-overview-dark.webp differ diff --git a/site/img/app-overview-light.webp b/site/img/app-overview-light.webp index 8d53ede81..9a6a438b1 100644 Binary files a/site/img/app-overview-light.webp and b/site/img/app-overview-light.webp differ diff --git a/site/img/app-overview-mac-dark.webp b/site/img/app-overview-mac-dark.webp index a0229dc70..1818c15a6 100644 Binary files a/site/img/app-overview-mac-dark.webp and b/site/img/app-overview-mac-dark.webp differ diff --git a/site/img/app-overview-mac-light.webp b/site/img/app-overview-mac-light.webp index 75dcb95ed..7c1470e4c 100644 Binary files a/site/img/app-overview-mac-light.webp and b/site/img/app-overview-mac-light.webp differ diff --git a/site/img/app-phone-cards-light.webp b/site/img/app-phone-cards-light.webp index b7e1c09f4..4968408c9 100644 Binary files a/site/img/app-phone-cards-light.webp and b/site/img/app-phone-cards-light.webp differ diff --git a/site/img/app-phone-cards.webp b/site/img/app-phone-cards.webp index 288993869..a9bebf93a 100644 Binary files a/site/img/app-phone-cards.webp and b/site/img/app-phone-cards.webp differ diff --git a/site/img/app-phone-overview-light.webp b/site/img/app-phone-overview-light.webp index 159c1bdd9..14158b0a0 100644 Binary files a/site/img/app-phone-overview-light.webp and b/site/img/app-phone-overview-light.webp differ diff --git a/site/img/app-phone-overview.webp b/site/img/app-phone-overview.webp index a45a34bc4..4d75ae2ee 100644 Binary files a/site/img/app-phone-overview.webp and b/site/img/app-phone-overview.webp differ diff --git a/site/img/app-prove-dark.webp b/site/img/app-prove-dark.webp index 5d7fe5644..22328faf7 100644 Binary files a/site/img/app-prove-dark.webp and b/site/img/app-prove-dark.webp differ diff --git a/site/img/app-prove-light.webp b/site/img/app-prove-light.webp index f086bb965..8a82cde64 100644 Binary files a/site/img/app-prove-light.webp and b/site/img/app-prove-light.webp differ diff --git a/site/img/app-settings-dark.webp b/site/img/app-settings-dark.webp index b5fb70822..fcdc46f23 100644 Binary files a/site/img/app-settings-dark.webp and b/site/img/app-settings-dark.webp differ diff --git a/site/img/app-settings-light.webp b/site/img/app-settings-light.webp index ca53cf1e9..6a45ba329 100644 Binary files a/site/img/app-settings-light.webp and b/site/img/app-settings-light.webp differ diff --git a/site/miner.html b/site/miner.html index 38ff0b2e1..778c7123f 100644 --- a/site/miner.html +++ b/site/miner.html @@ -268,9 +268,9 @@ pre b{color:var(--molten-text);font-weight:500}
@@ -384,17 +384,17 @@ pre b{color:var(--molten-text);font-weight:500}
Overview
- The Overview page of 0.3.16: an RTX 5090 at 103 MH/s and 317 W, 0.32 MH/W, 62 blocks this run and 91,521 lifetime, the Stop mining button, the chain drawn live with this rig's blocks ringed and locked checkpoints, the node synced with 5 peers + The Overview page of 0.3.16: an RTX 5090 at 103 MH/s and 317 W, 0.32 MH/W, 62 blocks this run and 91,521 lifetime, the Stop mining button, the chain drawn live with this rig's blocks ringed and locked checkpoints, the node synced with 5 peers
0.3.16, rendered from the RTX 5090 Windows rig’s live state at 23:33 UK, 6 October 2026.
Cards
- The Cards page: Ember Tune with Efficiency, Balanced and Maximum goals; one row per card with its rate, watts, hashes per watt, cost a day and temperature; the RTX 5090's details open with its power cap, goal, Retune and the tune curve + The Cards page: Ember Tune with Efficiency, Balanced and Maximum goals; one row per card with its rate, watts, hashes per watt, cost a day and temperature; the RTX 5090's details open with its power cap, goal, Retune and the tune curve
The Cards page, from the app in development.
Overview · Mac
- The Overview page on an Apple M5 Max: 18.3 MH/s, 6,789 blocks this run, the chain drawn live with this Mac's blocks in the lane marked you, locked checkpoints at 71% of weight, the node synced with 4 peers + The Overview page on an Apple M5 Max: 18.3 MH/s, 6,789 blocks this run, the chain drawn live with this Mac's blocks in the lane marked you, locked checkpoints at 71% of weight, the node synced with 4 peers
An Apple M5 Max mining at 18.3 MH/s, from the app in development.
diff --git a/site/provenance.html b/site/provenance.html index 4c6a99d16..1a29d2acf 100644 --- a/site/provenance.html +++ b/site/provenance.html @@ -238,7 +238,7 @@ table{min-width:560px}

Licence of Igneum's own code

Recommended: MIT, for the node fork's additions, igneum-pow, the prototypes and the tools. igneum-pow/Cargo.toml already declares license = "MIT" and should be read as provisional until the decision below.

-

Pending the maintainers' decision. Two obligations hold whatever is chosen: the fork keeps Kaspa's ISC copyright notice in vendor/igneum-node/LICENSE (ISC requires it), and the VDF code keeps chiavdf's Apache-2.0 notice and a statement of what was changed (Apache-2.0 section 4).

+

Pending the founder's decision. Two obligations hold whatever is chosen: the fork keeps Kaspa's ISC copyright notice in vendor/igneum-node/LICENSE (ISC requires it), and the VDF code keeps chiavdf's Apache-2.0 notice and a statement of what was changed (Apache-2.0 section 4).

Generated from the repository at build time. Times are UTC. Machine names are model names.

diff --git a/site/site.css b/site/site.css index 25fd7131e..e19affda9 100644 --- a/site/site.css +++ b/site/site.css @@ -29,7 +29,9 @@ --scrim:rgba(244,241,236,.72);--hover:rgba(0,0,0,.04);--ok:var(--molten); } /* ---------- 2. the package's rules ---------- */ -*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:120px}body{margin:0;background:var(--obsidian);color:var(--bone);font:17px/1.6 var(--sans);font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased}a{color:inherit;text-decoration:none}button,input,select,textarea{font:inherit}button,a,input,summary,select{ -webkit-tap-highlight-color:transparent}button{cursor:pointer}button:disabled{cursor:not-allowed;opacity:.55}button{color:inherit}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible,canvas:focus-visible{outline:2px solid var(--ember);outline-offset:5px}::selection{color:var(--bone);background:var(--ember-tint)}[hidden]{display:none!important}img,svg,canvas{max-width:100%}h1,h2,h3,h4,p{margin:0}h1,h2,h3{font-family:var(--display);text-wrap:balance}h1{font-size:clamp(38px,5.2vw,70px);font-weight:900;line-height:1.12;letter-spacing:-.055em}h2{font-size:clamp(26px,3.05vw,42px);line-height:1.2;letter-spacing:-.035em;font-weight:700}h3{font-size:19px;line-height:1.4;letter-spacing:-.02em;font-weight:700}h4{font-size:17px;font-weight:600}p{text-wrap:pretty}p+p{margin-top:15px}.container{max-width:var(--max);margin:auto;padding:0 36px}.section{padding:100px 0}.section.compact{padding:64px 0}.muted{color:var(--ash)}.accent{color:var(--ember)}.molten{color:var(--molten)}.mono{font-family:var(--mono)}.eyebrow{display:flex;align-items:center;gap:10px;font:500 11px/1.7 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ash);margin-bottom:20px}.eyebrow .line{display:inline-block;width:24px;height:1px;background:var(--ember)}.eyebrow em{font-style:normal;color:var(--ember)}.lead{font-size:19px;line-height:1.65;color:var(--ink-2);max-width:53ch;margin-top:24px}.small{font-size:13px;color:var(--ash)}.rule{border-top:1px solid var(--line)}.pill{display:inline-flex;align-items:center;gap:8px;font:500 10px/1.4 var(--mono);letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--line-2);padding:7px 10px;border-radius:5px;white-space:nowrap}.pill.warm{color:var(--molten);border-color:color-mix(in srgb,var(--molten) 28%,transparent);background:color-mix(in srgb,var(--molten) 6%,transparent)}.dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--molten)}.icon{display:inline-block;width:20px;height:20px;vertical-align:middle;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.btn{display:inline-flex;align-items:center;justify-content:center;gap:14px;min-height:48px;border:1px solid var(--line-2);background:var(--graphite);border-radius:8px;padding:13px 20px;font:700 12px/1.4 var(--display);letter-spacing:-.01em;transition:transform .2s,background .2s,border-color .2s}.btn:hover{border-color:var(--ash);transform:translateY(-2px)}.btn.primary{background:var(--ember);border-color:var(--ember);color:var(--ember-ink)}.btn.primary:hover{background:var(--ember-hi);border-color:var(--ember-hi)}.btn.ghost{background:transparent}.btn.small-btn{font:500 12px var(--sans);min-height:38px;padding:9px 12px}.btn.icon-btn{width:40px;height:40px;min-height:40px;padding:10px;border-color:transparent;background:transparent}.btn.icon-btn:hover{background:var(--graphite);border-color:var(--line)}.actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:30px}.text-link{display:inline-flex;align-items:center;gap:10px;color:var(--ink-2);font-size:14px;font-weight:500}.text-link:hover{color:var(--ember)}.text-link .icon{width:16px;height:16px}.skip{position:fixed;left:20px;top:-100px;z-index:100;background:var(--ember);color:var(--ember-ink);padding:12px}.skip:focus{top:15px}.statusbar{height:33px;border-bottom:1px solid var(--line);font:10px var(--mono);color:var(--ash);letter-spacing:.04em}.statusbar .container{height:100%;display:flex;align-items:center;justify-content:space-between;gap:15px}.statusbar .dev-label{color:var(--molten);margin-right:15px}.site-header,.nav{position:sticky;top:0;z-index:30;background:var(--glass);border-bottom:1px solid var(--line);backdrop-filter:blur(16px)}.nav-row{height:80px;display:flex;align-items:center;gap:36px}.logo{display:inline-flex;align-items:center;gap:10px;font:900 20px/1 var(--display);letter-spacing:.055em;flex-shrink:0}.logo .brand-mark{width:36px;height:36px;display:block}.logo .stop{color:#F2541B}.logo .word{font:inherit}.nav-links,.nav .links{display:flex;gap:27px;align-items:center;flex:1;justify-content:center}.nav-links>a,.nav .links>a,.nav-dropdown>summary{font-size:13px;color:var(--ink-2);white-space:nowrap}.nav-links>a:hover,.nav-links>a[aria-current=page],.nav .links>a:hover,.nav .links>a[aria-current=page]{color:var(--ember)}.nav-dropdown{position:relative}.nav-dropdown>summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:7px}.nav-dropdown>summary::-webkit-details-marker{display:none}.nav-dropdown .icon{width:12px}.dropdown-body{position:absolute;top:34px;right:-55px;width:540px;padding:22px;background:var(--graphite);border:1px solid var(--line-2);border-radius:14px;box-shadow:var(--shadow);display:grid;grid-template-columns:1fr 1fr;gap:4px}.dropdown-body a{font-size:14px;padding:10px 12px;border-radius:6px}.dropdown-body a:hover{background:var(--row);color:var(--ember)}.dropdown-body a small{display:block;color:var(--ash);font-size:11px;font-family:var(--mono);margin-top:3px}.nav-controls{display:flex;align-items:center;gap:7px}.nav-controls .btn.primary,.nav .cta{font-size:11px;min-height:40px;padding:11px 15px}.mobile-toggle,.burger{display:none}.mobile-nav,.nav-sheet{padding:16px 25px 25px;border-top:1px solid var(--line);max-height:70vh;overflow:auto;grid-template-columns:1fr 1fr;gap:5px}.mobile-nav a,.nav-sheet a{padding:9px 5px;font-size:14px}.mobile-nav:not([hidden]),.nav.open .nav-sheet{display:grid}.hero{padding:76px 0 57px;overflow:hidden}.hero-grid{display:grid;grid-template-columns:1.1fr 1fr;align-items:center;gap:12px;min-height:510px}.hero-copy{position:relative;z-index:1;padding-bottom:16px}.hero-copy h1 .accent{display:inline-block}.hero-copy .lead{max-width:43ch}.hero-footnote{display:flex;align-items:center;gap:9px;margin-top:20px;font:10px/1.6 var(--mono);color:var(--ash)}.hero-footnote .icon{width:14px}.hero-scene{height:500px;position:relative;margin-right:-20px;isolation:isolate}.hero-scene:before{content:'';position:absolute;inset:20px -50px 0;background:radial-gradient(ellipse at 58% 48%,rgba(242,84,27,.075),transparent 65%);z-index:-1}.hero-scene canvas{display:block;width:100%;height:100%}.scene-corner{position:absolute;font:10px/1.5 var(--mono);color:var(--ash);letter-spacing:.05em;pointer-events:none}.scene-corner.tl{left:15px;top:22px}.scene-corner.tr{right:24px;top:22px;text-align:right}.scene-corner.bl{left:15px;bottom:84px}.scene-corner.br{right:24px;bottom:30px;text-align:right;max-width:calc(50% - 130px)}.scene-corner strong{display:block;color:var(--ink-2);font-weight:500;margin-bottom:4px}.scene-steps{position:absolute;left:50%;bottom:30px;transform:translateX(-50%);display:flex;gap:5px;border:1px solid var(--line);padding:5px;border-radius:10px;background:var(--glass)}.scene-step{background:transparent;border:0;color:var(--ash);font:11px var(--mono);padding:9px 13px;border-radius:6px;white-space:nowrap}.scene-step[aria-pressed=true]{background:var(--ember-tint);color:var(--ember)}.scene-step:hover{color:var(--bone)}.hero-bottom{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);padding-top:25px;margin-top:26px;gap:28px}.principle{display:flex;gap:13px;align-items:flex-start}.principle .icon{color:var(--ember);width:17px;margin-top:2px}.principle strong{font-size:13px;font-weight:500;display:block}.principle small{font-size:11px;color:var(--ash);display:block;margin-top:4px}.section-head{display:flex;justify-content:space-between;align-items:flex-end;gap:30px;margin-bottom:36px}.section-head h2{max-width:20ch}.section-head>p{color:var(--ash);max-width:40ch;font-size:16px}.section-head .eyebrow{margin-bottom:12px}.panel{background:var(--row);border:1px solid var(--line);border-radius:16px;overflow:hidden}.panel-head{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:21px 25px;border-bottom:1px solid var(--line)}.panel-head .eyebrow{margin:0}.panel-controls{display:flex;gap:6px;align-items:center;flex-wrap:wrap}.panel-footer{display:flex;align-items:center;justify-content:space-between;padding:17px 25px;gap:12px;border-top:1px solid var(--line);font:10px/1.7 var(--mono);color:var(--ash)}.live-peek{position:relative}.live-peek canvas{display:block;height:280px;width:100%}.legend{display:flex;gap:17px;align-items:center;flex-wrap:wrap;font:10px var(--mono);color:var(--ash)}.legend i{display:inline-block;width:6px;height:6px;background:var(--ember);margin-right:6px}.legend .your{background:var(--molten)}.legend .included{background:var(--included)}.legend .excluded{background:var(--excluded)}.label-below{font-size:12px;color:var(--ash);margin-top:14px;display:flex;justify-content:space-between;gap:20px}.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:22px}.feature{position:relative;padding:30px 29px;background:var(--row);border:1px solid var(--line);border-radius:14px;overflow:hidden}.feature:after{content:'';position:absolute;width:75px;height:1px;top:0;left:29px;background:var(--ember);opacity:.7}.feature .number{font:11px var(--mono);color:var(--ember);margin-bottom:30px;display:flex;align-items:center;justify-content:space-between}.feature .number .icon{width:24px;height:24px;color:var(--ash)}.feature h3{margin-bottom:15px}.feature p{color:var(--ash);font-size:15px}.feature .text-link{margin-top:28px}.feature-graphic{height:120px;width:100%;margin:15px 0;display:flex;align-items:center;justify-content:center}.chip-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:5px;width:100%;max-width:260px;transform:perspective(400px) rotateX(30deg) rotateZ(-7deg)}.chip-grid i{display:block;height:10px;border:1px solid var(--line-2);border-radius:2px}.chip-grid i:nth-child(3n),.chip-grid i:nth-child(7n){background:var(--ember-tint);border-color:color-mix(in srgb,var(--ember) 50%,var(--line))}.split-section{display:grid;grid-template-columns:1fr 1fr;gap:100px;align-items:center}.split-section .lead{font-size:17px}.split-section h2{max-width:19ch}.reward-bars{padding:32px}.reward-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}.reward-row strong{font:700 38px var(--display);letter-spacing:-.04em}.reward-bar{height:12px;background:var(--graphite);display:flex;border-radius:3px;overflow:hidden;gap:3px;margin:24px 0}.reward-bar i:first-child{width:80%;background:var(--ember)}.reward-bar i:last-child{width:20%;background:var(--molten)}.reward-key{display:flex;justify-content:space-between;gap:25px;margin-top:26px;font-size:13px}.reward-key strong{display:block;margin-bottom:5px}.reward-key span{color:var(--ash)}.reward-note{margin-top:27px;border-top:1px solid var(--line);padding-top:20px;font:10px/1.8 var(--mono);color:var(--ash)}.mini-title{font:500 11px var(--mono);letter-spacing:.1em;text-transform:uppercase}.tag-row{display:flex;gap:8px;flex-wrap:wrap;margin-top:24px}.cta-band{position:relative;padding:58px;border:1px solid color-mix(in srgb,var(--ember) 35%,var(--line));border-radius:16px;background:linear-gradient(120deg,var(--ember-tint),transparent 70%);display:flex;align-items:center;justify-content:space-between;gap:40px;overflow:hidden}.cta-band h2{max-width:20ch}.cta-band p{color:var(--ash);font-size:15px;margin-top:15px;max-width:50ch}.cta-band .actions{margin:0;flex-shrink:0}.site-footer{padding:64px 0 25px;border-top:1px solid var(--line)}.footer-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:50px}.footer-brand p{font-size:13px;color:var(--ash);margin:21px 0}.footer-column h4{font:500 10px var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ash);margin-bottom:20px}.footer-column a{display:block;font-size:13px;margin:10px 0;color:var(--ink-2)}.footer-column a:hover{color:var(--ember)}.footer-bottom{margin-top:54px;border-top:1px solid var(--line);padding-top:22px;display:flex;justify-content:space-between;gap:20px;font:10px/1.8 var(--mono);color:var(--ash)}.footer-bottom p{max-width:82ch}.theme-group{display:flex;align-items:center;gap:3px;border:1px solid var(--line);padding:3px;border-radius:6px;align-self:flex-start}.theme-group button{background:none;border:0;border-radius:3px;font:10px var(--mono);padding:7px 10px;color:var(--ash)}.theme-group button[aria-pressed=true]{background:var(--graphite);color:var(--bone)}.page-hero{padding:65px 0 45px}.page-hero h1{font-size:clamp(36px,4.2vw,56px);max-width:22ch}.page-hero .lead{max-width:67ch;font-size:18px}.breadcrumb{font:10px var(--mono);color:var(--ash);margin-bottom:28px;display:flex;gap:12px}.breadcrumb a:hover{color:var(--ember)}.page-heading{display:flex;justify-content:space-between;align-items:flex-end;gap:40px}.page-heading .actions{margin:0}.tabs{display:flex;gap:5px;border-bottom:1px solid var(--line);margin-top:24px;overflow-x:auto;scrollbar-width:thin}.tabs button,.tabs a{background:none;border:0;border-bottom:2px solid transparent;padding:14px 17px;color:var(--ash);font:500 13px var(--sans);white-space:nowrap}.tabs [aria-selected=true],.tabs [aria-current=page]{border-bottom-color:var(--ember);color:var(--bone)}.tabs button:hover{color:var(--bone)}.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-bottom:24px;background:var(--row)}.stat{padding:22px 25px;border-right:1px solid var(--line)}.stat:last-child{border-right:0}.stat .key{font:10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);margin-bottom:11px}.stat strong{font:700 clamp(21px,2.2vw,29px) var(--display);letter-spacing:-.04em}.stat .small{font-size:10px;font-family:var(--mono);margin-top:8px}.console-layout{display:grid;grid-template-columns:minmax(0,1fr) 295px;gap:18px}.dag-panel{position:relative}.dag-panel canvas{height:420px;display:block;width:100%;touch-action:pan-y}.dag-tip{position:absolute;left:0;top:65px;pointer-events:none;z-index:4;max-width:280px;overflow-wrap:anywhere;white-space:pre-line;border:1px solid var(--line-2);padding:11px 13px;background:var(--graphite);border-radius:8px;box-shadow:var(--shadow);font:10px/1.8 var(--mono)}.dag-tip b,.dag-tip span{display:block}.inspector{padding:22px}.inspector .eyebrow{font-size:10px;margin:0}.inspector canvas{width:100%;height:200px;display:block}.inspector h3{font-size:13px;word-break:break-all;margin-bottom:17px}.data-row{display:flex;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);font:11px var(--mono)}.data-row:last-child{border:0}.data-row span{color:var(--ash)}.data-row strong{font-weight:500;text-align:right}.shards{display:flex;gap:6px;margin:18px 0}.shard{flex:1;min-width:0;border:1px solid var(--line-2);border-radius:4px;padding:10px 0;text-align:center;font:9px var(--mono);color:var(--ash);background:var(--graphite)}.shard[data-state=verified]{border-color:var(--ember);color:var(--ember)}.shard[data-state=paid]{border-color:var(--molten);color:var(--molten)}.shard[data-state=proving]{background:var(--ember-tint);border-color:var(--ember);color:var(--ember)}.demo-controls{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:17px 0;color:var(--ash);font-size:12px}.demo-controls>div{display:flex;gap:7px;flex-wrap:wrap}.demo-controls .btn{font-family:var(--mono);font-size:10px;min-height:35px;padding:8px 11px}.tables-row{margin-top:25px}.table-wrap{overflow-x:auto;max-width:100%;border:1px solid var(--line);border-radius:12px;background:var(--row)}table{border-collapse:collapse;width:100%;text-align:left;font-size:13px}caption{text-align:left;padding:20px 22px;color:var(--ash);font:10px var(--mono);letter-spacing:.12em;text-transform:uppercase}th{font:500 10px/1.6 var(--mono);text-transform:uppercase;letter-spacing:.08em;color:var(--ash);padding:13px 22px;border-bottom:1px solid var(--line);white-space:nowrap}td{padding:15px 22px;border-bottom:1px solid var(--line);white-space:nowrap}tr:last-child td{border:0}tbody tr:hover{background:var(--graphite)}.table-button{border:0;background:none;color:var(--molten);padding:0;font:12px var(--mono);text-align:left}.table-button:hover{text-decoration:underline}.small-caption{font-size:12px;color:var(--ash);padding:13px 0}.badge{display:inline-block;padding:4px 7px;border:1px solid var(--line-2);border-radius:4px;font:10px var(--mono);color:var(--ink-2);white-space:nowrap}.badge.warm{border-color:color-mix(in srgb,var(--ember) 40%,transparent);color:var(--ember)}.badge.gold{border-color:color-mix(in srgb,var(--molten) 40%,transparent);color:var(--molten)}.events{padding:8px 21px}.event{display:flex;gap:15px;padding:15px 0;border-bottom:1px solid var(--line);align-items:flex-start;font-size:12px}.event:last-child{border:0}.event .icon{color:var(--ember);width:15px}.event p{line-height:1.5}.event time{display:block;font:9px var(--mono);color:var(--ash);margin-top:5px}.event-tag{font:9px var(--mono);margin-left:auto;color:var(--ash);white-space:nowrap}.source-note{font:10px/1.8 var(--mono);color:var(--ash);margin-top:22px;padding-left:12px;border-left:2px solid var(--line-2)}.source-note a{color:var(--ink-2);text-decoration:underline;text-underline-offset:3px}.source-note a:hover{color:var(--ember)}.download-layout{display:grid;grid-template-columns:1.1fr 1fr;gap:52px;align-items:center}.app-window{border:1px solid var(--line-2);border-radius:15px;background:var(--row);box-shadow:var(--shadow);overflow:hidden}.window-top{height:43px;border-bottom:1px solid var(--line);display:flex;align-items:center;padding:0 17px;gap:5px;font:10px var(--mono);color:var(--ash)}.window-top i{width:6px;height:6px;background:var(--line-2);border-radius:50%}.window-top span{margin-left:auto;margin-right:auto}.app-inner{display:grid;grid-template-columns:100px 1fr;min-height:370px}.app-sidebar{padding:17px 11px;border-right:1px solid var(--line);font:10px var(--mono);color:var(--ash)}.app-sidebar div{padding:9px 7px;margin-bottom:4px}.app-sidebar div.on{color:var(--ember);background:var(--ember-tint);border-radius:4px}.app-content{padding:22px;min-width:0}.app-content .app-greeting{display:flex;justify-content:space-between;align-items:center;margin-bottom:22px}.app-content .app-greeting strong{font:700 14px var(--display)}.app-content .app-greeting .pill{font-size:8px;padding:5px}.app-stats{display:grid;grid-template-columns:1fr 1fr;gap:10px}.app-stat{border:1px solid var(--line);border-radius:7px;padding:12px}.app-stat span{display:block;font:9px var(--mono);color:var(--ash);margin-bottom:8px}.app-stat strong{font:700 20px var(--display)}.app-content canvas{width:100%;height:145px;display:block}.app-bar{display:flex;justify-content:space-between;font:9px var(--mono);border:1px solid var(--line);padding:11px;border-radius:6px}.app-bar b{color:var(--molten);font-weight:400}.download-card{padding:27px}.download-card .tabs{margin-top:0}.download-card .tabs button{padding:12px 15px;flex:1}.platform-body{padding-top:24px}.platform-body .platform-title{display:flex;align-items:center;gap:15px;margin:10px 0 15px}.platform-title .icon{width:28px;height:28px}.platform-body h3{font-size:18px}.platform-body p{font-size:14px;color:var(--ash)}.platform-body .btn{width:100%;margin-top:26px}.download-detail{display:flex;justify-content:space-between;gap:15px;font:10px var(--mono);margin-top:15px;color:var(--ash)}.step-list{display:grid;gap:0}.step-item{display:grid;grid-template-columns:44px 1fr;gap:20px;padding:28px 0;border-top:1px solid var(--line)}.step-item .step-index{font:700 14px var(--display);color:var(--ember);border:1px solid var(--line-2);height:38px;width:38px;display:grid;place-items:center;border-radius:8px}.step-item h3{font-size:16px;margin-bottom:9px}.step-item p{font-size:15px;color:var(--ash)}.faq details{border-bottom:1px solid var(--line)}.faq summary{font-size:16px;font-weight:500;list-style:none;cursor:pointer;display:flex;justify-content:space-between;gap:20px;padding:21px 0}.faq summary:after{content:'+';color:var(--ash);font:20px var(--mono)}.faq details[open] summary:after{content:'-';color:var(--ember)}.faq details p{padding-bottom:24px;color:var(--ash);font-size:15px;max-width:85ch}.faq details a{color:var(--ember)}.tools-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}.tool-card{border:1px solid var(--line);border-radius:14px;padding:25px;transition:border-color .2s,transform .2s;background:var(--row)}.tool-card:hover{border-color:var(--line-2);transform:translateY(-3px)}.tool-card .icon{color:var(--ember);width:26px;height:26px;margin-bottom:22px}.tool-card h3{font-size:16px;margin-bottom:12px}.tool-card p{color:var(--ash);font-size:14px}.tool-card .text-link{margin-top:22px}.docs-layout{display:grid;grid-template-columns:230px minmax(0,1fr);gap:55px;align-items:start}.doc-nav{position:sticky;top:112px;max-height:calc(100vh - 145px);overflow:auto;border-right:1px solid var(--line);padding-right:20px;scrollbar-width:thin}.doc-nav .eyebrow{margin-bottom:17px;font-size:10px}.doc-nav a{display:block;font-size:12px;color:var(--ash);padding:8px 10px;border-left:2px solid transparent}.doc-nav a:hover,.doc-nav a.active{color:var(--ember);background:var(--ember-tint);border-left-color:var(--ember)}.doc-body{max-width:810px;min-width:0}.doc-section{padding-bottom:42px;margin-bottom:42px;border-bottom:1px solid var(--line);scroll-margin-top:110px}.doc-section h2{font-size:27px;margin:0 0 22px}.doc-section h3{font-size:16px;margin:26px 0 13px}.doc-section p{color:var(--ink-2);font-size:16px;line-height:1.85}.doc-section .section-number{font:11px var(--mono);color:var(--ember);margin-bottom:13px}.doc-section li{color:var(--ink-2);font-size:15px;margin:9px 0}.doc-section .table-wrap{margin:25px 0}.doc-section td{white-space:normal;min-width:140px;font-size:13px}.doc-notice{background:var(--ember-tint);border:1px solid color-mix(in srgb,var(--ember) 25%,var(--line));border-radius:10px;padding:20px 24px;margin-bottom:35px;font-size:13px;color:var(--ink-2)}.doc-notice strong{display:block;color:var(--molten);margin-bottom:6px;font-weight:500}.doc-notice a{color:var(--ember);text-decoration:underline;text-underline-offset:3px}.searchbar{position:relative;display:flex;align-items:center;gap:12px;padding:12px 16px;border:1px solid var(--line-2);border-radius:8px;background:var(--row)}.searchbar .icon{width:17px;color:var(--ash)}.searchbar input{flex:1;min-width:0;border:0;outline:none;background:transparent;color:var(--bone);font-size:14px}.searchbar input::placeholder{color:var(--ash)}.filter-row{display:flex;gap:8px;flex-wrap:wrap;margin:22px 0}.filter{background:none;border:1px solid var(--line);border-radius:6px;padding:8px 13px;font:11px var(--mono);color:var(--ash)}.filter[aria-pressed=true]{border-color:var(--ember);color:var(--ember);background:var(--ember-tint)}.filter:hover{color:var(--bone)}.record-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.record{background:var(--row);border:1px solid var(--line);border-radius:12px;padding:25px}.record .record-top{display:flex;justify-content:space-between;gap:15px;align-items:center;margin-bottom:20px}.record time{font:10px var(--mono);color:var(--ash)}.record h3{font-size:16px;max-width:35ch;line-height:1.5;margin-bottom:13px}.record p{font-size:14px;color:var(--ash)}.record details{border-top:1px solid var(--line);margin-top:20px;padding-top:12px;font-size:12px}.record summary{cursor:pointer;color:var(--molten);font:11px var(--mono)}.record details p{margin-top:15px;font-size:13px}.record details a{display:block;margin-top:13px}.record-count{font:11px var(--mono);color:var(--ash);margin:20px 0}.evidence-row{display:grid;grid-template-columns:50px minmax(0,1fr) 160px;gap:25px;padding:25px 24px;border-bottom:1px solid var(--line);align-items:start}.evidence-row:last-child{border:0}.evidence-row>.mono{color:var(--ember);font-size:12px}.evidence-row h3{font-size:14px;margin:0 0 9px}.evidence-row p{font-size:13px;color:var(--ash)}.evidence-row .badge{justify-self:end}.evidence-row a{font:11px var(--mono);color:var(--molten);display:inline-block;margin-top:12px}.notice{display:flex;gap:14px;align-items:flex-start;border:1px solid var(--line-2);border-radius:10px;padding:20px 23px;font-size:13px;color:var(--ash);background:var(--row)}.notice .icon{color:var(--molten);width:19px;margin-top:1px}.notice strong{color:var(--ink-2);display:block;margin-bottom:4px;font-weight:500}.wallet-hero{display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:65px}.wallet-card{padding:32px;border:1px solid var(--line-2);border-radius:17px;background:var(--row);position:relative;overflow:hidden}.wallet-card:before{content:'';position:absolute;width:300px;height:180px;right:-100px;top:-100px;background:radial-gradient(ellipse,var(--ember-tint),transparent 65%)}.wallet-card .eyebrow{margin:0}.wallet-balance{font:700 43px var(--display);letter-spacing:-.05em;margin:27px 0 9px}.wallet-balance small{font:15px var(--mono);color:var(--ash)}.wallet-address{display:flex;align-items:center;justify-content:space-between;gap:10px;font:11px var(--mono);padding:13px 15px;border:1px solid var(--line);border-radius:7px;margin-top:25px;color:var(--ash)}.wallet-card .actions{display:grid;grid-template-columns:1fr 1fr}.wallet-card .actions .btn{font:12px var(--sans)}.wallet-history{margin-top:25px}.wallet-history .data-row{font:12px var(--sans);padding:14px 0}.form-panel{max-width:650px;margin:auto;padding:35px}.form-panel h2{font-size:25px;margin-bottom:18px}.form-panel label{display:block;font-size:13px;margin:22px 0 9px;color:var(--ink-2)}.form-panel input,.form-panel select{background:var(--obsidian);border:1px solid var(--line-2);border-radius:7px;padding:14px 15px;color:var(--bone);width:100%;font:12px var(--mono)}.form-panel .btn{width:100%;margin-top:24px}.form-panel .form-status{font-size:13px;color:var(--molten);min-height:24px;margin-top:20px}.form-status.error{color:var(--ember)}.form-note{font-size:12px;color:var(--ash);margin-top:14px}.stepper{display:flex;gap:7px;margin:25px 0}.stepper div{flex:1;border-top:2px solid var(--line);padding-top:9px;font:9px var(--mono);color:var(--ash)}.stepper div.active{color:var(--ember);border-color:var(--ember)}.timeline{position:relative;margin-top:40px}.milestone{display:grid;grid-template-columns:130px 1fr;gap:35px;position:relative;padding-bottom:44px}.milestone:before{content:'';position:absolute;top:12px;bottom:0;left:146px;width:1px;background:var(--line)}.milestone:last-child:before{display:none}.milestone:after{content:'';width:9px;height:9px;border:1px solid var(--line-2);background:var(--obsidian);border-radius:2px;position:absolute;left:142px;top:8px}.milestone.current:after{background:var(--ember);border-color:var(--ember)}.milestone time{font:11px var(--mono);color:var(--ash);padding-top:5px}.milestone h3{font-size:18px;margin-bottom:12px}.milestone p{color:var(--ash);font-size:15px;max-width:75ch}.milestone .badge{margin-bottom:12px}.compare-table td:first-child{font-weight:500}.compare-table th:last-child{color:var(--ember)}.compare-table td{white-space:normal;min-width:180px;vertical-align:top;line-height:1.8;font-size:14px}.compare-table td:last-child{background:var(--ember-tint)}.code{font:12px/1.8 var(--mono);border:1px solid var(--line);border-radius:8px;background:var(--row);padding:19px 22px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;color:var(--ink-2);margin:20px 0}.benchmark-bar{width:120px;height:4px;border-radius:2px;background:var(--line);margin-top:7px;overflow:hidden}.benchmark-bar i{display:block;background:var(--ember);height:100%}.empty-state{padding:50px 25px;text-align:center;color:var(--ash)}.empty-state .icon{width:33px;height:33px;color:var(--ember);margin-bottom:20px}.empty-state h3{color:var(--bone);font-size:17px;margin-bottom:14px}.empty-state p{font-size:14px;max-width:55ch;margin:auto}.dialog{border:1px solid var(--line-2);border-radius:16px;background:var(--graphite);color:var(--bone);padding:0;max-width:660px;width:calc(100% - 32px);max-height:85vh;box-shadow:0 20px 150px #0008}.dialog::backdrop{background:rgba(0,0,0,.65);backdrop-filter:blur(5px)}.dialog .dialog-head{padding:20px 24px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line)}.dialog h2{font-size:17px}.dialog .dialog-body{padding:24px;overflow:auto;max-height:68vh}.dialog .searchbar{margin-bottom:14px}.search-results{display:grid;gap:5px}.search-results a{padding:13px 12px;border-radius:7px;display:flex;justify-content:space-between;font-size:14px;gap:20px}.search-results a:hover{background:var(--row);color:var(--ember)}.search-results a small{font:10px var(--mono);color:var(--ash)}.toast{position:fixed;bottom:27px;left:50%;transform:translate(-50%,20px);z-index:100;max-width:calc(100% - 32px);border:1px solid var(--line-2);background:var(--graphite);border-radius:10px;box-shadow:var(--shadow);padding:14px 22px;font-size:13px;opacity:0;pointer-events:none;transition:.22s}.toast.show{opacity:1;transform:translate(-50%,0)}.review-switch{position:fixed;bottom:20px;right:20px;z-index:25;display:flex;align-items:center;gap:9px;font:10px var(--mono);color:var(--ash);background:var(--glass);padding:10px 13px;border:1px solid var(--line-2);border-radius:7px;backdrop-filter:blur(12px)}.review-switch:hover{color:var(--bone);border-color:var(--ember)}.review-switch .icon{width:14px}.screen-reader{position:absolute;width:1px;height:1px;margin:-1px;clip:rect(0,0,0,0);overflow:hidden}.incoming{animation:incoming .65s ease-out}.page-enter{animation:pageIn .26s ease-out}.reveal{opacity:1}.reveal.will-reveal{opacity:0;transform:translateY(18px);transition:opacity .65s,transform .65s}.reveal.visible{opacity:1;transform:none}@keyframes incoming{0%{background:var(--ember-tint)}100%{background:transparent}}@keyframes pageIn{from{opacity:.4;transform:translateY(6px)}to{opacity:1;transform:none}}.glow-button{position:relative}.glow-button:after{content:'';position:absolute;inset:-4px;border:1px solid var(--ember);border-radius:12px;opacity:0;pointer-events:none}.glow-button:hover:after{animation:btnSignal .7s ease-out}@keyframes btnSignal{from{transform:scale(.96);opacity:.45}to{transform:scale(1.06);opacity:0}} +*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:120px}body{margin:0;background:var(--obsidian);color:var(--bone);font:17px/1.6 var(--sans);font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased}a{color:inherit;text-decoration:none}button,input,select,textarea{font:inherit}button,a,input,summary,select{ -webkit-tap-highlight-color:transparent}button{cursor:pointer}button:disabled{cursor:not-allowed;opacity:.55}button{color:inherit}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible,canvas:focus-visible{outline:2px solid var(--ember);outline-offset:5px}::selection{color:var(--bone);background:var(--ember-tint)}[hidden]{display:none!important}img,svg,canvas{max-width:100%}h1,h2,h3,h4,p{margin:0}h1,h2,h3{font-family:var(--display);text-wrap:balance}h1{font-size:clamp(38px,5.2vw,70px);font-weight:900;line-height:1.12;letter-spacing:-.055em}h2{font-size:clamp(26px,3.05vw,42px);line-height:1.2;letter-spacing:-.035em;font-weight:700}h3{font-size:19px;line-height:1.4;letter-spacing:-.02em;font-weight:700}h4{font-size:17px;font-weight:600}p{text-wrap:pretty}p+p{margin-top:15px}.container{max-width:var(--max);margin:auto;padding:0 36px}.section{padding:100px 0}.section.compact{padding:64px 0}.muted{color:var(--ash)}.accent{color:var(--ember)}.molten{color:var(--molten)}.mono{font-family:var(--mono)}.eyebrow{display:flex;align-items:center;gap:10px;font:500 11px/1.7 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ash);margin-bottom:20px}.eyebrow .line{display:inline-block;width:24px;height:1px;background:var(--ember)}.eyebrow em{font-style:normal;color:var(--ember)}.lead{font-size:19px;line-height:1.65;color:var(--ink-2);max-width:53ch;margin-top:24px}.small{font-size:13px;color:var(--ash)}.rule{border-top:1px solid var(--line)}.pill{display:inline-flex;align-items:center;gap:8px;font:500 10px/1.4 var(--mono);letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--line-2);padding:7px 10px;border-radius:5px;white-space:nowrap}.pill.warm{color:var(--molten);border-color:color-mix(in srgb,var(--molten) 28%,transparent);background:color-mix(in srgb,var(--molten) 6%,transparent)}.dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--molten)}.icon{display:inline-block;width:20px;height:20px;vertical-align:middle;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.btn{display:inline-flex;align-items:center;justify-content:center;gap:14px;min-height:48px;border:1px solid var(--line-2);background:var(--graphite);border-radius:8px;padding:13px 20px;font:700 12px/1.4 var(--display);letter-spacing:-.01em;transition:transform .2s,background .2s,border-color .2s}.btn:hover{border-color:var(--ash);transform:translateY(-2px)}.btn.primary{background:var(--ember);border-color:var(--ember);color:var(--ember-ink)}.btn.primary:hover{background:var(--ember-hi);border-color:var(--ember-hi)}.btn.ghost{background:transparent}.btn.small-btn{font:500 12px var(--sans);min-height:38px;padding:9px 12px}.btn.icon-btn{width:40px;height:40px;min-height:40px;padding:10px;border-color:transparent;background:transparent}.btn.icon-btn:hover{background:var(--graphite);border-color:var(--line)}.actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:30px}.text-link{display:inline-flex;align-items:center;gap:10px;color:var(--ink-2);font-size:14px;font-weight:500}.text-link:hover{color:var(--ember)}.text-link .icon{width:16px;height:16px}.skip{position:fixed;left:20px;top:-100px;z-index:100;background:var(--ember);color:var(--ember-ink);padding:12px}.skip:focus{top:15px}.statusbar{height:33px;border-bottom:1px solid var(--line);font:10px var(--mono);color:var(--ash);letter-spacing:.04em}.statusbar .container{height:100%;display:flex;align-items:center;justify-content:space-between;gap:15px}.statusbar .dev-label{color:var(--molten);margin-right:15px}.site-header,.nav{position:sticky;top:0;z-index:30;background:var(--glass);border-bottom:1px solid var(--line);backdrop-filter:blur(16px)}.nav-row{height:80px;display:flex;align-items:center;gap:36px}.logo{display:inline-flex;align-items:center;gap:10px;font:900 20px/1 var(--display);letter-spacing:.055em;flex-shrink:0}.logo .brand-mark{width:36px;height:36px;display:block}.logo .stop{color:#F2541B}.logo .word{font:inherit}.nav-links,.nav .links{display:flex;gap:27px;align-items:center;flex:1;justify-content:center}.nav-links>a,.nav .links>a,.nav-dropdown>summary{font-size:13px;color:var(--ink-2);white-space:nowrap}.nav-links>a:hover,.nav-links>a[aria-current=page],.nav .links>a:hover,.nav .links>a[aria-current=page]{color:var(--ember)}.nav-dropdown{position:relative}.nav-dropdown>summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:7px}.nav-dropdown>summary::-webkit-details-marker{display:none}.nav-dropdown .icon{width:12px}.dropdown-body{position:absolute;top:34px;right:-55px;width:540px;padding:22px;background:var(--graphite);border:1px solid var(--line-2);border-radius:14px;box-shadow:var(--shadow);display:grid;grid-template-columns:1fr 1fr;gap:4px}.dropdown-body a{font-size:14px;padding:10px 12px;border-radius:6px}.dropdown-body a:hover{background:var(--row);color:var(--ember)}.dropdown-body a small{display:block;color:var(--ash);font-size:11px;font-family:var(--mono);margin-top:3px}.nav-controls{display:flex;align-items:center;gap:7px}.nav-controls .btn.primary,.nav .cta{font-size:11px;min-height:40px;padding:11px 15px}.mobile-toggle,.burger{display:none}.mobile-nav,.nav-sheet{padding:16px 25px 25px;border-top:1px solid var(--line);max-height:70vh;overflow:auto;grid-template-columns:1fr 1fr;gap:5px}.mobile-nav a,.nav-sheet a{padding:9px 5px;font-size:14px}.mobile-nav:not([hidden]),.nav.open .nav-sheet{display:grid}.hero{padding:76px 0 57px;overflow:hidden}.hero-grid{display:grid;grid-template-columns:1.1fr 1fr;align-items:center;gap:12px;min-height:510px}.hero-copy{position:relative;z-index:1;padding-bottom:16px}.hero-copy h1 .accent{display:inline-block}.hero-copy .lead{max-width:43ch}.hero-footnote{display:flex;align-items:center;gap:9px;margin-top:20px;font:10px/1.6 var(--mono);color:var(--ash)}.hero-footnote .icon{width:14px}.hero-scene{height:500px;position:relative;margin-right:-20px;isolation:isolate}.hero-scene:before{content:'';position:absolute;inset:20px -50px 0;background:radial-gradient(ellipse at 58% 48%,rgba(242,84,27,.075),transparent 65%);z-index:-1}.hero-scene canvas{display:block;width:100%;height:100%}.scene-corner{position:absolute;font:10px/1.5 var(--mono);color:var(--ash);letter-spacing:.05em;pointer-events:none}.scene-corner.tl{left:15px;top:22px}.scene-corner.tr{right:24px;top:22px;text-align:right}.scene-corner.bl{left:15px;bottom:84px}.scene-corner.br{right:24px;bottom:30px;text-align:right;max-width:calc(50% - 130px)}.scene-corner strong{display:block;color:var(--ink-2);font-weight:500;margin-bottom:4px}.scene-steps{position:absolute;left:50%;bottom:30px;transform:translateX(-50%);display:flex;gap:5px;border:1px solid var(--line);padding:5px;border-radius:10px;background:var(--glass)}.scene-step{background:transparent;border:0;color:var(--ash);font:11px var(--mono);padding:9px 13px;border-radius:6px;white-space:nowrap}.scene-step[aria-pressed=true]{background:var(--ember-tint);color:var(--ember)}.scene-step:hover{color:var(--bone)}.hero-bottom{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);padding-top:25px;margin-top:26px;gap:28px}.principle{display:flex;gap:13px;align-items:flex-start}.principle .icon{color:var(--ember);width:17px;margin-top:2px}.principle strong{font-size:13px;font-weight:500;display:block}.principle small{font-size:11px;color:var(--ash);display:block;margin-top:4px}.section-head{display:flex;justify-content:space-between;align-items:flex-end;gap:30px;margin-bottom:36px}.section-head h2{max-width:20ch}.section-head>p{color:var(--ash);max-width:40ch;font-size:16px}.section-head .eyebrow{margin-bottom:12px}.panel{background:var(--row);border:1px solid var(--line);border-radius:16px;overflow:hidden}.panel-head{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:21px 25px;border-bottom:1px solid var(--line)}.panel-head .eyebrow{margin:0}.panel-controls{display:flex;gap:6px;align-items:center;flex-wrap:wrap}.panel-footer{display:flex;align-items:center;justify-content:space-between;padding:17px 25px;gap:12px;border-top:1px solid var(--line);font:10px/1.7 var(--mono);color:var(--ash)}.live-peek{position:relative}.live-peek canvas{display:block;height:280px;width:100%}.legend{display:flex;gap:17px;align-items:center;flex-wrap:wrap;font:10px var(--mono);color:var(--ash)}.legend i{display:inline-block;width:6px;height:6px;background:var(--ember);margin-right:6px}.legend .your{background:var(--molten)}.legend .included{background:var(--included)}.legend .excluded{background:var(--excluded)}.label-below{font-size:12px;color:var(--ash);margin-top:14px;display:flex;justify-content:space-between;gap:20px}.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:22px}.feature{position:relative;padding:30px 29px;background:var(--row);border:1px solid var(--line);border-radius:14px;overflow:hidden}.feature:after{content:'';position:absolute;width:75px;height:1px;top:0;left:29px;background:var(--ember);opacity:.7}.feature .number{font:11px var(--mono);color:var(--ember);margin-bottom:30px;display:flex;align-items:center;justify-content:space-between}.feature .number .icon{width:24px;height:24px;color:var(--ash)}.feature h3{margin-bottom:15px}.feature p{color:var(--ash);font-size:15px}.feature .text-link{margin-top:28px}.feature-graphic{height:120px;width:100%;margin:15px 0;display:flex;align-items:center;justify-content:center}.chip-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:5px;width:100%;max-width:260px;transform:perspective(400px) rotateX(30deg) rotateZ(-7deg)}.chip-grid i{display:block;height:10px;border:1px solid var(--line-2);border-radius:2px}.chip-grid i:nth-child(3n),.chip-grid i:nth-child(7n){background:var(--ember-tint);border-color:color-mix(in srgb,var(--ember) 50%,var(--line))}.split-section{display:grid;grid-template-columns:1fr 1fr;gap:100px;align-items:center}.split-section .lead{font-size:17px}.split-section h2{max-width:19ch}.reward-bars{padding:32px}.reward-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}.reward-row strong{font:700 38px var(--display);letter-spacing:-.04em}.reward-bar{height:12px;background:var(--graphite);display:flex;border-radius:3px;overflow:hidden;gap:3px;margin:24px 0}.reward-bar i:first-child{width:80%;background:var(--ember)}.reward-bar i:last-child{width:20%;background:var(--molten)}.reward-key{display:flex;justify-content:space-between;gap:25px;margin-top:26px;font-size:13px}.reward-key strong{display:block;margin-bottom:5px}.reward-key span{color:var(--ash)}.reward-note{margin-top:27px;border-top:1px solid var(--line);padding-top:20px;font:10px/1.8 var(--mono);color:var(--ash)}.mini-title{font:500 11px var(--mono);letter-spacing:.1em;text-transform:uppercase}.tag-row{display:flex;gap:8px;flex-wrap:wrap;margin-top:24px}.cta-band{position:relative;padding:58px;border:1px solid color-mix(in srgb,var(--ember) 35%,var(--line));border-radius:16px;background:linear-gradient(120deg,var(--ember-tint),transparent 70%);display:flex;align-items:center;justify-content:space-between;gap:40px;overflow:hidden}.cta-band h2{max-width:20ch}.cta-band p{color:var(--ash);font-size:15px;margin-top:15px;max-width:50ch}.cta-band .actions{margin:0;flex-shrink:0}.site-footer{padding:64px 0 25px;border-top:1px solid var(--line)}.footer-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:50px}.footer-brand p{font-size:13px;color:var(--ash);margin:21px 0}.footer-column h4{font:500 10px var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ash);margin-bottom:20px}.footer-column a{display:block;font-size:13px;margin:10px 0;color:var(--ink-2)}.footer-column a:hover{color:var(--ember)}.footer-bottom{margin-top:54px;border-top:1px solid var(--line);padding-top:22px;display:flex;justify-content:space-between;gap:20px;font:10px/1.8 var(--mono);color:var(--ash)}.footer-bottom p{max-width:82ch}.theme-group{display:flex;align-items:center;gap:3px;border:1px solid var(--line);padding:3px;border-radius:6px;align-self:flex-start}.theme-group button{background:none;border:0;border-radius:3px;font:10px var(--mono);padding:7px 10px;color:var(--ash)}.theme-group button[aria-pressed=true]{background:var(--graphite);color:var(--bone)}.page-hero{padding:65px 0 45px}.page-hero h1{font-size:clamp(36px,4.2vw,56px);max-width:22ch}.page-hero .lead{max-width:67ch;font-size:18px}.breadcrumb{font:10px var(--mono);color:var(--ash);margin-bottom:28px;display:flex;gap:12px}.breadcrumb a:hover{color:var(--ember)}.page-heading{display:flex;justify-content:space-between;align-items:flex-end;gap:40px}.page-heading .actions{margin:0}.tabs{display:flex;gap:5px;border-bottom:1px solid var(--line);margin-top:24px;overflow-x:auto;scrollbar-width:thin}.tabs button,.tabs a{background:none;border:0;border-bottom:2px solid transparent;padding:14px 17px;color:var(--ash);font:500 13px var(--sans);white-space:nowrap}.tabs [aria-selected=true],.tabs [aria-current=page]{border-bottom-color:var(--ember);color:var(--bone)}.tabs button:hover{color:var(--bone)}.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-bottom:24px;background:var(--row)}.stat{padding:22px 25px;border-right:1px solid var(--line)}.stat:last-child{border-right:0}.stat .key{font:10px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--ash);margin-bottom:11px}.stat strong{font:700 clamp(21px,2.2vw,29px) var(--display);letter-spacing:-.04em}.stat .small{font-size:10px;font-family:var(--mono);margin-top:8px}.console-layout{display:grid;grid-template-columns:minmax(0,1fr) 295px;gap:18px}.dag-panel{position:relative}.dag-panel canvas{height:420px;display:block;width:100%;touch-action:pan-y}.dag-tip{position:absolute;left:0;top:65px;pointer-events:none;z-index:4;max-width:280px;overflow-wrap:anywhere;white-space:pre-line;border:1px solid var(--line-2);padding:11px 13px;background:var(--graphite);border-radius:8px;box-shadow:var(--shadow);font:10px/1.8 var(--mono)}.dag-tip b,.dag-tip span{display:block}.inspector{padding:22px}.inspector .eyebrow{font-size:10px;margin:0}.inspector canvas{width:100%;height:200px;display:block}.inspector h3{font-size:13px;word-break:break-all;margin-bottom:17px}.data-row{display:flex;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--line);font:11px var(--mono)}.data-row:last-child{border:0}.data-row span{color:var(--ash)}.data-row strong{font-weight:500;text-align:right}.shards{display:flex;gap:6px;margin:18px 0}.shard{flex:1;min-width:0;border:1px solid var(--line-2);border-radius:4px;padding:10px 0;text-align:center;font:9px var(--mono);color:var(--ash);background:var(--graphite)}.shard[data-state=verified]{border-color:var(--ember);color:var(--ember)}.shard[data-state=paid]{border-color:var(--molten);color:var(--molten)}.shard[data-state=proving]{background:var(--ember-tint);border-color:var(--ember);color:var(--ember)}.demo-controls{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:17px 0;color:var(--ash);font-size:12px}.demo-controls>div{display:flex;gap:7px;flex-wrap:wrap}.demo-controls .btn{font-family:var(--mono);font-size:10px;min-height:35px;padding:8px 11px}.tables-row{margin-top:25px}.table-wrap{overflow-x:auto;max-width:100%;border:1px solid var(--line);border-radius:12px;background:var(--row)}table{border-collapse:collapse;width:100%;text-align:left;font-size:13px}caption{text-align:left;padding:20px 22px;color:var(--ash);font:10px var(--mono);letter-spacing:.12em;text-transform:uppercase}th{font:500 10px/1.6 var(--mono);text-transform:uppercase;letter-spacing:.08em;color:var(--ash);padding:13px 22px;border-bottom:1px solid var(--line);white-space:nowrap}td{padding:15px 22px;border-bottom:1px solid var(--line);white-space:nowrap}tr:last-child td{border:0}tbody tr:hover{background:var(--graphite)}.table-button{border:0;background:none;color:var(--molten);padding:0;font:12px var(--mono);text-align:left}.table-button:hover{text-decoration:underline}.small-caption{font-size:12px;color:var(--ash);padding:13px 0}.badge{display:inline-block;padding:4px 7px;border:1px solid var(--line-2);border-radius:4px;font:10px var(--mono);color:var(--ink-2);white-space:nowrap}.badge.warm{border-color:color-mix(in srgb,var(--ember) 40%,transparent);color:var(--ember)}.badge.gold{border-color:color-mix(in srgb,var(--molten) 40%,transparent);color:var(--molten)}.events{padding:8px 21px}.event{display:flex;gap:15px;padding:15px 0;border-bottom:1px solid var(--line);align-items:flex-start;font-size:12px}.event:last-child{border:0}.event .icon{color:var(--ember);width:15px}.event p{line-height:1.5}.event time{display:block;font:9px var(--mono);color:var(--ash);margin-top:5px}.event-tag{font:9px var(--mono);margin-left:auto;color:var(--ash);white-space:nowrap}.source-note{font:10px/1.8 var(--mono);color:var(--ash);margin-top:22px;padding-left:12px;border-left:2px solid var(--line-2)}.source-note a{color:var(--ink-2);text-decoration:underline;text-underline-offset:3px}.source-note a:hover{color:var(--ember)}.download-layout{display:grid;grid-template-columns:1.1fr 1fr;gap:52px;align-items:center} +/* the miner's meet section (7 October 2026): the app window carries the section, so it takes the content width under its copy */ +#meet .download-layout{grid-template-columns:1fr;gap:var(--s-5);align-items:start}.app-window{border:1px solid var(--line-2);border-radius:15px;background:var(--row);box-shadow:var(--shadow);overflow:hidden}.window-top{height:43px;border-bottom:1px solid var(--line);display:flex;align-items:center;padding:0 17px;gap:5px;font:10px var(--mono);color:var(--ash)}.window-top i{width:6px;height:6px;background:var(--line-2);border-radius:50%}.window-top span{margin-left:auto;margin-right:auto}.app-inner{display:grid;grid-template-columns:100px 1fr;min-height:370px}.app-sidebar{padding:17px 11px;border-right:1px solid var(--line);font:10px var(--mono);color:var(--ash)}.app-sidebar div{padding:9px 7px;margin-bottom:4px}.app-sidebar div.on{color:var(--ember);background:var(--ember-tint);border-radius:4px}.app-content{padding:22px;min-width:0}.app-content .app-greeting{display:flex;justify-content:space-between;align-items:center;margin-bottom:22px}.app-content .app-greeting strong{font:700 14px var(--display)}.app-content .app-greeting .pill{font-size:8px;padding:5px}.app-stats{display:grid;grid-template-columns:1fr 1fr;gap:10px}.app-stat{border:1px solid var(--line);border-radius:7px;padding:12px}.app-stat span{display:block;font:9px var(--mono);color:var(--ash);margin-bottom:8px}.app-stat strong{font:700 20px var(--display)}.app-content canvas{width:100%;height:145px;display:block}.app-bar{display:flex;justify-content:space-between;font:9px var(--mono);border:1px solid var(--line);padding:11px;border-radius:6px}.app-bar b{color:var(--molten);font-weight:400}.download-card{padding:27px}.download-card .tabs{margin-top:0}.download-card .tabs button{padding:12px 15px;flex:1}.platform-body{padding-top:24px}.platform-body .platform-title{display:flex;align-items:center;gap:15px;margin:10px 0 15px}.platform-title .icon{width:28px;height:28px}.platform-body h3{font-size:18px}.platform-body p{font-size:14px;color:var(--ash)}.platform-body .btn{width:100%;margin-top:26px}.download-detail{display:flex;justify-content:space-between;gap:15px;font:10px var(--mono);margin-top:15px;color:var(--ash)}.step-list{display:grid;gap:0}.step-item{display:grid;grid-template-columns:44px 1fr;gap:20px;padding:28px 0;border-top:1px solid var(--line)}.step-item .step-index{font:700 14px var(--display);color:var(--ember);border:1px solid var(--line-2);height:38px;width:38px;display:grid;place-items:center;border-radius:8px}.step-item h3{font-size:16px;margin-bottom:9px}.step-item p{font-size:15px;color:var(--ash)}.faq details{border-bottom:1px solid var(--line)}.faq summary{font-size:16px;font-weight:500;list-style:none;cursor:pointer;display:flex;justify-content:space-between;gap:20px;padding:21px 0}.faq summary:after{content:'+';color:var(--ash);font:20px var(--mono)}.faq details[open] summary:after{content:'-';color:var(--ember)}.faq details p{padding-bottom:24px;color:var(--ash);font-size:15px;max-width:85ch}.faq details a{color:var(--ember)}.tools-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}.tool-card{border:1px solid var(--line);border-radius:14px;padding:25px;transition:border-color .2s,transform .2s;background:var(--row)}.tool-card:hover{border-color:var(--line-2);transform:translateY(-3px)}.tool-card .icon{color:var(--ember);width:26px;height:26px;margin-bottom:22px}.tool-card h3{font-size:16px;margin-bottom:12px}.tool-card p{color:var(--ash);font-size:14px}.tool-card .text-link{margin-top:22px}.docs-layout{display:grid;grid-template-columns:230px minmax(0,1fr);gap:55px;align-items:start}.doc-nav{position:sticky;top:112px;max-height:calc(100vh - 145px);overflow:auto;border-right:1px solid var(--line);padding-right:20px;scrollbar-width:thin}.doc-nav .eyebrow{margin-bottom:17px;font-size:10px}.doc-nav a{display:block;font-size:12px;color:var(--ash);padding:8px 10px;border-left:2px solid transparent}.doc-nav a:hover,.doc-nav a.active{color:var(--ember);background:var(--ember-tint);border-left-color:var(--ember)}.doc-body{max-width:810px;min-width:0}.doc-section{padding-bottom:42px;margin-bottom:42px;border-bottom:1px solid var(--line);scroll-margin-top:110px}.doc-section h2{font-size:27px;margin:0 0 22px}.doc-section h3{font-size:16px;margin:26px 0 13px}.doc-section p{color:var(--ink-2);font-size:16px;line-height:1.85}.doc-section .section-number{font:11px var(--mono);color:var(--ember);margin-bottom:13px}.doc-section li{color:var(--ink-2);font-size:15px;margin:9px 0}.doc-section .table-wrap{margin:25px 0}.doc-section td{white-space:normal;min-width:140px;font-size:13px}.doc-notice{background:var(--ember-tint);border:1px solid color-mix(in srgb,var(--ember) 25%,var(--line));border-radius:10px;padding:20px 24px;margin-bottom:35px;font-size:13px;color:var(--ink-2)}.doc-notice strong{display:block;color:var(--molten);margin-bottom:6px;font-weight:500}.doc-notice a{color:var(--ember);text-decoration:underline;text-underline-offset:3px}.searchbar{position:relative;display:flex;align-items:center;gap:12px;padding:12px 16px;border:1px solid var(--line-2);border-radius:8px;background:var(--row)}.searchbar .icon{width:17px;color:var(--ash)}.searchbar input{flex:1;min-width:0;border:0;outline:none;background:transparent;color:var(--bone);font-size:14px}.searchbar input::placeholder{color:var(--ash)}.filter-row{display:flex;gap:8px;flex-wrap:wrap;margin:22px 0}.filter{background:none;border:1px solid var(--line);border-radius:6px;padding:8px 13px;font:11px var(--mono);color:var(--ash)}.filter[aria-pressed=true]{border-color:var(--ember);color:var(--ember);background:var(--ember-tint)}.filter:hover{color:var(--bone)}.record-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}.record{background:var(--row);border:1px solid var(--line);border-radius:12px;padding:25px}.record .record-top{display:flex;justify-content:space-between;gap:15px;align-items:center;margin-bottom:20px}.record time{font:10px var(--mono);color:var(--ash)}.record h3{font-size:16px;max-width:35ch;line-height:1.5;margin-bottom:13px}.record p{font-size:14px;color:var(--ash)}.record details{border-top:1px solid var(--line);margin-top:20px;padding-top:12px;font-size:12px}.record summary{cursor:pointer;color:var(--molten);font:11px var(--mono)}.record details p{margin-top:15px;font-size:13px}.record details a{display:block;margin-top:13px}.record-count{font:11px var(--mono);color:var(--ash);margin:20px 0}.evidence-row{display:grid;grid-template-columns:50px minmax(0,1fr) 160px;gap:25px;padding:25px 24px;border-bottom:1px solid var(--line);align-items:start}.evidence-row:last-child{border:0}.evidence-row>.mono{color:var(--ember);font-size:12px}.evidence-row h3{font-size:14px;margin:0 0 9px}.evidence-row p{font-size:13px;color:var(--ash)}.evidence-row .badge{justify-self:end}.evidence-row a{font:11px var(--mono);color:var(--molten);display:inline-block;margin-top:12px}.notice{display:flex;gap:14px;align-items:flex-start;border:1px solid var(--line-2);border-radius:10px;padding:20px 23px;font-size:13px;color:var(--ash);background:var(--row)}.notice .icon{color:var(--molten);width:19px;margin-top:1px}.notice strong{color:var(--ink-2);display:block;margin-bottom:4px;font-weight:500}.wallet-hero{display:grid;grid-template-columns:1fr;align-items:start;gap:var(--s-5)}.wallet-card{padding:32px;border:1px solid var(--line-2);border-radius:17px;background:var(--row);position:relative;overflow:hidden}.wallet-card:before{content:'';position:absolute;width:300px;height:180px;right:-100px;top:-100px;background:radial-gradient(ellipse,var(--ember-tint),transparent 65%)}.wallet-card .eyebrow{margin:0}.wallet-balance{font:700 43px var(--display);letter-spacing:-.05em;margin:27px 0 9px}.wallet-balance small{font:15px var(--mono);color:var(--ash)}.wallet-address{display:flex;align-items:center;justify-content:space-between;gap:10px;font:11px var(--mono);padding:13px 15px;border:1px solid var(--line);border-radius:7px;margin-top:25px;color:var(--ash)}.wallet-card .actions{display:grid;grid-template-columns:1fr 1fr}.wallet-card .actions .btn{font:12px var(--sans)}.wallet-history{margin-top:25px}.wallet-history .data-row{font:12px var(--sans);padding:14px 0}.form-panel{max-width:650px;margin:auto;padding:35px}.form-panel h2{font-size:25px;margin-bottom:18px}.form-panel label{display:block;font-size:13px;margin:22px 0 9px;color:var(--ink-2)}.form-panel input,.form-panel select{background:var(--obsidian);border:1px solid var(--line-2);border-radius:7px;padding:14px 15px;color:var(--bone);width:100%;font:12px var(--mono)}.form-panel .btn{width:100%;margin-top:24px}.form-panel .form-status{font-size:13px;color:var(--molten);min-height:24px;margin-top:20px}.form-status.error{color:var(--ember)}.form-note{font-size:12px;color:var(--ash);margin-top:14px}.stepper{display:flex;gap:7px;margin:25px 0}.stepper div{flex:1;border-top:2px solid var(--line);padding-top:9px;font:9px var(--mono);color:var(--ash)}.stepper div.active{color:var(--ember);border-color:var(--ember)}.timeline{position:relative;margin-top:40px}.milestone{display:grid;grid-template-columns:130px 1fr;gap:35px;position:relative;padding-bottom:44px}.milestone:before{content:'';position:absolute;top:12px;bottom:0;left:146px;width:1px;background:var(--line)}.milestone:last-child:before{display:none}.milestone:after{content:'';width:9px;height:9px;border:1px solid var(--line-2);background:var(--obsidian);border-radius:2px;position:absolute;left:142px;top:8px}.milestone.current:after{background:var(--ember);border-color:var(--ember)}.milestone time{font:11px var(--mono);color:var(--ash);padding-top:5px}.milestone h3{font-size:18px;margin-bottom:12px}.milestone p{color:var(--ash);font-size:15px;max-width:75ch}.milestone .badge{margin-bottom:12px}.compare-table td:first-child{font-weight:500}.compare-table th:last-child{color:var(--ember)}.compare-table td{white-space:normal;min-width:180px;vertical-align:top;line-height:1.8;font-size:14px}.compare-table td:last-child{background:var(--ember-tint)}.code{font:12px/1.8 var(--mono);border:1px solid var(--line);border-radius:8px;background:var(--row);padding:19px 22px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;color:var(--ink-2);margin:20px 0}.benchmark-bar{width:120px;height:4px;border-radius:2px;background:var(--line);margin-top:7px;overflow:hidden}.benchmark-bar i{display:block;background:var(--ember);height:100%}.empty-state{padding:50px 25px;text-align:center;color:var(--ash)}.empty-state .icon{width:33px;height:33px;color:var(--ember);margin-bottom:20px}.empty-state h3{color:var(--bone);font-size:17px;margin-bottom:14px}.empty-state p{font-size:14px;max-width:55ch;margin:auto}.dialog{border:1px solid var(--line-2);border-radius:16px;background:var(--graphite);color:var(--bone);padding:0;max-width:660px;width:calc(100% - 32px);max-height:85vh;box-shadow:0 20px 150px #0008}.dialog::backdrop{background:rgba(0,0,0,.65);backdrop-filter:blur(5px)}.dialog .dialog-head{padding:20px 24px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line)}.dialog h2{font-size:17px}.dialog .dialog-body{padding:24px;overflow:auto;max-height:68vh}.dialog .searchbar{margin-bottom:14px}.search-results{display:grid;gap:5px}.search-results a{padding:13px 12px;border-radius:7px;display:flex;justify-content:space-between;font-size:14px;gap:20px}.search-results a:hover{background:var(--row);color:var(--ember)}.search-results a small{font:10px var(--mono);color:var(--ash)}.toast{position:fixed;bottom:27px;left:50%;transform:translate(-50%,20px);z-index:100;max-width:calc(100% - 32px);border:1px solid var(--line-2);background:var(--graphite);border-radius:10px;box-shadow:var(--shadow);padding:14px 22px;font-size:13px;opacity:0;pointer-events:none;transition:.22s}.toast.show{opacity:1;transform:translate(-50%,0)}.review-switch{position:fixed;bottom:20px;right:20px;z-index:25;display:flex;align-items:center;gap:9px;font:10px var(--mono);color:var(--ash);background:var(--glass);padding:10px 13px;border:1px solid var(--line-2);border-radius:7px;backdrop-filter:blur(12px)}.review-switch:hover{color:var(--bone);border-color:var(--ember)}.review-switch .icon{width:14px}.screen-reader{position:absolute;width:1px;height:1px;margin:-1px;clip:rect(0,0,0,0);overflow:hidden}.incoming{animation:incoming .65s ease-out}.page-enter{animation:pageIn .26s ease-out}.reveal{opacity:1}.reveal.will-reveal{opacity:0;transform:translateY(18px);transition:opacity .65s,transform .65s}.reveal.visible{opacity:1;transform:none}@keyframes incoming{0%{background:var(--ember-tint)}100%{background:transparent}}@keyframes pageIn{from{opacity:.4;transform:translateY(6px)}to{opacity:1;transform:none}}.glow-button{position:relative}.glow-button:after{content:'';position:absolute;inset:-4px;border:1px solid var(--ember);border-radius:12px;opacity:0;pointer-events:none}.glow-button:hover:after{animation:btnSignal .7s ease-out}@keyframes btnSignal{from{transform:scale(.96);opacity:.45}to{transform:scale(1.06);opacity:0}} @media(min-width:1600px){:root{--max:1390px}.hero-grid{gap:45px}.hero-scene{height:540px}.hero h1{font-size:76px}} @media(max-width:1100px){.nav-links,.nav .links{gap:19px}.nav-row{gap:18px}.container{padding:0 28px}.hero-grid{gap:0;grid-template-columns:1.06fr 1fr}.hero-scene{height:420px;margin-right:-15px}.hero-copy h1{font-size:clamp(42px,5.25vw,61px)}.hero .lead{font-size:17px}.split-section{gap:50px}.download-layout{gap:30px}.footer-grid{gap:25px}.console-layout{grid-template-columns:minmax(0,1fr) 270px}.docs-layout{grid-template-columns:195px minmax(0,1fr);gap:35px}.app-sidebar{font-size:9px}.app-inner{grid-template-columns:85px 1fr}.app-content{padding:18px}.wallet-hero{gap:35px}} @media(max-width:860px){.nav-links,.nav .links{display:none}.nav-row{height:68px}.nav-controls{margin-left:auto}.mobile-toggle,.burger{display:inline-flex!important}.hero{padding-top:50px}.hero-grid{grid-template-columns:1fr;min-height:0}.hero-copy{max-width:640px}.hero-copy h1{font-size:clamp(44px,7.9vw,68px);max-width:16ch}.hero-scene{max-width:660px;width:100%;height:440px;margin:0 auto}.hero-bottom{grid-template-columns:1fr 1fr;gap:23px;margin-top:8px}.section{padding:70px 0}.grid-3,.tools-grid{grid-template-columns:1fr 1fr}.grid-3>.feature:last-child{grid-column:1/-1}.split-section{grid-template-columns:1fr;gap:35px}.split-section h2{max-width:26ch}.section-head{align-items:flex-start}.section-head>p{max-width:30ch}.console-layout{grid-template-columns:1fr}.inspector{display:grid;grid-template-columns:200px 1fr;column-gap:25px}.inspector>.eyebrow{grid-column:1/-1}.inspector canvas{grid-row:2/7}.inspector h3{margin:17px 0 8px}.inspector .small{grid-column:1/-1}.inspector .shards{grid-column:2}.stat{padding:18px}.stat .key{font-size:9px}.stat-grid{grid-template-columns:repeat(4,1fr)}.stat strong{font-size:21px}.download-layout,.wallet-hero{grid-template-columns:1fr}.download-layout>.app-window{max-width:620px;margin:auto;width:100%}.footer-grid{grid-template-columns:1.2fr 1fr 1fr;gap:30px}.footer-brand{grid-column:1/-1}.footer-brand p{margin:12px 0}.cta-band{padding:37px;flex-direction:column;align-items:flex-start;gap:25px}.page-heading{align-items:flex-start;flex-direction:column;gap:20px}.page-heading .actions{margin:0}.docs-layout{grid-template-columns:1fr}.doc-nav{position:relative;top:0;max-height:190px;border:1px solid var(--line);border-radius:9px;padding:18px;display:grid;grid-template-columns:1fr 1fr}.doc-nav .eyebrow{grid-column:1/-1}.record-grid{gap:12px}.evidence-row{grid-template-columns:27px 1fr 135px;gap:14px}.page-hero{padding-top:40px}.wallet-card{max-width:580px;width:100%;margin:auto}.review-switch{font-size:9px;bottom:12px;right:12px}} @@ -164,7 +166,7 @@ input:focus,select:focus,textarea:focus{border-color:var(--line-2)} .phero{position:relative;padding:calc(var(--s-6) + 16px) 0 var(--s-6);overflow:hidden} .phero::before{content:"";position:absolute;inset:auto -10% -30% 40%;height:70%;background:radial-gradient(closest-side,var(--ember-12),transparent);pointer-events:none} .phero .wrap{position:relative;display:grid;gap:var(--s-6);grid-template-columns:1fr;align-items:center} -@media (min-width:980px){.phero .wrap{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);gap:var(--s-6) 56px}} +@media (min-width:980px){.phero .wrap{grid-template-columns:1fr;gap:var(--s-5)} /* 7 October 2026: the page hero's shot carries the page, so it takes the content width under its copy */} .phero h1{margin:0 0 var(--s-4)} .phero .lead{margin:0 0 var(--s-5)} .phero .os{display:flex;flex-wrap:wrap;gap:6px 16px;font:400 var(--t-sm)/1.4 var(--f-mono);color:var(--ash);margin-top:var(--s-4)} @@ -179,8 +181,7 @@ input:focus,select:focus,textarea:focus{border-color:var(--line-2)} :root[data-theme="light"] .frame .img-dark,:root[data-theme="light"] .frame .cap-dark{display:none}:root[data-theme="light"] .frame .img-light{display:block}:root[data-theme="light"] .frame .cap-light{display:inline} .glow{position:relative} .glow::before{content:"";position:absolute;inset:12% -6% -8% -6%;background:radial-gradient(closest-side,var(--ember-12),transparent);filter:blur(12px);pointer-events:none} -.shots3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-4)} -@media (max-width:900px){.shots3{grid-template-columns:1fr}} +.shots3{display:grid;grid-template-columns:1fr;gap:var(--s-5)} .dl-list{display:flex;flex-direction:column;gap:var(--s-2);margin:var(--s-4) 0} .dl-list a{display:flex;justify-content:space-between;align-items:center;gap:var(--s-3);padding:12px 16px;border:1px solid var(--line);border-radius:var(--r-row);background:var(--graphite);color:var(--bone);font-weight:600;min-width:0} .dl-list a:hover{text-decoration:none;border-color:var(--line-2);background:var(--hover)} @@ -200,8 +201,11 @@ p.notice{display:block;margin:14px 0 0;font-size:13px;line-height:1.7} .lines.c2{grid-template-columns:repeat(2,minmax(0,1fr))} .lines.c4{grid-template-columns:repeat(4,minmax(0,1fr))} @media (max-width:900px){.lines,.lines.c2,.lines.c4{grid-template-columns:1fr}} -.feat-row{display:grid;grid-template-columns:1fr;gap:var(--s-5);align-items:center} -@media (min-width:980px){.feat-row{grid-template-columns:minmax(0,1.2fr) minmax(0,.8fr)}.feat-row.flip>.frame{order:2}} +/* the screenshot rows (7 October 2026, the shots read narrow): a shot that carries a page sits on its own row at the content's + full width with its text as the lead above it; two-up only where both shots would be 600 px or wider, which no breakpoint of + this site gives, so the rows stack at every width and the phone stacks them too */ +.feat-row{display:grid;grid-template-columns:1fr;gap:var(--s-4);align-items:start} +.feat-row>.frame{order:2} .feat-row h2{margin-bottom:var(--s-3)} .feat-row>div>p{color:var(--ink-2)} .feat-row .lines{grid-template-columns:1fr;margin-top:var(--s-4)} diff --git a/site/wallet.html b/site/wallet.html index ff8f8be21..d92bbe0ca 100644 --- a/site/wallet.html +++ b/site/wallet.html @@ -253,7 +253,7 @@
in a block
Chain block 8

A block carries it and the chain’s height passed it. It can still be reorganised until a checkpoint covers it.

final · cp 5
Under a verified checkpoint

Its block sits under a 30-second checkpoint whose certificate this wallet verified: the voter list, the aggregate BLS signature, two thirds of all weight.

-
+
History
The wallet's History page: every transfer with the node's word, pending, proven, executed, finalised under a checkpoint verified here, and one failed with the fee still paid
Every transfer with the node’s word: pending, proven, executed, finalised under a checkpoint this wallet verified. Igneum Wallet 0.1.5, rendered from its mock state with example keys, 7 October 2026.
diff --git a/tools/ci/README.md b/tools/ci/README.md index e8e368710..059771c39 100644 --- a/tools/ci/README.md +++ b/tools/ci/README.md @@ -2,11 +2,10 @@ | Check | What it fails | Since | |---|---|---| -| no text overlaps (`overlap-check.mjs`) | A served page, or a miner or wallet screen (behind `IGNEUM_OVERLAP_APPS=1`), where a visible run of text is covered by another element (a pill over a caption, a label over a value, a card over its neighbour, text under the header at rest), clipped by an overflow-hidden ancestor, or past the viewport; a page that scrolls sideways. Five widths, light and dark, the home hero at rest and at each step. A fixture with one deliberate overlap of each kind must be flagged first (`--self-test`). Needs a headless Chromium: CI installs Playwright; the Mac ships the pages to build-2 (`infra/build-server/overlap-browser.sh`). | 7 October 2026: the hero's step pill sat on the caption's second line ("Two thirds of the weight sign. The checkpoint locks.") at every desktop width, found by the founder on the live site | - -| master takes only CI-passed commits (`ci-state.mjs`, `merge-to-master.sh`, the hook's `master_ci_ok`) | A push to master whose commit, or whose merge's branch parent, has no green `ci` run on that exact sha (the runs API through gh: red, queued, none or gh unreachable all refuse); a merge onto a master whose last compiled run is red, unless declared the fix (`--fixes-master`). The merge tool pushes an unrun branch for a run and waits for a queued one with the clock. A feature-branch push prints the branch's previous red first (`--branch-red`). | 7 October 2026: era-vdf's tip 0e2d6b1c merged with no ci run; master's igneum-pow suite red from 16:31 UK under five docs-only green merges | -| every workflow job carries timeout-minutes (`workflow-timeouts-check.sh`) | A job in .github/workflows without `timeout-minutes`, or a budget off its measured line (site 15, changes 10, pow 60, sims 45). | 7 October 2026: three hosted site jobs on master hung over two hours each in the tree gate; the six-hour default was the only stop | -| a box or network check gets one retry (`retry-once.sh`) | Nothing by itself: wraps the box-locks check, the scene parity check and the live public API check so a first failure is printed and retried once; the second is the verdict. The checks keep their own skip line on a runner without the resource. | 7 October 2026 | -| the red watcher fires on cancelled and timed-out runs too (`ci-red.yml`, `red-watch.mjs`) | The watcher's `if` missing any of failure, cancelled, timed_out, or the conclusion not handed to the record step (the self-test reads the workflow file); the line names the kind: CI red, CI cancelled, CI timed out. | 7 October 2026 | +| no text overlaps (`overlap-check.mjs`) | A served page, or a miner or wallet screen (behind `IGNEUM_OVERLAP_APPS=1`), where a visible run of text is covered by another element (a pill over a caption, a label over a value, a card over its neighbour, text under the header at rest), clipped by an overflow-hidden ancestor, or past the viewport; a page that scrolls sideways. Five widths, light and dark, the home hero at rest and at each step. A fixture with one deliberate overlap of each kind must be flagged first (`--self-test`). Needs a headless Chromium: CI installs Playwright; the Mac ships the pages to build-2 (`infra/build-server/overlap-browser.sh`). | 7 October 2026: the hero's step pill sat on the caption's second line ("Two thirds of the weight sign. The checkpoint locks.") at every desktop width, found by the project lead on the live site | | kill by exact command or pid file (owed as a check) | 6 October 2026, 21:09Z: a Mac-side `pkill -f ` matched nothing (the log name was a redirect, not part of the command line), the roll-everything script lived on and wiped a box it had been told to hold. Rule: a job is stopped by its pid file (`tools/fleet/fleet-bg.sh start|stop `) or by a pattern anchored on its exact command line (`^python3 -u /root/fleet/in/box-prover.py`), never by a word that may or may not appear in it. The check that flags a `pkill -f`/`pgrep -f` whose literal is a path or a name that never starts a command line is owed to the CI lane | + +## No inline deletion in a shell string (7 October 2026) + +The desktop app asks the founder to approve any shell command that carries `rm` inside an inline `bash -c '...'` or `sh -c '...'` string ("runs rm and could not be checked"). Rule for every lane: never an inline `rm`, `rm -rf`, `find ... -delete` or a redirect-truncate inside a `bash -c` / `sh -c` string. Put the script in a file under `tools/` (or the lane's scratch directory) and run it by path; on the boxes, do deletions through the lease or job tooling, which the checker reads as a plain command. `tools/ci/inline-rm-check.sh` greps every tracked script for the shape (self-test first, known-failed shapes named) and runs in the gate. diff --git a/tools/ci/inline-rm-check.sh b/tools/ci/inline-rm-check.sh new file mode 100755 index 000000000..075209abc --- /dev/null +++ b/tools/ci/inline-rm-check.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# No inline deletion inside a `bash -c` or `sh -c` string (main, 7 October 2026 21:33 BST: the desktop app asked the founder to +# approve lanes' shell commands that carried `rm` inside an inline bash -c '...' string, "runs rm and could not be checked"). +# Rule: never an inline `rm`, `rm -rf`, `find ... -delete` or a redirect-truncate (`: > file`, `> file` on its own) inside a +# `bash -c` / `sh -c` string in a tracked script; put the script in a file under tools/ (or the lane's scratch directory) and run it +# by path; on the boxes, deletions go through the lease or job tooling, which the checker reads as a plain command. +# This check greps every tracked shell, PowerShell and JS/MJS script for a bash -c / sh -c string that carries one of those. Known +# failures named with file and line. --self-test first: four banned shapes fail, four allowed shapes pass. +set -uo pipefail +cd "$(git rev-parse --show-toplevel)" +# a line that opens an inline shell string (bash -c, sh -c, "bash", "-c" in a PowerShell or JS argument list) and, on the same +# line, a deletion word inside it +BANNED='((bash|sh|pwsh|powershell)(\.exe)? +-l?c +["'"'"'][^"'"'"']*|"-c", *["'"'"'][^"'"'"']*)(\brm +|\brm$|find [^"'"'"']*-delete|(^|[ ;&|]): *> *[^ ]|[ ;&|]> *([A-Za-z._$]|/[a-ce-z]|/d[a-df-z])[^ ]* *([;&|]|$))' +scan() { # : prints "file:line: text" for each hit + grep -n -H -E "$BANNED" "$@" 2>/dev/null | grep -v -E '^[^:]*:[0-9]+:\s*#' || true +} +if [ "${1:-}" = --self-test ]; then + t=$(mktemp -d); trap 'rm -rf "$t"' EXIT; fail=0 + printf '%s\n' 'ssh box "bash -c '"'"'cd /tmp && rm -rf /tmp/x'"'"'"' > "$t/b1.sh" + printf '%s\n' 'sh -c "find /srv/x -name y -delete"' > "$t/b2.sh" + printf '%s\n' 'bash -c '"'"': > /srv/builds/_locks/quiet'"'"'' > "$t/b3.sh" + printf '%s\n' 'Start-Process bash -ArgumentList "-c", "rm /tmp/old.log; echo ok"' > "$t/b4.ps1" + printf '%s\n' 'bash tools/ci/clean-scratch.sh /tmp/x' > "$t/a1.sh" + printf '%s\n' 'rm -rf "$t" # a plain command, the checker reads it' > "$t/a2.sh" + printf '%s\n' 'ssh box "bash -c '"'"'ls /srv/x && echo done'"'"'"' > "$t/a3.sh" + printf '%s\n' '# bash -c "rm -rf x" is banned (a comment names the rule)' > "$t/a4.sh" + for f in b1.sh b2.sh b3.sh b4.ps1; do [ -n "$(scan "$t/$f")" ] || { echo "inline-rm self-test: FAIL: banned shape $f passed"; fail=1; }; done + for f in a1.sh a2.sh a3.sh a4.sh; do [ -z "$(scan "$t/$f")" ] || { echo "inline-rm self-test: FAIL: allowed shape $f was flagged: $(scan "$t/$f")"; fail=1; }; done + [ "$fail" = 0 ] && echo "inline-rm self-test: 4 banned shapes fail (rm, find -delete, truncate, PowerShell -c list), 4 allowed shapes pass (script by path, plain rm, no deletion, a comment)" + [ "$fail" = 0 ] || exit 1 +fi +# allowed for now, named: the proving lane's WSL socket clean-up (tools/proving-v1, three lines of `bash -c 'pkill ...; rm -f /tmp/sp1-cuda-*.sock'` +# run inside WSL on a PC by a job, not from a Mac shell); the lane moves it into a file under tools/proving-v1 and the lines leave this list +ALLOW='^tools/proving-v1/(pc2-agg-cost(-restore)?|pc2-segments)\.ps1:' +hits="" +while IFS= read -r f; do + [ -n "$f" ] || continue + h=$(scan "$f" | grep -v -E "$ALLOW" || true) + [ -n "$h" ] && hits="${hits}${h}"$'\n' +done < <(git ls-files -- '*.sh' '*.bash' '*.ps1' '*.mjs' '*.js' '*.yml' '*.yaml' | grep -v -E '^tools/ci/inline-rm-check\.sh$') +hits=$(printf '%s' "$hits" | sed '/^$/d') +if [ -n "$hits" ]; then + echo "inline-rm: a deletion inside an inline bash -c / sh -c string (put the script in a file and run it by path; on a box use the lease or job tooling):" + echo "$hits" | cut -c1-200 | sed 's/^/ /'; exit 1 +fi +echo "inline-rm: no tracked script carries rm, find -delete or a truncate inside an inline bash -c / sh -c string" diff --git a/tools/ci/pre-push.sh b/tools/ci/pre-push.sh index d401750cb..b72bead41 100755 --- a/tools/ci/pre-push.sh +++ b/tools/ci/pre-push.sh @@ -26,7 +26,6 @@ cd "$(git rev-parse --show-toplevel)" || exit 1 # and fire this hook again inside the fixture: the first master push through the gate died that way (6 October 2026). unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_PREFIX GIT_COMMON_DIR GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_QUARANTINE_PATH GIT_PUSH_OPTION_COUNT MODE="${1:-local}"; MODE="${MODE#--}" -GATE_ROOT="$(pwd -P)" # the readers below are called from fixture repositories in the self-test, so by absolute path RED=0; N=0; LOG="$(mktemp)"; trap 'rm -rf "$LOG" "${SITE_TMP:-}"' EXIT T0=$(date +%s) @@ -53,20 +52,12 @@ site_build() { (cd "$SITE_TMP/site" && SITE_DOWNLOADS_OFFLINE=1 node build.mjs) } -wall_clock() { # : under GNU timeout where it exists (the runners); the Mac has none, and the job's timeout-minutes is the stop there. - # No array here: an empty array expanded under set -u is "unbound variable" on the Mac's bash 3.2 and ended the gate with no RED line (17:3x UK, 7 October 2026). - local secs="$1"; shift - if command -v timeout >/dev/null 2>&1; then timeout "$secs" "$@"; else "$@"; fi -} overlap_sweep() { - run "no lateral scroll: scrollWidth equals clientWidth on every route at five widths, both themes (self-test, then the site; skipped where there is no Playwright)" bash -c 'node tools/ci/scroll-width-check.mjs --self-test && node tools/ci/scroll-width-check.mjs --site site' # tools/ci/overlap-check.mjs: the known-failed fixture first, then the built site (the gate's temporary copy locally, the tree in # CI). A browser is needed: CI installs Playwright in the workflow; a machine without one ships the pages to a build box # (nothing heavy on the Mac). IGNEUM_OVERLAP_APPS=1 adds the miner and wallet UIs through their mocks (slower, the box). local dir="site"; [ "$MODE" = ci ] || dir="$SITE_TMP/site" - # a wall clock of 10 minutes where GNU timeout exists (the runners; the Mac ships the sweep to a box): the sweep took 192 s on a hosted - # runner on 7 October 2026 and three master jobs hung in this step for over two hours each the same afternoon - if [ "${IGNEUM_OVERLAP_APPS:-0}" = 1 ]; then wall_clock 600 node tools/ci/overlap-check.mjs --self-test --site "$dir" --apps .; else wall_clock 600 node tools/ci/overlap-check.mjs --self-test --site "$dir"; fi + if [ "${IGNEUM_OVERLAP_APPS:-0}" = 1 ]; then node tools/ci/overlap-check.mjs --self-test --site "$dir" --apps .; else node tools/ci/overlap-check.mjs --self-test --site "$dir"; fi } structural_checks() { @@ -80,9 +71,6 @@ never_push_checks() { # A secret or an identity leak must not reach the remote on any branch; together about 20 s on the Mac. run "identity grep of the public export list and the served site" bash tools/ci/identity-check.sh run "no secret file names and no 64-hex secrets in the tree" bash -c 'bash tools/ci/no-secrets-check.sh --self-test && bash tools/ci/no-secrets-check.sh' - # the third never-push class (7 October 2026, 20:5x UK): a founder name on ANY branch, because every branch went to the public host's - # mirror and a branch green-stamped before the check existed carried one onto master through the deferred merge - run "no founder name, personal login, earlier business or personal address in any tracked text file (the pre-public scrub; self-test first, encoded list)" bash -c 'bash tools/ci/founder-strings-check.sh --self-test && bash tools/ci/founder-strings-check.sh' } tree_checks() { @@ -116,7 +104,8 @@ tree_checks() { run "long-running tools keep their body in one parsed block (the edited-while-running class)" bash -c 'bash tools/ci/whole-body-check.sh --self-test && bash tools/ci/whole-body-check.sh' run "build-remote without a priority flag bounds suites and benches (nice 10, 32 cores); a gate runs unbounded" bash tools/ci/build-kind-default-check.sh run "the class router is a preference with spill-over (a held or overloaded box hands the job to the other one)" bash tools/ci/route-spill-check.sh - run "per-core leases, the quiet class and the reaper pass on the box (lease.sh and remote-run.sh self-tests over ssh; skipped on a runner with no box; one retry)" bash tools/ci/retry-once.sh box-locks bash tools/ci/box-locks-check.sh $( [ "$MODE" = ci ] && echo --ci ) + run "no deletion inside an inline bash -c / sh -c string in a tracked script (self-test first; the app cannot check it)" bash tools/ci/inline-rm-check.sh --self-test + run "per-core leases, the quiet class and the reaper pass on the box (lease.sh and remote-run.sh self-tests over ssh)" bash tools/ci/box-locks-check.sh $( [ "$MODE" = ci ] && echo --ci ) run "the simulators job runs on master and release-* pushes and pull requests into them only" bash tools/ci/sims-branch-check.sh run "publish-jobs.sh never removes a running or installs-app job without --force (the PC 2 abort class)" bash tools/ci/publish-jobs-check.sh run "no shell assignment hides behind a trailing comment (the swallowed-defaults class)" bash -c 'bash tools/ci/defaults-line-check.sh --self-test && bash tools/ci/defaults-line-check.sh' @@ -129,22 +118,18 @@ tree_checks() { run "the home hero's loop never idles in view, stops hidden, resumes without a jump" node tools/site-redesign/tests/hero-loop-test.cjs run "chain scene: the site's and the app's copies are scene/ byte for byte, the palette tokens live once (self-test, then the tree)" bash -c 'node tools/scene/sync.mjs --self-test && node tools/scene/sync.mjs --check' run "chain scene: a push paints with the document hidden and no animation frame (the blank /live of 7 Oct 2026; known-failed first)" node tools/scene/paint-test.cjs - run "chain scene: the live feed contract (the recorded reply validates; a rewritten miner, a float now, a stray key refused)" node --test tools/scene/feed-contract.test.mjs tools/scene/legend.test.mjs tools/scene/shard-words.test.mjs - run "chain scene parity: one recorded feed through the home fold, /live and the app's Inspect view on build-2, three frames each pixel-equal apart from the app's own-key overlay (a changed token fails first; skipped with no box and no Playwright; one retry)" bash tools/ci/retry-once.sh scene-parity bash tools/scene/parity-remote.sh + run "chain scene: the live feed contract (the recorded reply validates; a rewritten miner, a float now, a stray key refused)" node --test tools/scene/feed-contract.test.mjs + run "chain scene parity: one recorded feed through the home fold, /live and the app's Inspect view on build-2, three frames each pixel-equal apart from the app's own-key overlay (a changed token fails first; skipped with no box and no Playwright)" bash tools/scene/parity-remote.sh run "no text overlaps: every served page at 390 to 1600 px, light and dark, the hero at each step (self-test first; IGNEUM_OVERLAP_APPS=1 adds the miner and wallet UIs)" overlap_sweep - run "explorer, emission and public stats unit tests" node --test site/lib/explorer.test.mjs site/lib/emission.test.mjs site/lib/money.test.mjs site/lib/leaderboard.test.mjs site/api/public-stats.test.mjs + run "explorer, emission and public stats unit tests" node --test site/lib/explorer.test.mjs site/lib/emission.test.mjs site/lib/money.test.mjs site/api/public-stats.test.mjs run "ship tool self-test" node tools/ship-app.mjs --self-test run "relay unit tests" node --test relay/test/parse.test.mjs relay/test/auth.test.mjs relay/test/wake.test.mjs relay/test/ember.test.mjs run "miner app notice strip and update card tests" node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs app/igneum-app/ui/view.test.mjs app/igneum-app/ui/tune-line.test.mjs run "launch gates: every row with its check, the handoff text clean (self-test, then the tree)" bash -c 'node tools/ci/launch-gates-check.mjs --self-test && node tools/ci/launch-gates-check.mjs' - run "income per tier: the public table equals its inputs, the schedule arithmetic" bash -c 'node tools/launch/income-tiers.mjs --check && node --test tools/launch/income-tiers.test.mjs && node tools/launch/income-page.mjs --check' + run "income per tier: the public table equals its inputs, the schedule arithmetic" bash -c 'node tools/launch/income-tiers.mjs --check && node --test tools/launch/income-tiers.test.mjs' run "hash-origin report: a known-finished day and a known-failed day" node --test tools/observer/hash-origin.test.mjs run "harness summaries never carry a raw 64-hex key (the writer's own redaction and check)" node infra/fast-time/lib/redact-keys.mjs --self-test run "docs-only pushes skip the compile-or-compute CI jobs (the changes job's classifier)" bash tools/ci/docs-only-check.sh --self-test - run "the public ledger (docs/ledger-public.md) is what docs/fud-ledger.md generates: one row per item, no commit ids, times or team names (self-test first)" bash -c 'node tools/ledger/export-public.mjs --self-test && node tools/ledger/export-public.mjs --check' - run "every workflow job carries timeout-minutes (site 15, changes 10, pow 60, sims 45; the hung-job class of 7 October 2026)" bash tools/ci/workflow-timeouts-check.sh --self-test - run "a box or network check gets one retry before it is red (retry-once self-test)" bash tools/ci/retry-once.sh --self-test - run "CI state reader: a commit's newest run, master's last compiled run, a branch's last red (fake gh; the merge rule's reader)" node tools/ci/ci-state.mjs --self-test } gated_refs() { @@ -180,33 +165,6 @@ deferred_merge() { # [repo dir] -> "defer /dev/null || stat -c %Y "$f") )); [ "$age" -le 43200 ] || { echo "full the stamp for ${p2:0:8} is $age s old"; return; } echo "defer $p2" } -# Master takes only what CI has already passed (standing rule, 7 October 2026, 17:2x UK: era-vdf's tip 0e2d6b1c was merged with -# no ci run at all and master's igneum-pow suite stayed red for 40 minutes under docs-only merges). For a push to master the hook -# asks tools/ci/ci-state.mjs: a two-parent merge needs a green run on its SECOND parent (the branch's own run on the exact -# commit), a plain commit needs a green run on itself (a fast-forward of a branch CI passed); anything else is refused with the -# run's state, and the lane uses tools/ci/merge-to-master.sh, which waits for a queued run. gh unreachable = refused (unknown). -# release-* branches keep the full local gate alone (the shipper's cuts carry their own box suite line). -master_ci_ok() { # -> 0 and a line, or 1 and the reason - local lsha="$1" rsha="$2" parents p2 want line state - parents=$(git rev-list --parents -n 1 "$lsha" 2>/dev/null | cut -d' ' -f2-); set -- $parents - if [ -n "${2:-}" ] && [ -z "${3:-}" ] && [ "$1" = "$rsha" ]; then want="$2"; else want="$lsha"; fi - line=$(node "$GATE_ROOT/tools/ci/ci-state.mjs" "$want" 2>&1); state="${line%% *}" - if [ "$state" = success ]; then echo " master takes ${want:0:8}: ci $line"; return 0; fi - echo "pre-push gate: REFUSED. master takes only a commit whose own ci run is green on that exact commit; ${want:0:8} is: $line" >&2 - echo " Use tools/ci/merge-to-master.sh (it pushes the branch for a run when there is none, waits for a queued run and refuses a red)." >&2 - return 1 -} -master_rule_binds() { # : 0 when the CI rule applies to this push (a GitHub remote, no declared exception), 1 with a printed line otherwise - local url="${1:-}" - if [ -n "${IGNEUM_MASTER_EXCEPTION:-}" ]; then echo " EXCEPTION to the CI rule for this push, declared by main: $IGNEUM_MASTER_EXCEPTION (the local gate is the verdict)"; return 1; fi - case "$url" in *github.com*) return 0 ;; esac - echo " the remote ${url:-?} is not GitHub (a mirror): the CI rule binds GitHub's master; the local gate is the verdict here"; return 1 -} -branch_red_line() { # : the branch's newest completed ci run, when red, printed before the light gate (nothing on green or no gh) - local line; line=$(node "$GATE_ROOT/tools/ci/ci-state.mjs" --branch-red "$1" 2>/dev/null) || return 0 - case "$line" in previous\ CI\ red*) echo " $line" ;; esac - return 0 -} finish() { local what="$1" secs=$(( $(date +%s) - T0 )) if [ "$RED" = 0 ]; then echo "pre-push gate ($what): GREEN, $N checks in ${secs}s"; [ "${STAMP:-0}" = 1 ] && stamp_green; exit 0; fi @@ -230,7 +188,6 @@ case "$MODE" in # the light gate carries the two never-push classes beside the structural checks, and the full gate runs them too declare -f never_push_checks | grep -q 'tools/ci/no-secrets-check.sh' || { echo "self-test failed: the never-push checks do not run the no-secrets check"; fails=1; } declare -f never_push_checks | grep -q 'tools/ci/identity-check.sh' || { echo "self-test failed: the never-push checks do not run the identity grep"; fails=1; } - declare -f never_push_checks | grep -q 'tools/ci/founder-strings-check.sh' || { echo "self-test failed: the never-push checks do not run the founder-strings check"; fails=1; } grep -qE '^\s+structural_checks; never_push_checks; finish "feature branch"' "$0" || { echo "self-test failed: the hook's light gate does not run the never-push checks"; fails=1; } # the green stamp and the deferral, in a fixture repository: a merge of a stamped branch onto the remote tip defers; an # unstamped branch, a stale stamp, a merge onto an older tip and a plain commit all take the full gate @@ -251,36 +208,7 @@ case "$MODE" in MODE=ci GITHUB_ACTIONS= site_in_place && { echo "self-test failed: --ci outside GitHub Actions chose the in-place build"; fails=1; } MODE=ci GITHUB_ACTIONS=true site_in_place || { echo "self-test failed: --ci inside GitHub Actions did not choose the in-place build"; fails=1; } declare -f tree_checks | grep -q 'never_push_checks' || { echo "self-test failed: the full gate does not run the never-push checks"; fails=1; } - # the overlap sweep's wall clock runs the command with GNU timeout where it exists and plainly where it does not (bash 3.2 under set -u included) - [ "$(wall_clock 5 /bin/echo clocked 2>&1)" = clocked ] || { echo "self-test failed: wall_clock did not run its command"; fails=1; } - [ "$(PATH=/nonexistent wall_clock 5 /bin/echo plain 2>&1)" = plain ] || { echo "self-test failed: wall_clock without a timeout binary did not run its command plainly"; fails=1; } - grep -q 'wall_clock 600 node tools/ci/overlap-check.mjs' "$0" || { echo "self-test failed: the overlap sweep does not run under the wall clock"; fails=1; } - # master takes only CI-passed commits: a merge asks about its second parent, a plain commit about itself; red, pending, none and unknown refuse - grep -qE 'master_ci_ok "\$lsha" "\$rsha" \|\| exit 1' "$0" || { echo "self-test failed: the hook does not ask ci-state before a push to master"; fails=1; } - grep -qE 'branch_red_line "\$\{rref#refs/heads/\}"' "$0" || { echo "self-test failed: the feature-branch hook does not print the branch's previous red"; fails=1; } - fx=$(mktemp -d); ( cd "$fx" && git init -q -b master . && git -c user.name=t -c user.email=t@t commit -q --allow-empty -m a ) 2>/dev/null - A=$(git -C "$fx" rev-parse HEAD); git -C "$fx" checkout -q -b b; git -C "$fx" -c user.name=t -c user.email=t@t commit -q --allow-empty -m b; B=$(git -C "$fx" rev-parse HEAD) - git -C "$fx" checkout -q master; git -C "$fx" -c user.name=t -c user.email=t@t merge -q --no-ff -m "merge b" b; M=$(git -C "$fx" rev-parse HEAD) - fakebin=$(mktemp -d) - cat > "$fakebin/gh" </dev/null 2>&1 ) || { echo "self-test failed: a merge whose branch parent has a green run was refused"; fails=1; } - ( cd "$fx" && PATH="$fakebin:$PATH" master_ci_ok "$B" "$A" >/dev/null 2>&1 ) || { echo "self-test failed: a plain commit with its own green run was refused"; fails=1; } - ( cd "$fx" && PATH="$fakebin:$PATH" master_ci_ok "$M" "$B" >/dev/null 2>&1 ) && { echo "self-test failed: a merge onto another tip (its own run queued) was let through"; fails=1; } - ( cd "$fx" && PATH="$fakebin:$PATH" master_ci_ok "$A" "$A" >/dev/null 2>&1 ) && { echo "self-test failed: a commit with no ci run was let through to master"; fails=1; } - rm -rf "$fx" "$fakebin" - # the CI rule binds a GitHub remote; a mirror remote and a declared exception take the local gate, each with a printed line - master_rule_binds https://github.com/igneum-network/igneum.git >/dev/null || { echo "self-test failed: the CI rule did not bind a GitHub remote"; fails=1; } - master_rule_binds build@188.40.146.49:/srv/igneum.git >/dev/null && { echo "self-test failed: the CI rule bound a box mirror remote"; fails=1; } - ( IGNEUM_MASTER_EXCEPTION="main, 7 Oct 2026 19:5x UK: GitHub suspended" master_rule_binds https://github.com/x/y.git >/dev/null ) && { echo "self-test failed: a declared exception did not lift the CI rule"; fails=1; } - out=$(IGNEUM_MASTER_EXCEPTION="ruling text" master_rule_binds https://github.com/x/y.git); case "$out" in *"EXCEPTION"*"ruling text"*) ;; *) echo "self-test failed: the exception was not printed with its ruling: $out"; fails=1 ;; esac - [ "$fails" = 0 ] && echo "self-test passed: a failing check is RED and fails the gate, a passing one is ok; master and release-* select the full gate, other refs the light one; a merge of a green-stamped branch onto the remote tip defers to CI, every other shape takes the full gate; master takes only a commit (or a merge's branch parent) whose own ci run is green, and refuses red, queued and unrun ones (GitHub remotes; a mirror remote or a declared exception takes the local gate, printed); a feature-branch push prints the branch's previous red first; a --ci site build outside GitHub Actions leaves the tree unchanged (structural checks, no-secrets, identity grep)" + [ "$fails" = 0 ] && echo "self-test passed: a failing check is RED and fails the gate, a passing one is ok; master and release-* select the full gate, other refs the light one; a merge of a green-stamped branch onto the remote tip defers to CI, every other shape takes the full gate; a --ci site build outside GitHub Actions leaves the tree unchanged (structural checks, no-secrets, identity grep)" exit $fails ;; list) grep -E '^\s+run "' "$0" | sed -E 's/^\s+run "([^"]+)".*/\1/' ;; @@ -289,16 +217,6 @@ FAKEGH if [ "$which" = full ]; then # a merge of a green-stamped branch onto the exact remote tip goes through on the light gate (CI runs the full one) verdict=""; while read -r lref lsha rref rsha; do case "$rref" in refs/heads/master|refs/heads/release-*) verdict=$(deferred_merge "$lsha" "$rsha"); break ;; esac; done <<<"$REFS" - # a push to master: the pushed commit (or its branch parent) must already have a green ci run on that exact commit. CI runs on - # GitHub, so the rule binds a push whose remote is github.com; a push of master to a box mirror (build@:/srv/igneum.git) - # takes the local gate as before. IGNEUM_MASTER_EXCEPTION="" lifts the CI rule for one push and is printed with - # the push (7 October 2026, 19:5x UK: the GitHub account suspended, lanes landing on the box mirror's master by main's ruling, - # the box gate stamp as the verdict; GitHub gets the fast-forward when it answers again). - if master_rule_binds "${2:-}"; then - while read -r lref lsha rref rsha; do - if [ "$rref" = refs/heads/master ] && [ "$lsha" != 0000000000000000000000000000000000000000 ]; then master_ci_ok "$lsha" "$rsha" || exit 1; fi - done <<<"$REFS" - fi case "$verdict" in defer*) echo "pre-push gate: a merge of green-stamped ${verdict#defer } onto the remote tip: the light gate here, the full gate in CI on landing:" structural_checks; never_push_checks; finish "merge of a green branch (full gate deferred to CI)" ;; @@ -307,7 +225,6 @@ FAKEGH esac else echo "pre-push gate: a feature branch, the light gate (the two structural checks, the no-secrets check, the identity grep):" - while read -r lref lsha rref rsha; do case "$rref" in refs/heads/*) branch_red_line "${rref#refs/heads/}" ;; esac; done <<<"$REFS" structural_checks; never_push_checks; finish "feature branch" fi ;; ci|local)