+-
++
+
+ form:nth-child(1) > div:nth-child(3) {
++ @extend %vw-hide;
++}
++
++/* Hide the `This account is owned by a business` checkbox and label */
++#ownedBusiness,
++label[for^="ownedBusiness"] {
++ @extend %vw-hide;
++}
++
++/* Hide the radio button and label for the `Custom` org user type */
++#userTypeCustom,
++label[for^="userTypeCustom"] {
++ @extend %vw-hide;
++}
++
++/* Hide Business Name */
++app-org-account form div bit-form-field.tw-block:nth-child(3) {
++ @extend %vw-hide;
++}
++
++/* Hide organization plans */
++app-organization-plans > form > h2.mt-5 {
++ @extend %vw-hide;
++}
++
++/* Hide Device Verification form at the Two Step Login screen */
++app-security > app-two-factor-setup > form {
++ @extend %vw-hide;
++}
++
++/* Replace the Bitwarden Shield at the top left with a Vaultwarden icon */
++.bwi-shield:before {
++ content: "" !important;
++ width: 32px !important;
++ height: 40px !important;
++ display: block !important;
++ background-image: url(../images/icon-white.png) !important;
++ background-repeat: no-repeat;
++ background-position-y: bottom;
++}
++/**** END Vaultwarden CHANGES ****/
+diff --git a/apps/web/src/scss/variables.scss b/apps/web/src/scss/variables.scss
+index 9d3d8d6ad4..5bc773c0d8 100644
+--- a/apps/web/src/scss/variables.scss
++++ b/apps/web/src/scss/variables.scss
+@@ -3,7 +3,7 @@ $dark-icon-themes: "theme_dark";
+ $primary: #175ddc;
+ $primary-accent: #1252a3;
+ $secondary: #ced4da;
+-$secondary-alt: #1a3b66;
++$secondary-alt: #212529;
+ $success: #017e45;
+ $info: #555555;
+ $warning: #8b6609;
+diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js
+index 6ac384cb82..0492e09476 100644
+--- a/apps/web/webpack.config.js
++++ b/apps/web/webpack.config.js
+@@ -141,8 +141,6 @@ const plugins = [
+ { from: "./src/favicon.ico" },
+ { from: "./src/browserconfig.xml" },
+ { from: "./src/app-id.json" },
+- { from: "./src/404.html" },
+- { from: "./src/404", to: "404" },
+ { from: "./src/images", to: "images" },
+ { from: "./src/locales", to: "locales" },
+ { from: "../../node_modules/qrious/dist/qrious.min.js", to: "scripts" },
+diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts
+index 3cffebe71b..c1229b5c2c 100644
+--- a/libs/angular/src/auth/components/register.component.ts
++++ b/libs/angular/src/auth/components/register.component.ts
+@@ -106,6 +106,14 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
+ }
+
+ async submit(showToast = true) {
++ if (typeof crypto.subtle === "undefined") {
++ this.platformUtilsService.showToast(
++ "error",
++ "This browser requires HTTPS to use the web vault",
++ "Check the Vaultwarden wiki for details on how to enable it",
++ );
++ return;
++ }
+ let email = this.formGroup.value.email;
+ email = email.trim().toLowerCase();
+ let name = this.formGroup.value.name;
+diff --git a/libs/angular/src/auth/components/two-factor-options.component.ts b/libs/angular/src/auth/components/two-factor-options.component.ts
+index 4293eb9966..7a8e861e8d 100644
+--- a/libs/angular/src/auth/components/two-factor-options.component.ts
++++ b/libs/angular/src/auth/components/two-factor-options.component.ts
+@@ -30,7 +30,9 @@ export class TwoFactorOptionsComponent implements OnInit {
+ }
+
+ recover() {
+- this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/recover-2fa");
++ this.platformUtilsService.launchUri(
++ "https://bitwarden.com/help/two-step-recovery-code/#use-your-recovery-code",
++ );
+ this.onRecoverSelected.emit();
+ }
+ }
+diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css
+index 75a8fa6380..733dbe9413 100644
+--- a/libs/components/src/tw-theme.css
++++ b/libs/components/src/tw-theme.css
+@@ -6,12 +6,12 @@
+ --color-background: 255 255 255;
+ --color-background-alt: 251 251 251;
+ --color-background-alt2: 23 92 219;
+- --color-background-alt3: 18 82 163;
+- --color-background-alt4: 13 60 119;
++ --color-background-alt3: 33 37 41; /* bg of menu panel */
++ --color-background-alt4: 16 18 21; /* bg of active menu item */
+
+- --color-primary-300: 103 149 232;
+- --color-primary-500: 23 93 220;
+- --color-primary-700: 18 82 163;
++ --color-primary-300: 108 117 125; /* hover of menu items */
++ --color-primary-500: 18 82 163; /* color of links and buttons */
++ --color-primary-700: 13 60 119; /* hover of links and buttons */
+
+ --color-secondary-100: 240 240 240;
+ --color-secondary-300: 206 212 220;
diff --git a/patches/v2024.3.0.patch b/patches/v2024.3.0.patch
new file mode 100644
index 0000000..dc2e448
--- /dev/null
+++ b/patches/v2024.3.0.patch
@@ -0,0 +1,719 @@
+diff --git a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html
+index 6029cfd833..04324b7d19 100644
+--- a/apps/web/src/app/admin-console/organizations/create/organization-information.component.html
++++ b/apps/web/src/app/admin-console/organizations/create/organization-information.component.html
+@@ -12,7 +12,7 @@
+
+
+
+- {{ "billingEmail" | i18n }}
++ {{ "email" | i18n }}
+
+
+
+diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts
+index 90010160aa..4d0a2717af 100644
+--- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts
++++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts
+@@ -113,6 +113,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
+ }
+
+ canShowBillingTab(organization: Organization): boolean {
++ return false; // disable billing tab in Vaultwarden
+ return canAccessBillingTab(organization);
+ }
+
+diff --git a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts
+index 7abee6b0d0..2e3b789b23 100644
+--- a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts
++++ b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts
+@@ -68,13 +68,6 @@ const routes: Routes = [
+ (m) => m.OrganizationReportingModule,
+ ),
+ },
+- {
+- path: "billing",
+- loadChildren: () =>
+- import("../../billing/organizations/organization-billing.module").then(
+- (m) => m.OrganizationBillingModule,
+- ),
+- },
+ ],
+ },
+ ];
+diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html
+index 7035b976ca..44b24584ae 100644
+--- a/apps/web/src/app/admin-console/organizations/settings/account.component.html
++++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html
+@@ -17,7 +17,7 @@
+
+
+
+- {{ "billingEmail" | i18n }}
++ {{ "email" | i18n }}
+
+
+
+diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.ts b/apps/web/src/app/admin-console/organizations/settings/account.component.ts
+index 8527aa1b17..971d78d8d5 100644
+--- a/apps/web/src/app/admin-console/organizations/settings/account.component.ts
++++ b/apps/web/src/app/admin-console/organizations/settings/account.component.ts
+@@ -99,7 +99,7 @@ export class AccountComponent {
+ ) {}
+
+ async ngOnInit() {
+- this.selfHosted = this.platformUtilsService.isSelfHost();
++ this.selfHosted = false; // set to false so we can rename organizations
+
+ this.route.params
+ .pipe(
+@@ -204,6 +204,7 @@ export class AccountComponent {
+ }
+
+ submitCollectionManagement = async () => {
++ return; // flexible collections are not supported by Vaultwarden
+ // Early exit if self-hosted
+ if (this.selfHosted) {
+ return;
+diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
+index 73721de789..1b1726ff1f 100644
+--- a/apps/web/src/app/app.component.ts
++++ b/apps/web/src/app/app.component.ts
+@@ -213,6 +213,10 @@ export class AppComponent implements OnDestroy, OnInit {
+ break;
+ }
+ case "showToast":
++ if (typeof message.text === "string" && typeof crypto.subtle === "undefined") {
++ message.title = "This browser requires HTTPS to use the web vault";
++ message.text = "Check the Vaultwarden wiki for details on how to enable it";
++ }
+ this.showToast(message);
+ break;
+ case "convertAccountToKeyConnector":
+diff --git a/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html b/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html
+index 4690a4e63a..9d297671d2 100644
+--- a/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html
++++ b/apps/web/src/app/auth/emergency-access/accept/accept-emergency.component.html
+@@ -1,6 +1,6 @@
+
+
+-
++
+
+
+
+-
++
+
+ {{ "loginOrCreateNewAccount" | i18n }}
+
+@@ -51,7 +51,7 @@
+
+
+
+-
++
+
{{ "or" | i18n }}
+
+
+
+-
+-
+diff --git a/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts b/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts
+index 849e003440..de32156aad 100644
+--- a/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts
++++ b/apps/web/src/app/auth/settings/two-factor-authenticator.component.ts
+@@ -109,11 +109,11 @@ export class TwoFactorAuthenticatorComponent
+ new window.QRious({
+ element: document.getElementById("qr"),
+ value:
+- "otpauth://totp/Bitwarden:" +
++ "otpauth://totp/Vaultwarden:" +
+ Utils.encodeRFC3986URIComponent(email) +
+ "?secret=" +
+ encodeURIComponent(this.key) +
+- "&issuer=Bitwarden",
++ "&issuer=Vaultwarden",
+ size: 160,
+ });
+ }, 100);
+diff --git a/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts b/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts
+index 78872aa6a9..eed953b91a 100644
+--- a/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts
++++ b/apps/web/src/app/billing/organizations/organization-billing-history-view.component.ts
+@@ -44,7 +44,7 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
+ return;
+ }
+ this.loading = true;
+- this.billing = await this.organizationApiService.getBilling(this.organizationId);
++ this.billing = null;
+ this.loading = false;
+ }
+ }
+diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.html b/apps/web/src/app/billing/organizations/organization-plans.component.html
+index a77d42a359..7de4e33fe2 100644
+--- a/apps/web/src/app/billing/organizations/organization-plans.component.html
++++ b/apps/web/src/app/billing/organizations/organization-plans.component.html
+@@ -6,7 +6,7 @@
+ >
+ {{ "loading" | i18n }}
+
+-
++
+ {{ "uploadLicenseFileOrg" | i18n }}
+