These three commits were pushed to the forge's theseus and site repos
from their branch but never reached master, so pushing master would
have dropped them there. Merged so master carries them: the branded
error page on BCNR-to-clearnet fallback failures, the Cloudflare Bot
Fight 503 hint with a .bch mirror suggestion, and the site's docs page
for the p-record reverse-proxy workaround.
Registered bergamot.x on-chain with {s3: bns/bergamot/, u: silentmode.st/bergamot}.
The page explains what Bergamot (Mozilla's WASM translator) will add to Theseus:
an on-device translation provider that never sends the page to a server, as an
alternative to the hosted LibreTranslate backend. Models mirror from Sia on
first use, one direction per download.
Lives at:
- https://silentmode.st/bergamot (ICANN)
- https://silentmode.st/bns/bergamot.x/ (gateway proxy)
- bergamot.x (BNS; Sia-backed through bns/bergamot/)
The provider stub comes in a follow-up Theseus commit.
Setup 9e5c4b6b…b7e9, portable b223eb14…5c49. Pithos opens at
pithos.sia/<user>/<drive>/<folder>, music keeps playing in background
tabs, a widened left panel no longer squeezes the page; bundles Pithos
0.3.10 and Aegis 0.31.0.
A flagged name and its subdomains are served behind a warning that names the
reason, the list and the report transaction. The visitor may continue, per
name, for a day. The one refusal is the csam reason.
/api/blocklist returns the subscribed lists and current flags, and
/api/name/<name> carries the flag fields, for clients that cannot reach a
full electrum server. It is a convenience copy: every entry names its report
and can be re-derived from the list address.
Flags are read once a minute from full servers and shared across requests;
names are resolved without the extra round trip. BNS_BLOCKLISTS adds lists.
The mobile constants now carry the default subscriptions for the consumer to
come, and the docs explain flagged names.
buildReleaseTx spends the certificate and writes no token output: the
omission is the burn. The certificate's own dust pays the beacon and the fee,
so a release needs no other coin.
releaseWithBuiltInWallet checks whether the certificate sits in a beacon
transaction. One that arrived by a plain transfer cannot be proven burned
from the beacon history, so the flow publishes an UPD first and releases its
output. Both paths ran on chipnet, and a released name was registered again
after its release confirmed.
checkAvailability now reports a pending release as not available: a REG
broadcast while the release is unconfirmed could be mined beside it and be
void, and the buyer would have paid for nothing.
Cloudflare's Bot Fight Mode fingerprints Electron's TLS ClientHello and
returns HTTP 503 to Theseus regardless of user-agent (verified against
whybitcoincash.com). BNS `p` records proxy through Node's undici fetch
from the main process, which has a different TLS fingerprint and slips
past the check — Theseus renders the upstream under the .bch origin.
New /mirrors/ page explains the mechanism, links the relevant code
(record-picker.js and main.js serveP), and walks through minting a
mirror in Sirius. Ships with an empty featured list; entries populate
as .bch names are minted and added to home-cards.json.
Also adds a short note on /tools/ pointing at the new page so users
hitting a 503 have a discovery path.
A parallel ship pass raced this one on the same version string: the
other session built 0.3.75 from 4bfef3a (Aegis 0.29.0) and scp'd its
binaries over mine. The first reconcile pass accepted the on-disk
hashes under the "both built from the same HEAD" assumption, but they
are different builds — mine includes d2ddee5 (Aegis 0.30.0) and the
master tip, theirs stops at 4bfef3a. The peer stood down, I re-scp'd
my binaries, and this commit pulls the manifest + the releases page +
theseus.x back to those hashes. The release notes already named
Aegis 0.30.0, which matches what the binaries actually bundle now.
Manifest, releases page, download pages and theseus.x fallback text all point at
0.3.61 with the new hashes. Silentmode.st serves static; silentmode.bch mirror
follows via the 5-min Sia sync.
Every subsystem is now individually switchable and reports its own state.
GET http://127.0.0.1/api/status returns:
- daemon: version, startedAt, uptimeSec, policy, permittedTlds, ports,
upstream, gateway
- index: size, nameCacheSize, warmStart {source, at, size}
- sources.snapshotHttps: enabled, urls, lastAttempt/Success/Status/Error,
winnerUrl, notModified count, refreshes count, ETags
- sources.electrumWss: enabled, lastAttempt/Success/Error, failStreak, refreshes
- sources.perQueryLookup: enabled, gateway, lastAttempt, hits/misses/errors
- sources.diskCache: enabled, path, exists, size, mtime
- sources.localApi: enabled, endpoints[]
- policyFile: path, exists
policy.json schema extended with a sources.<name>.enabled block, hot-reloaded
by the existing loadPolicyOverride() on the same 5-second tick as the
collision policy. Each refresh/lookup path guards on its flag, so an operator
can isolate any subsystem without a restart:
- snapshotHttps off -> daemon skips dl.silentmode.st/Sia polling
- electrumWss off -> daemon skips chipnet WSS refresh
- perQueryLookup off -> DNS handler misses fall straight through to forward
- diskCache off -> no write to and no read from bns-name-snapshot.json
- localApi off -> /api/* return 503 with a hint pointing at policy.json
Verified locally on port 18080: /api/status returned the full JSON with a
snapshot warm-start from dl.silentmode.st recorded in warmStart, ETag captured
in sources.snapshotHttps.etags, disk cache path/size/mtime populated.
Deployed dl.silentmode.st + Sia. sha256 a16d10759efede4412f4fdb52d59424bf56bbb258bb002ab930f4a5a5aef8a41.
The matching Theseus panel UI (source table with the toggles + a Copy-status
button that fetches /api/status) belongs in the Theseus release; not touched
here to avoid colliding with settings-preload.js work in flight from a
parallel session.
Manifest and download pages point at the new build. Silentmode.st serves
static; silentmode.bch mirror follows via the 5-min Sia sync; theseus.x's
fallback text and hashes match the 0.3.60 binaries so the page reads correctly
before the client-side manifest fetch overwrites them.
- .iss pre-install hook now also kills orphan node.exe from the Ariadne
install dir (foreground diagnostic runs, crashed processes not cleaned
up by the scheduled task), path-scoped so no other app is affected.
Fixes upgrades failing with "DeleteFile failed; code 5 -- Access is
denied" on runtime/node.exe -- seen on 0.1.11 install by a user who had
run the daemon manually per an earlier diagnostic.
- bnsd.js Express gateway now serves local BNS indexer endpoints:
/api/tlds -> {source, tlds: string[], count}
/api/name/:n -> full BNS entry (same shape as navigate.st/api/name/)
/api/registry -> {source, count, names[]} full index dump
CORS wide-open (matches operator behavior). Any app on the machine can
now query BNS locally with no navigate.st round-trip. Answers off the
daemMons in-memory index which already merges snapshot warm-start +
ETag polling + per-query indexer fallback + electrum WSS.
Verified locally: hello.bch resolves via /api/name; unknown gives 404;
/api/tlds returns the CA-constrained set (bch p2p bit deviant nav test
bcnr on this boxs current CA); /api/registry returns 61 names.
Deployed: dl.silentmode.st + Sia. sha256 b041652a330fefb4561da7ca14fa84ddf3b6085fda6eb62831cb08ea56ec602d.
The daemon now uses the operator's live BNS indexer as the primary source of
truth, not chipnet electrum. Two changes to the resolver pipeline:
1) Background refresh is HTTPS-first with ETag. Every 30 s the daemon polls
dl.silentmode.st/bns-name-index.json (and s3.silentmode.st:8600 as an
independent Sia mirror) sending If-None-Match; only reparses the array
when the operator republished, does zero work otherwise. Electrum WSS
stays as a same-tick secondary that runs when HTTPS turned nothing up,
so a daemon on a network that can reach chipnet but not the operator VPS
still converges. Both broken? Keep the last-good index from warm-start.
2) Per-query indexer fallback in the DNS handler. When the in-memory index
misses, the handler calls navigate.st/api/name/<host> directly with a
5-second timeout and a 30-second LRU cache. Names registered AFTER the
last snapshot poll but BEFORE the next one now answer immediately from
the live indexer instead of falling straight through to a forward and
returning NXDOMAIN. Cache is cleared on any successful full refresh so
a de-registered name doesn't stay resolvable.
Net effect: on the class of failure that motivated this (chipnet electrum
timing out on blockchain.scripthash.get_history, or port 50004 filtered by
the network), the daemon just works. The operator's HTTPS indexer -- which
every other client in the ecosystem (Theseus mobile, Aegis, sirius.x, the
gateway itself) already reads from -- is now Ariadne's Thread's primary
too. Trust model unchanged: the snapshot always came from the operator.
Verified locally with the built binary on port 15353:
bnsd index: warm-started from https://dl.silentmode.st/bns-name-index.json (61 names)
hello.bch -> 127.0.0.1 (snapshot hit)
game.x -> 127.0.0.1 (per-query /api/name fallback -- not in .bch-heavy snapshot)
coinspectrum.x -> 127.0.0.1 (per-query fallback)
ariadne.x -> 127.0.0.1 (per-query fallback)
notregisteredxyz.x -> NXDOMAIN (indexer confirms not registered, forwarded to upstream)
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.11.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.11.exe
- silentmode.st manifest advertises 0.1.11
- sha256 58ffb06424785973d2cd656e5122061ce10b53a8dcff55605c23b5699552ee75
WSS-blocked networks
Symptom on the other box (2026-09-29): task Running, port 53 bound by our
node, `Resolve-DnsName hello.bch -Server 127.0.0.1` times out. Cause: the
daemon's initial index build was a top-level `await buildIndex()` over
electrum WSS to chipnet (port 50004). Corporate/ISP networks that filter
outbound WSS let the await hang forever; the queries fell through to
`forward()` to upstream 1.1.1.1:53, which the same firewall also blocked,
so both legs died.
0.1.10 borrows Theseus's warmFromSnapshot pattern for the system-wide
daemon. On startup, in parallel with an 8 s deadline per source:
1. HTTPS snapshot from operator VPS https://dl.silentmode.st/bns-name-index.json
2. HTTPS snapshot from Sia mirror https://s3.silentmode.st:8600/bns/name-list.json
3. On-disk cache from a previous run C:\ProgramData\Ariadne\bns-name-snapshot.json
First non-empty result wins; on any HTTPS win the raw array is written to
the disk cache so the NEXT boot is instant even fully offline. dns.bind()
runs the moment warm-start completes, whether or not electrum was
reachable. Electrum WSS refresh continues in the background on the 30 s
timer and wins over the snapshot when it succeeds because it is strictly
newer.
Snapshot format is the pre-resolved array Android's Ariadne reader already
consumes (`[{name, category, records, txid, height, updatedTxid, owner?}]`),
so the operator maintains ONE artifact for both clients. Custom URLs go in
`ariadne.config.json`.snapshotUrls.
Verified on the dev box by running the built binary manually on port 15353:
bnsd index: warm-started from https://dl.silentmode.st/bns-name-index.json (61 names)
bnsd DNS: 127.0.0.1:15353 (policy=bcnr-first, upstream 1.1.1.1)
hello.bch -> 127.0.0.1
Disk cache written: 17,674 bytes.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.10.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.10.exe
- silentmode.st manifest advertises 0.1.10
- sha256 29710c4011dfe058a252f94af221c02593e728e89cc7427e3e01eaa530f8e526
Chromium (Chrome + Edge) doesn't treat `foo.x` as a URL because `.x` isn't on
its known-TLD list -- it sends bare input to the default search engine. Only
way to intercept it without a browser extension is to make the default search
engine one that understands BNS.
The daemon now serves that. New route `app.get("/search")` before the catch-all
Express handler:
- `q` matches <label>.<permitted-tld> -> 301 https://q/ (any path preserved)
- q has whitespace, unknown TLD, IP, etc. -> 302 to `searchFallback`
(ariadne.config.json, defaults to https://duckduckgo.com/?q=)
- empty q -> 400
Permitted-TLD check reuses isPermittedHost() from lib/tlds.js -- same set the
CA is constrained to and the SNI callback gates leaf minting against, so
"routable, therefore a URL" stays one decision.
Users set their browser's default search engine to
`http://127.0.0.1/search?q=%s`. Everything decided locally, no navigate.st
round trip. Works offline. Works with the same offline BNS index the DNS side
uses. Fallback engine is per-user via config, not a locked-in default.
Verified on this box after upgrade:
"ariadne.x" -> 301 https://ariadne.x/
"game.x" -> 301 https://game.x/
"hello.bch" -> 301 https://hello.bch/
"ariadne.x/path" -> 301 https://ariadne.x/path
"Weather" -> 302 https://duckduckgo.com/?q=Weather
"bitcoin cash" -> 302 https://duckduckgo.com/?q=bitcoin%20cash
"unknown.zzz" -> 302 https://duckduckgo.com/?q=unknown.zzz
"" -> 400 bnsd search: q parameter is required
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.9.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.9.exe
- silentmode.st manifest advertises 0.1.9
- sha256 3b973e0ae584113ad776c756b16b895fd0dfb217a02bfae6376c5abb48f9a77c
Before 0.1.8, a BNS name with an on-chain `ip` record made the daemon return
the origin's public IP directly. Browsers then hit the origin's own HTTPS
server -- and if that origin's cert was not browser-trusted (which is the
whole point of the on-chain `tls` fingerprint pin next to the `ip` record),
every browser except Theseus rejected the site with ERR_CERT_AUTHORITY_INVALID
or SEC_ERROR_UNKNOWN_ISSUER. game.x and hephaestus.x both hit this. Theseus
was fine because its in-process resolver validates against the on-chain pin.
0.1.8 answers DNS with 127.0.0.1 whenever the name has BOTH `ip` and `tls`,
terminates the browser's TLS locally with our trusted leaf, and reverse-proxies
to the origin over HTTPS while validating the origin's SHA-256 fingerprint
against the on-chain pin. Same algorithm Theseus uses (main.js:pinnedHttpsGet,
cert.fingerprint256 lower-cased, colons stripped) so a site's `tls` record
means the same thing in-Theseus and system-wide.
Names with just `ip` (no pin) keep direct routing -- unchanged. Only opts in
when the owner has published a fingerprint pin, so nothing regresses for sites
that deliberately wanted direct IP routing.
Two subtle bugs found + fixed while landing this:
1. `agent: false` on the outbound https.request. With Node's default global
agent (keepAlive on), the second request onwards reuses the TLS socket
and `res.socket.getPeerCertificate(false)` comes back stripped of
fingerprint256 -- pin validation then reads "empty" and rejects with 526.
Fresh socket per request costs a handshake but is cheap next to the
pin-verify miss.
2. Removed `content-encoding` from the hop-by-hop strip list. Origin sends
gzip'd bytes; my proxy streams them unchanged. If we strip
content-encoding while forwarding compressed bytes, the browser treats the
gzip magic as text and renders garbage. content-encoding is end-to-end
per RFC 7230 -- keep it.
Verified on this box: game.x, hephaestus.x, theseus.x, sirius.x,
coinspectrum.x, hello.bch all load HTTPS 200 in strict IWR and Chromium; DNS
answers 127.0.0.1 for game.x + hephaestus.x (was their origin IP before),
still their origin IP for names without a tls pin.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.8.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.8.exe
- silentmode.st manifest advertises 0.1.8
- sha256 47450ad4555beb04fe3b90ae5f658dc2932061d011ada9a2fb507471e2f0a0cb
The per-name tab was a DNS record table: eight record types, of which the
stack reads exactly one, and then only as a last resort when a name carries
no content record. Everything else was signed, stored and read by nobody —
furniture that looked like configuration. Meanwhile the thing a name owner
actually has, a folder tree that already answers on matching subdomains, was
not visible anywhere and could not be changed.
The tab now leads with what answers today: the apex, every folder in the
name's storage next to the subdomain it serves on, and which of those a rule
overrides. Below it, the rules — point a subdomain at a different folder,
redirect it, or switch it off.
Classic DNS keeps its table, behind a disclosure that says plainly what
those records do today and what they are waiting for. Nobody loses a record
they published; they just stop being the first thing a name owner is asked
to think about. The table gains a Host column, so records can belong to a
subdomain rather than only the apex.
Both halves are one signed manifest and one publish button — they always
were one file, and two buttons for it only ever invited a half-saved state.
Labels and values are separated in the generated rows so the words
translate and the owner's own folder and URL do not.
The signer accepted v1 manifests only, which would have rejected every
publish from this screen.
Feature. The daemon now hot-reloads C:\ProgramData\Ariadne\policy.json every
5 s (fs.stat mtime check, only opens the file when it actually changed) and
flips its DNS collision policy between bcnr-first and icann-first in place.
Every browser on the machine follows within seconds -- no daemon restart,
no reinstall, no UAC. The next Ariadne panel in Theseus will edit this file
directly; a text editor works too.
install.ps1 seeds the file with the current -Policy default on FIRST install
only (an upgrade never clobbers a user's later flip) and grants BUILTIN\Users
Modify on it so an unprivileged app can rewrite it. Invalid values keep the
last good policy (logged). File deleted -> daemon falls back to the CLI
policy the scheduled task was registered with.
Also fixes an intermittent "config unreadable" on daemon startup when
ariadne.config.json had a UTF-8 BOM -- same class of PS-writes-BOM bug 0.1.6
fixed in the TLD-sync path, this time in bnsd.js's own config loader.
Verified live on this box with a second daemon running on port 15353:
bnsd policy: bcnr-first -> icann-first (from C:\ProgramData\Ariadne\policy.json)
bnsd policy: icann-first -> bcnr-first (from C:\ProgramData\Ariadne\policy.json)
bnsd policy: ... has invalid policy 'cash-first' -- keeping bcnr-first
ACL check: BUILTIN\Users has Modify on policy.json, non-elevated write succeeds.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.7.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.7.exe
- silentmode.st manifest advertises 0.1.7
- sha256 742f8005c2dfb47929287c009cddf7738f0d12bd56fb8f8a837df3e9b435f47f
Theseus UI wiring for this file NOT touched -- settings-preload.js has 31
lines of uncommitted work from another session; a Theseus panel selector
belongs in that session's next commit so it doesn't collide.
Symptom: on any machine that had been through a series of installs, one or
more older "BNS Local Root CA" certs from earlier builds could accumulate in
LocalMachine\Root -- an unconstrained root from before 2026-07, or a rotated
one -- and every install added the current constrained root ALONGSIDE the
stale ones. Two certs with the same Subject-DN defeat browser chain-builders:
Chromium/Edge/Firefox pick one candidate and refuse to try the others, so
every .bch site failed with ERR_CERT_AUTHORITY_INVALID / SEC_ERROR_BAD_SIGNATURE
in every browser EXCEPT Theseus (which trusts the on-chain tls fingerprint
directly, not the machine store).
Reproduced on the dev box: two BNS Local Root CAs present (thumbprints
EB5DBE98... constrained + 23538FD7... unconstrained), DNS answered correctly,
strict Invoke-WebRequest to https://coinspectrum.bch/ failed. Removing the
stale one and re-running the chain-build restored HTTPS 200.
Fix (install.ps1):
- Before Add(imported), enumerate the store and $store.Remove() every
"BNS Local Root CA" whose thumbprint differs from the one we're about
to trust. Post-condition: exactly one BNS root remains after install.
Fix (uninstall.ps1):
- Switched from `Get-ChildItem Cert:\LocalMachine\Root` to X509Store direct.
The Cert: PSDrive is not always loaded in Inno's [UninstallRun] -NoProfile
context, so uninstall could silently leave the CA behind on the store side
even while it removed everything else.
Verified end-to-end on this box: 0.1.4 upgrade over 0.1.3 finished cleanly,
BNS Resolver Daemon Running, 127.0.0.1:53 open, exactly one BNS Local Root
CA in the machine store, strict HTTPS to https://coinspectrum.bch/ returned
200 (506,997 bytes) with X509Chain.Build ok=true leaf -> BNS root.
Deployed
- dl.silentmode.st/AriadneResolver-Setup-0.1.4.exe
- s3://bns/silentmode/dl/AriadneResolver-Setup-0.1.4.exe
- silentmode.st manifest advertises 0.1.4
- sha256 30ed5e3bb6d6da5325f854c97976410b4fc63067ed52c810a55e9d2e1bdc4e17
Every client hard-coded the chipnet beacons, address prefix and electrum
servers on its own: resolver, registrar config, wallets, gateway, indexer,
mirror scripts, the browser bundle and the mobile Java. A mainnet launch would
have meant finding all of them and hoping none was missed.
The table now lives in resolver-web.js, the one file every client already
shares, so it stays a single-file drop-in. BNS_NETWORK selects the record;
unset means chipnet, so nothing changes today: the live index resolves the
same 60 names and 20 TLDs, the 67 offline tests pass, and the dashboard,
market and studio load the same values through BNS.NETWORK.
The mainnet record carries the verified public servers, the prefix and its
own Sia bucket, but its beacons, start height and operator address are
deliberately null: requireBeacons() refuses to scan until they are pinned in
the order ROADMAP-MAINNET.md §6 requires. Bns.java reads a generated
BnsNetwork.java so the phone cannot drift from the desktop clients.
NETWORK-CONFIG.md records what reads the table and what a launch still pins.
The page assigned free to sm-1, but sm-1 was the primary infra box —
public gateway, BNS indexer, site, mailbox. Free carries the most
traffic, so the exits were renumbered to put free on the lightest box
and max-only on the busiest, and the page now matches: sm-1 is the
free-and-up exit, sm-3 is max-only, and each carries the Reality
steering domain it is really fronted by.
site/brand/social/ and site/brand/icon/ carry ready-to-upload PNGs at the
sizes X, LinkedIn, Facebook, Instagram, GitHub and PWA manifests want:
X header 1500x500, post 1200x675, LinkedIn 1584x396, Facebook 820x312,
Instagram 1080, avatars 400/1024, icons 512/192, favicons 64/32, plus the
Open Graph 1200x630 that every page already advertises. The brand page
gained a "Social media and icons" section with download links.
scripts/brand-assets.mjs renders the whole set from one HTML template via
scripts/render-html-png.cjs (Electron offscreen). Windows clamps even an
offscreen window to the work area, so captures taller than the screen are
rendered as strips and stitched on a canvas inside the page.
The VPS serves silentmode.st with Angie, not nginx (nginx.service is dead
there), so the URL rules now live in VPS/SilentMode/silentmode-st.angie.conf,
deployed and live. try_files lists $uri/index.html before $uri because a
bare $uri also matches a directory and would 301 to add the slash back.
GOTCHAS and the URL-scheme notes corrected accordingly.
Addon:
- Paste any https:// URL that returns a list of vless:// (either
newline-separated or base64) and the extension fetches, decodes,
parses, and adds every server to the dropdown. The full vless URL
never leaves the panel — the addon holds it in its own storage and
passes an opaque "sub-<hash>" id back for selection.
- Subscription CRUD on the addon side (listSubscriptions,
addSubscription, refreshSubscription, removeSubscription). A refresh
is a no-op inside the 6-hour TTL to avoid pounding the provider.
- Merges subscription servers with the baked-in three and gateway
overlay by id; the dropdown groups them under one banner.
Site:
- silentmode.st/vpn landing page: three-plan grid (Free, Pro at $1/mo
BCH, Max at $4/mo BCH), how-it-works four-step block, "the three
servers" strip with per-tier availability, why-this-VPN cards, FAQ.
Priced in USD, paid in BCH via the oracle at pay-time — same pattern
as the marketplace's USD-listing covenant, no reintroduction of
fiat/card processors.
Fraunces/Ubuntu font picker is gone. theme.js used to persist the
choice in localStorage and paint a pill in the corner; now it just
sets data-font-cmp="ubuntu" on <html> so every page that already
carries the html[data-font-cmp="ubuntu"] rules in its stylesheet
switches to Ubuntu — the Bitcoin Cash brand face — on load. Same
one-line runtime on both sirius-x and hephaestus.x theme.js.
Mobile bottom nav rail was rgba(11,14,20,.52) with no blur, so
whatever body text was scrolled behind it bled straight through the
half-transparent bar — first sentence of How it works ended up
visually merged with the sidebar icons on hephaestus.x, section
headings ran under the Sirius.x rail. Bumped to rgba(...,.94) and
added backdrop-filter:blur(12px); content underneath is now covered
instead of showing through. Same tweak on all six Sirius.X pages
plus Hephaestus.X home.
Every pantheon card and footer entry across Sirius.X and Hephaestus.X
was routing through the gateway path form
(silentmode.st/bns/<name>.x/) instead of the sibling's own BCNR name.
Inside Theseus that meant every "Open →" bounced through the relay to
reach a site the browser could have resolved directly — and Silentmode
was linked as silentmode.st/bns/silentmode.x/ even though silentmode.x
resolves the same way in Theseus.
Rewrote every pantheon href to https://<name>.x/. Silentmode, Sirius,
Theseus, Hephaestus, Prometheus, Helios, Hermes all reach each other by
name.
Sirius.X pantheon also picked up the same polish Hephaestus already
carried: acid .X on every title, Theseus.X card gets its own compass
brand mark instead of the generic 🧭 emoji, the Hephaestus.X card
swaps its old 🔥 emoji for the forge ⚒️ mark, the .lbl wrapper
collapses the h3's own 8px gap so "Silentmode .X" stops splitting
across the name and the suffix.
Brand mark carried "Hephaestus" in forge orange and ".X" in plain ink
white, so the .X tail read as page chrome rather than part of the
brand — inconsistent with the acid .X pattern every other .x site now
uses. Wrapped the .X in <span class="x"> and gave .topnav .brand .x
the acid tint on both index and docs pages. Forge orange stays on the
name because that is Hephaestus's identity; the .X now signs off in
the ecosystem's shared colour.
Also aligned the footer's Pantheon column with the main pantheon
section: dropped the stale Fly.X entry, added Prometheus.X, Helios.X,
Hermes.X, and gave every entry the same Silentmode<span class="g">.X</span>
split so the acid tint on the suffix is consistent between the site
and the footer index.