2026-08-02 11:39:00 +02:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" / >
< title > Open with…< / title >
< meta name = "viewport" content = "width=device-width, initial-scale=1" / >
< style >
:root {
color-scheme: dark light;
2026-08-02 14:43:31 +02:00
--bg: #0f1116;
--fg: #e5e7eb;
--muted: #9ca3af;
--border: #2a2f3a;
--panel: #131722;
--panel-hover: #181e2b;
--bcdn: #d6ff3d; /* acid glow green (matches address-bar toggle) */
--icann: #4c9eff; /* blue (matches address-bar toggle) */
2026-08-02 11:39:00 +02:00
}
@media (prefers-color-scheme: light) {
2026-08-02 14:43:31 +02:00
:root { --bg:#f7f7f8; --fg:#111827; --muted:#5b6472; --border:#e5e7eb; --panel:#ffffff; --panel-hover:#f0f2f5; --bcdn:#7fa900; --icann:#1f6fd4; }
2026-08-02 11:39:00 +02:00
}
* { box-sizing: border-box; }
2026-08-02 14:43:31 +02:00
html, body { margin: 0; min-height: 100%; }
body {
background: var(--bg); color: var(--fg);
font: 15px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
display: flex; flex-direction: column; align-items: center; justify-content: center;
padding: 40px 24px;
}
main { width: 100%; max-width: 720px; }
header { margin-bottom: 28px; }
h1 { margin: 0 0 8px; font-size: 22px; font-weight: 600; letter-spacing: -.01em; }
.sub { color: var(--muted); font-size: 14px; }
.host { color: var(--fg); font-weight: 600; }
.choices { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 28px; }
@media (max-width: 620px) { .choices { grid-template-columns: 1fr; } }
.choice {
background: var(--panel); border: 2px solid var(--border); border-radius: 12px;
padding: 22px; color: var(--fg); text-align: left; cursor: pointer;
transition: border-color .12s, background .12s, transform .06s;
display: flex; flex-direction: column; gap: 8px;
}
.choice:hover { background: var(--panel-hover); }
.choice:active { transform: scale(.99); }
.choice.sel.bcdn { border-color: var(--bcdn); box-shadow: 0 0 0 1px var(--bcdn), 0 0 22px -8px var(--bcdn); }
.choice.sel.icann { border-color: var(--icann); box-shadow: 0 0 0 1px var(--icann), 0 0 22px -10px var(--icann); }
.choice .head { display: flex; align-items: center; gap: 12px; }
.choice .radio {
flex: none; width: 18px; height: 18px; border-radius: 50%;
border: 2px solid var(--border); position: relative;
}
.choice.sel.bcdn .radio { border-color: var(--bcdn); background: radial-gradient(circle, var(--bcdn) 40%, transparent 42%); }
.choice.sel.icann .radio { border-color: var(--icann); background: radial-gradient(circle, var(--icann) 40%, transparent 42%); }
.choice .icon { font-size: 22px; line-height: 1; }
.choice .title { font-weight: 600; font-size: 16px; }
.choice.bcdn .title { color: var(--bcdn); }
2026-08-02 13:02:47 +02:00
.choice.icann .title { color: var(--icann); }
2026-08-02 14:43:31 +02:00
.choice .desc { font-size: 13.5px; color: var(--muted); }
fieldset { border: 0; padding: 0; margin: 0 0 28px; display: flex; flex-direction: column; gap: 10px; }
fieldset legend {
color: var(--muted); font-size: 12px; padding: 0; margin-bottom: 8px;
text-transform: uppercase; letter-spacing: .06em;
}
fieldset .row { display: flex; align-items: center; gap: 10px; font-size: 14px; padding: 3px 0; }
fieldset .row input { accent-color: var(--bcdn); width: 16px; height: 16px; }
fieldset .row label { color: var(--fg); cursor: pointer; }
.actions { display: flex; justify-content: flex-end; gap: 12px; }
button.act {
border: 1px solid var(--border); background: var(--panel); color: var(--fg);
padding: 11px 22px; border-radius: 8px; font-size: 14px; cursor: pointer;
transition: background .1s, filter .1s;
}
button.act:hover { background: var(--panel-hover); }
button.act.primary { background: var(--bcdn); color: #111; border-color: var(--bcdn); font-weight: 600; }
button.act.primary:hover { filter: brightness(1.06); }
kbd { border: 1px solid var(--border); border-radius: 3px; padding: 0 5px; font: 11px monospace; color: var(--muted); margin-left: 6px; }
2026-08-02 11:39:00 +02:00
< / style >
< / head >
< body >
2026-08-02 14:43:31 +02:00
< main >
< header >
< h1 > < span class = "host" id = "host" > < / span > exists in two registries< / h1 >
< div class = "sub" > Choose which one to open. You can change this later in Settings.< / div >
< / header >
2026-08-02 11:39:00 +02:00
2026-08-02 14:43:31 +02:00
< div class = "choices" >
< div class = "choice bcdn sel" data-choice = "bcnr" tabindex = "0" >
< div class = "head" >
< span class = "radio" > < / span > < span class = "icon" > ⛓< / span >
< span class = "title" > BCNR / BCDN< / span >
< / div >
< div class = "desc" > On-chain registration. Owned by the holder of a digital name certificate. The registry served by the blockchain root.< / div >
2026-08-02 13:02:47 +02:00
< / div >
2026-08-02 14:43:31 +02:00
< div class = "choice icann" data-choice = "icann" tabindex = "0" >
< div class = "head" >
< span class = "radio" > < / span > < span class = "icon" > 🌐< / span >
< span class = "title" > ICANN / IANA< / span >
< / div >
< div class = "desc" > DNS service coordinated by the ICANN. The registry served by the incumbent root.< / div >
2026-08-02 13:02:47 +02:00
< / div >
< / div >
2026-08-02 11:39:00 +02:00
2026-08-02 14:43:31 +02:00
< fieldset >
< legend > Remember this choice< / legend >
< div class = "row" > < input type = "radio" name = "remember" id = "rem-no" value = "no" checked > < label for = "rem-no" > Ask again next time< / label > < / div >
< div class = "row" > < input type = "radio" name = "remember" id = "rem-name" value = "name" > < label for = "rem-name" > Always use for < span class = "host" id = "host2" > < / span > < / label > < / div >
< div class = "row" > < input type = "radio" name = "remember" id = "rem-tld" value = "tld" > < label for = "rem-tld" > Always use for all < span id = "tld" > < / span > names< / label > < / div >
< / fieldset >
2026-08-02 11:39:00 +02:00
2026-08-02 14:43:31 +02:00
< div class = "actions" >
< button class = "act" id = "cancel" > Cancel< kbd > Esc< / kbd > < / button >
< button class = "act primary" id = "confirm" > Open< kbd > Enter< / kbd > < / button >
< / div >
< / main >
2026-08-02 11:39:00 +02:00
< script >
const qs = new URLSearchParams(location.search);
2026-08-02 14:43:31 +02:00
const host = qs.get("host") || "";
const tld = qs.get("tld") || "";
const resturl = qs.get("resturl") || "/";
document.getElementById("host").textContent = host;
2026-08-02 11:39:00 +02:00
document.getElementById("host2").textContent = host;
2026-08-02 14:43:31 +02:00
document.getElementById("tld").textContent = "." + tld;
2026-08-02 11:39:00 +02:00
document.title = "Open " + host + " with…";
2026-08-02 14:43:31 +02:00
let choice = "bcnr";
const bcdnEl = document.querySelector('.choice[data-choice="bcnr"]');
2026-08-02 13:02:47 +02:00
const icannEl = document.querySelector('.choice[data-choice="icann"]');
function select(c) {
choice = c;
2026-08-02 14:43:31 +02:00
bcdnEl.classList.toggle("sel", c === "bcnr");
2026-08-02 13:02:47 +02:00
icannEl.classList.toggle("sel", c === "icann");
2026-08-02 14:43:31 +02:00
// primary button colour follows the selected choice
const p = document.getElementById("confirm");
p.style.background = c === "bcnr"
? "var(--bcdn)"
: "var(--icann)";
p.style.borderColor = p.style.background;
p.style.color = c === "bcnr" ? "#111" : "#fff";
2026-08-02 11:39:00 +02:00
}
2026-08-02 14:43:31 +02:00
select("bcnr"); // initial paint
2026-08-02 13:02:47 +02:00
for (const el of [bcdnEl, icannEl]) {
el.addEventListener("click", () => select(el.dataset.choice));
el.addEventListener("keydown", (e) => { if (e.key === " " || e.key === "Enter") { e.preventDefault(); select(el.dataset.choice); } });
2026-08-02 11:39:00 +02:00
}
2026-08-02 13:02:47 +02:00
function remember() { return document.querySelector('input[name="remember"]:checked')?.value || "no"; }
function confirm() {
2026-08-02 14:43:31 +02:00
const q = new URLSearchParams({ host, tld, choice, remember: remember(), resturl });
// Navigate to the special bns:// endpoint that main.js's serveBns intercepts:
// it applies the remember choice and redirects to the real target.
location.href = "bns://collision-choose/?" + q.toString();
}
function cancel() {
if (history.length > 1) history.back();
else location.href = "about:blank";
2026-08-02 13:02:47 +02:00
}
document.getElementById("confirm").addEventListener("click", confirm);
document.getElementById("cancel").addEventListener("click", cancel);
2026-08-02 11:39:00 +02:00
document.addEventListener("keydown", (e) => {
2026-08-02 13:02:47 +02:00
if (e.key === "Escape") cancel();
if (e.key === "Enter" & & e.target.tagName !== "BUTTON") confirm();
2026-08-02 11:39:00 +02:00
});
< / script >
< / body >
< / html >