diff --git a/src/browser/base/content/zen-assets.inc.xhtml b/src/browser/base/content/zen-assets.inc.xhtml
index f67426009c3..d43e78eab06 100644
--- a/src/browser/base/content/zen-assets.inc.xhtml
+++ b/src/browser/base/content/zen-assets.inc.xhtml
@@ -28,6 +28,7 @@
+
# Startup "preloaded" scripts that requre globals such as gBrowser and gURLBar
diff --git a/src/zen/common/ZenPreloadedScripts.js b/src/zen/common/ZenPreloadedScripts.js
index eaa87e51dd5..dcbb10561ba 100644
--- a/src/zen/common/ZenPreloadedScripts.js
+++ b/src/zen/common/ZenPreloadedScripts.js
@@ -12,6 +12,7 @@
"resource:///modules/zen/ZenSpaceManager.mjs",
"chrome://browser/content/zen-components/ZenCompactMode.mjs",
"chrome://browser/content/ZenUIManager.mjs",
+ "chrome://browser/content/zen-components/ZenTetraID.mjs",
"chrome://browser/content/zen-components/ZenAISidebar.mjs",
"chrome://browser/content/zen-components/ZenMods.mjs",
"chrome://browser/content/zen-components/ZenKeyboardShortcuts.mjs",
diff --git a/src/zen/common/jar.inc.mn b/src/zen/common/jar.inc.mn
index ba436bf38bf..283ac0679ef 100644
--- a/src/zen/common/jar.inc.mn
+++ b/src/zen/common/jar.inc.mn
@@ -15,6 +15,7 @@
content/browser/zen-components/ZenHasPolyfill.mjs (../../zen/common/modules/ZenHasPolyfill.mjs)
content/browser/zen-components/ZenSidebarNotification.mjs (../../zen/common/modules/ZenSidebarNotification.mjs)
content/browser/zen-components/ZenMenubar.mjs (../../zen/common/modules/ZenMenubar.mjs)
+ content/browser/zen-components/ZenTetraID.mjs (../../zen/common/modules/ZenTetraID.mjs)
content/browser/zen-components/ZenEmojisData.min.mjs (../../zen/common/emojis/ZenEmojisData.min.mjs)
content/browser/zen-components/ZenEmojiPicker.mjs (../../zen/common/emojis/ZenEmojiPicker.mjs)
@@ -33,6 +34,7 @@
content/browser/zen-styles/zen-branding.css (../../zen/common/styles/zen-branding.css)
content/browser/zen-styles/zen-sidebar-notification.css (../../zen/common/styles/zen-sidebar-notification.css)
content/browser/zen-styles/zen-ai-sidebar.css (../../zen/common/styles/zen-ai-sidebar.css)
+ content/browser/zen-styles/zen-tetraid.css (../../zen/common/styles/zen-tetraid.css)
content/browser/zen-styles/zen-panels/bookmarks.css (../../zen/common/styles/zen-panels/bookmarks.css)
content/browser/zen-styles/zen-panels/print.css (../../zen/common/styles/zen-panels/print.css)
diff --git a/src/zen/common/modules/ZenTetraID.mjs b/src/zen/common/modules/ZenTetraID.mjs
new file mode 100644
index 00000000000..e511a559d08
--- /dev/null
+++ b/src/zen/common/modules/ZenTetraID.mjs
@@ -0,0 +1,301 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const TETRAID_BASE_URL_PREF = "identity.tetraid.auth.base_url";
+const TETRAID_DEFAULT_BASE_URL = "https://tetraid-altzen-auth.vercel.app";
+const TETRAID_PLACEHOLDER_STATE_PREF = "identity.tetraid.placeholder_state";
+const TETRAID_PLACEHOLDER_DISPLAY_NAME_PREF =
+ "identity.tetraid.placeholder_display_name";
+const TETRAID_PLACEHOLDER_USERNAME_PREF =
+ "identity.tetraid.placeholder_username";
+
+const ACCOUNT_STATUS_ID = "appMenu-fxa-status2";
+const ACCOUNT_TEXT_ID = "appMenu-fxa-text";
+const ACCOUNT_ACTION_ID = "appMenu-fxa-label2";
+const ACCOUNT_TITLE_ID = "appMenu-header-title";
+const ACCOUNT_DESCRIPTION_ID = "appMenu-header-description";
+const LEGACY_TETRAID_STATUS_ID = "appMenu-tetraid-status";
+
+let gTetraIDServices;
+let gTetraIDServicesResolved = false;
+
+function warnTetraID(message, error) {
+ console.warn(`TetraID: ${message}`, error);
+}
+
+function getTetraIDServices() {
+ if (gTetraIDServicesResolved) {
+ return gTetraIDServices;
+ }
+
+ gTetraIDServicesResolved = true;
+ gTetraIDServices = globalThis.Services || globalThis.window?.Services;
+
+ if (!gTetraIDServices && globalThis.ChromeUtils?.importESModule) {
+ try {
+ gTetraIDServices = ChromeUtils.importESModule(
+ "resource://gre/modules/Services.sys.mjs"
+ ).Services;
+ } catch (error) {
+ warnTetraID(
+ "Services unavailable; account UI will use safe defaults.",
+ error
+ );
+ }
+ }
+
+ return gTetraIDServices;
+}
+
+class ZenTetraIDStateAdapter {
+ get state() {
+ const services = getTetraIDServices();
+ if (!services?.prefs) {
+ return { status: "signedOut" };
+ }
+
+ if (
+ services.prefs.getStringPref(
+ TETRAID_PLACEHOLDER_STATE_PREF,
+ "signedOut"
+ ) == "signedIn"
+ ) {
+ return {
+ status: "signedIn",
+ displayName: services.prefs.getStringPref(
+ TETRAID_PLACEHOLDER_DISPLAY_NAME_PREF,
+ "AltZen"
+ ),
+ username: services.prefs.getStringPref(
+ TETRAID_PLACEHOLDER_USERNAME_PREF,
+ "@altzen"
+ ),
+ };
+ }
+
+ return { status: "signedOut" };
+ }
+
+ async refresh() {
+ return this.state;
+ }
+}
+
+class ZenTetraIDAccountMenu {
+ #stateAdapter = new ZenTetraIDStateAdapter();
+ #lastState = { status: "signedOut" };
+
+ init() {
+ document.addEventListener("popupshowing", event => {
+ if (event.target.id == "appMenu-popup") {
+ this.refreshTetraIDAccountState();
+ window.setTimeout(() => this.refreshTetraIDAccountState(), 0);
+ }
+ });
+
+ document.addEventListener("ViewShowing", event => {
+ if (event.target.id == "appMenu-mainView") {
+ this.refreshTetraIDAccountState();
+ window.setTimeout(() => this.refreshTetraIDAccountState(), 0);
+ }
+ });
+
+ const handleAccountActivation = event => this.handleAccountActivation(event);
+ document.addEventListener("command", handleAccountActivation, true);
+ document.addEventListener("click", handleAccountActivation, true);
+ }
+
+ get baseUrl() {
+ const services = getTetraIDServices();
+ if (!services?.prefs) {
+ return TETRAID_DEFAULT_BASE_URL;
+ }
+
+ return services.prefs
+ .getStringPref(TETRAID_BASE_URL_PREF, TETRAID_DEFAULT_BASE_URL)
+ .replace(/\/$/, "");
+ }
+
+ async refreshTetraIDAccountState() {
+ try {
+ this.#lastState = await this.#stateAdapter.refresh();
+ } catch (error) {
+ warnTetraID("Account state refresh failed; using signed-out state.", error);
+ this.#lastState = { status: "signedOut" };
+ }
+
+ this.renderMenuRow(this.#lastState);
+ return this.#lastState;
+ }
+
+ renderMenuRow(state = this.#lastState) {
+ const legacyTetraIDStatus = document.getElementById(
+ LEGACY_TETRAID_STATUS_ID
+ );
+ if (legacyTetraIDStatus) {
+ legacyTetraIDStatus.hidden = true;
+ }
+
+ const statusItem = document.getElementById(ACCOUNT_STATUS_ID);
+ const text = document.getElementById(ACCOUNT_TEXT_ID);
+ const actionButton = document.getElementById(ACCOUNT_ACTION_ID);
+ const title = document.getElementById(ACCOUNT_TITLE_ID);
+ const description = document.getElementById(ACCOUNT_DESCRIPTION_ID);
+
+ if (!statusItem || !text || !actionButton || !title || !description) {
+ return;
+ }
+
+ statusItem.hidden = false;
+ statusItem.setAttribute("tetraid-entry", "true");
+ statusItem.classList.add("toolbaritem-combined-buttons");
+ statusItem.removeAttribute("fxastatus");
+ statusItem.removeAttribute("tooltiptext");
+ statusItem.removeAttribute("data-l10n-id");
+ statusItem.removeAttribute("command");
+ statusItem.removeAttribute("oncommand");
+
+ text.removeAttribute("data-l10n-id");
+ text.hidden = false;
+ actionButton.removeAttribute("data-l10n-id");
+ actionButton.removeAttribute("command");
+ actionButton.removeAttribute("oncommand");
+ actionButton.removeAttribute("key");
+ actionButton.removeAttribute("aria-labelledby");
+ actionButton.classList.remove("subviewbutton-nav");
+ actionButton.classList.remove("subviewbutton-iconic");
+ actionButton.classList.add("subviewbutton-iconic", "tetraid-chevron-button");
+ actionButton.setAttribute("closemenu", "none");
+ actionButton.hidden = false;
+ actionButton.setAttribute("label", "");
+ actionButton.setAttribute(
+ "image",
+ "chrome://global/skin/icons/arrow-right.svg"
+ );
+
+ title.hidden = true;
+ description.hidden = true;
+
+ if (state.status == "signedIn") {
+ statusItem.setAttribute("tetraid-status", "signed-in");
+ text.replaceChildren(this.#buildSignedInIdentity(state));
+ actionButton.setAttribute("aria-label", "Open TetraID account");
+ actionButton.setAttribute("title", "Open TetraID account");
+ actionButton.setAttribute("tooltiptext", "Open TetraID account");
+ return;
+ }
+
+ statusItem.setAttribute("tetraid-status", "signed-out");
+ text.textContent = "Connect AltZen to your TetraID";
+ actionButton.setAttribute("aria-label", "Sign in to TetraID");
+ actionButton.setAttribute("title", "Sign in to TetraID");
+ actionButton.setAttribute("tooltiptext", "Sign in to TetraID");
+ }
+
+ showSignInDialog() {
+ const services = getTetraIDServices();
+ if (!services?.prompt) {
+ warnTetraID("Prompt service unavailable; sign-in dialog was not opened.");
+ return;
+ }
+
+ const buttonFlags =
+ services.prompt.BUTTON_POS_0 * services.prompt.BUTTON_TITLE_IS_STRING +
+ services.prompt.BUTTON_POS_1 * services.prompt.BUTTON_TITLE_CANCEL;
+ const buttonPressed = services.prompt.confirmEx(
+ window,
+ "Sign in to TetraID",
+ "Use your TetraID to connect AltZen with your Tetra account.",
+ buttonFlags,
+ "Continue",
+ null,
+ null,
+ null,
+ {}
+ );
+
+ if (buttonPressed == 0) {
+ this.openAuthStart();
+ }
+ }
+
+ openAuthStart() {
+ this.openTetraIDAuthFlow();
+ }
+
+ openTetraIDAuthFlow() {
+ window.openTrustedLinkIn(`${this.baseUrl}/api/auth/login`, "tab");
+ }
+
+ openAccountHome() {
+ window.openTrustedLinkIn(`${this.baseUrl}/`, "tab");
+ }
+
+ #buildSignedInIdentity(state) {
+ const container = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "div"
+ );
+ container.id = "tetraid-menu-identity";
+
+ const avatar = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "span"
+ );
+ avatar.id = "tetraid-menu-avatar";
+ avatar.setAttribute("aria-hidden", "true");
+
+ const copy = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "span"
+ );
+ copy.id = "tetraid-menu-copy";
+
+ const name = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "span"
+ );
+ name.id = "tetraid-menu-name";
+ name.textContent = state.displayName || "AltZen";
+
+ const username = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "span"
+ );
+ username.id = "tetraid-menu-username";
+ username.textContent = state.username || "@altzen";
+
+ copy.append(name, username);
+ container.append(avatar, copy);
+ return container;
+ }
+
+ handleAccountActivation(event) {
+ const target = event.target?.closest?.(
+ `#${ACCOUNT_ACTION_ID}, #${ACCOUNT_STATUS_ID}`
+ );
+ if (!target) {
+ return;
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopImmediatePropagation();
+
+ if (this.#lastState.status == "signedIn") {
+ this.openAccountHome();
+ } else {
+ this.openTetraIDAuthFlow();
+ }
+ }
+}
+
+try {
+ window.gZenTetraID = new ZenTetraIDAccountMenu();
+ window.refreshTetraIDAccountState = () =>
+ window.gZenTetraID.refreshTetraIDAccountState();
+ window.gZenTetraID.init();
+} catch (error) {
+ warnTetraID("Initialization failed; browser chrome will continue.", error);
+}
diff --git a/src/zen/common/styles/zen-tetraid.css b/src/zen/common/styles/zen-tetraid.css
new file mode 100644
index 00000000000..f33ba2980b4
--- /dev/null
+++ b/src/zen/common/styles/zen-tetraid.css
@@ -0,0 +1,97 @@
+#appMenu-fxa-status2[tetraid-entry="true"] {
+ gap: 8px;
+ min-height: 48px;
+ padding-block: 4px;
+}
+
+#appMenu-fxa-status2[tetraid-entry="true"] > #appMenu-fxa-text {
+ flex: 1;
+ min-width: 0;
+ font-weight: 600;
+ line-height: 1.25;
+}
+
+#appMenu-fxa-status2[tetraid-entry="true"] > #appMenu-fxa-label2 {
+ flex: 0 0 auto;
+}
+
+#appMenu-fxa-status2[tetraid-entry="true"] > #appMenu-fxa-label2.tetraid-chevron-button {
+ -moz-context-properties: fill, fill-opacity;
+ fill: currentColor;
+ fill-opacity: 0.75;
+ list-style-image: url("chrome://global/skin/icons/arrow-right.svg");
+ appearance: none;
+ justify-content: center;
+ min-width: 28px;
+ min-height: 28px;
+ margin-inline-start: 4px;
+ padding: 5px;
+}
+
+#appMenu-fxa-status2[tetraid-entry="true"] > #appMenu-fxa-label2.tetraid-chevron-button > .toolbarbutton-text {
+ display: none;
+}
+
+#appMenu-fxa-status2[tetraid-entry="true"] > #appMenu-fxa-label2.tetraid-chevron-button > .toolbarbutton-icon {
+ display: -moz-box;
+ width: 16px;
+ height: 16px;
+ margin: 0;
+}
+
+#appMenu-fxa-status2[tetraid-entry="true"] > #appMenu-fxa-label2.tetraid-chevron-button:-moz-locale-dir(rtl) {
+ list-style-image: url("chrome://global/skin/icons/arrow-left.svg");
+}
+
+#appMenu-fxa-status2[tetraid-status="signed-in"] {
+ align-items: center;
+ min-height: 66px;
+ padding-block: 6px;
+}
+
+#appMenu-fxa-status2[tetraid-status="signed-in"] > #appMenu-fxa-label2 {
+ margin-inline-start: 8px;
+ white-space: nowrap;
+}
+
+#tetraid-menu-identity {
+ display: flex;
+ align-items: center;
+ min-width: 0;
+ gap: 12px;
+}
+
+#tetraid-menu-avatar {
+ width: 38px;
+ height: 38px;
+ flex: 0 0 auto;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 35% 35%, #ffffffcc 0 18%, transparent 19%),
+ linear-gradient(145deg, #f56d41, #55a5ff);
+}
+
+#tetraid-menu-copy {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+ gap: 3px;
+}
+
+#tetraid-menu-name,
+#tetraid-menu-username {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+#tetraid-menu-name {
+ font-weight: 600;
+ line-height: 1.2;
+}
+
+#tetraid-menu-username {
+ color: color-mix(in srgb, currentColor 68%, transparent);
+ font-size: 0.92em;
+ font-weight: 400;
+}